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 GetSynchronizationObjectBuffer() { + return m_sync_object_buffer.sync_objects; + } + + std::span 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 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(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(sizeof(Handle) * num_handles)), + ResultInvalidPointer); - std::array 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 objs; - R_UNLESS(handle_table.GetMultipleObjects(objs.data(), handles.data(), - num_handles), - ResultInvalidHandle); + // Convert the handles to objects. + R_UNLESS(handle_table.GetMultipleObjects( + 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 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(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(objs.data(), handles, - num_handles), + R_UNLESS(handle_table.GetMultipleObjects( + 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 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);