From b94e57665369ab1c944c51586912f758ad4b86b1 Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Sat, 24 Jun 2023 21:30:09 -0400
Subject: [PATCH] kernel: Synchronize

---
 src/core/hle/kernel/k_thread.h                | 10 +++++
 src/core/hle/kernel/svc/svc_ipc.cpp           | 31 +++++++++-----
 .../hle/kernel/svc/svc_synchronization.cpp    | 41 +++++++++----------
 3 files changed, 49 insertions(+), 33 deletions(-)

diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index dd662b3f8..d178c2453 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -338,6 +338,15 @@ public:
         return m_parent != nullptr;
     }
 
+    std::span<KSynchronizationObject*> GetSynchronizationObjectBuffer() {
+        return m_sync_object_buffer.sync_objects;
+    }
+
+    std::span<Handle> GetHandleBuffer() {
+        return {m_sync_object_buffer.handles.data() + Svc::ArgumentHandleCountMax,
+                Svc::ArgumentHandleCountMax};
+    }
+
     u16 GetUserDisableCount() const;
     void SetInterruptFlag();
     void ClearInterruptFlag();
@@ -855,6 +864,7 @@ private:
     u32* m_light_ipc_data{};
     KProcessAddress m_tls_address{};
     KLightLock m_activity_pause_lock;
+    SyncObjectBuffer m_sync_object_buffer{};
     s64 m_schedule_count{};
     s64 m_last_scheduled_tick{};
     std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> m_per_core_priority_queue_entry{};
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp
index 60247df2e..bb94f6934 100644
--- a/src/core/hle/kernel/svc/svc_ipc.cpp
+++ b/src/core/hle/kernel/svc/svc_ipc.cpp
@@ -38,22 +38,31 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
 
 Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles,
                        Handle reply_target, s64 timeout_ns) {
+    // Ensure number of handles is valid.
+    R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
+
+    // Get the synchronization context.
     auto& kernel = system.Kernel();
     auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
+    auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer();
+    auto handles = GetCurrentThread(kernel).GetHandleBuffer();
 
-    R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
-    R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
-                 handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
-             ResultInvalidPointer);
+    // Copy user handles.
+    if (num_handles > 0) {
+        // Ensure we can try to get the handles.
+        R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
+                     handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
+                 ResultInvalidPointer);
 
-    std::array<Handle, Svc::ArgumentHandleCountMax> handles;
-    GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles);
+        // Get the handles.
+        GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(),
+                                           sizeof(Handle) * num_handles);
 
-    // Convert handle list to object table.
-    std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
-    R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(),
-                                                                     num_handles),
-             ResultInvalidHandle);
+        // Convert the handles to objects.
+        R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(
+                     objs.data(), handles.data(), num_handles),
+                 ResultInvalidHandle);
+    }
 
     // Ensure handles are closed when we're done.
     SCOPE_EXIT({
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp
index 53df5bcd8..f02d03f30 100644
--- a/src/core/hle/kernel/svc/svc_synchronization.cpp
+++ b/src/core/hle/kernel/svc/svc_synchronization.cpp
@@ -47,21 +47,35 @@ Result ResetSignal(Core::System& system, Handle handle) {
     R_THROW(ResultInvalidHandle);
 }
 
-static Result WaitSynchronization(Core::System& system, int32_t* out_index, const Handle* handles,
-                                  int32_t num_handles, int64_t timeout_ns) {
+/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
+Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_handles,
+                           int32_t num_handles, int64_t timeout_ns) {
+    LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles,
+              num_handles, timeout_ns);
+
     // Ensure number of handles is valid.
     R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
 
     // Get the synchronization context.
     auto& kernel = system.Kernel();
     auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
-    std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
+    auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer();
+    auto handles = GetCurrentThread(kernel).GetHandleBuffer();
 
     // Copy user handles.
     if (num_handles > 0) {
+        // Ensure we can try to get the handles.
+        R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
+                     user_handles, static_cast<u64>(sizeof(Handle) * num_handles)),
+                 ResultInvalidPointer);
+
+        // Get the handles.
+        GetCurrentMemory(kernel).ReadBlock(user_handles, handles.data(),
+                                           sizeof(Handle) * num_handles);
+
         // Convert the handles to objects.
-        R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
-                                                                         num_handles),
+        R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(
+                     objs.data(), handles.data(), num_handles),
                  ResultInvalidHandle);
     }
 
@@ -80,23 +94,6 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons
     R_RETURN(res);
 }
 
-/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_handles,
-                           int32_t num_handles, int64_t timeout_ns) {
-    LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles,
-              num_handles, timeout_ns);
-
-    // Ensure number of handles is valid.
-    R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
-    std::array<Handle, Svc::ArgumentHandleCountMax> handles;
-    if (num_handles > 0) {
-        GetCurrentMemory(system.Kernel())
-            .ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle));
-    }
-
-    R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns));
-}
-
 /// Resumes a thread waiting on WaitSynchronization
 Result CancelSynchronization(Core::System& system, Handle handle) {
     LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);