From 674122038ad01aae7eb4b6eff604f94fb8864bd4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Apr 2021 23:38:20 -0700 Subject: [PATCH] hle: kernel: svc: Migrate WaitSynchronization. --- src/core/hle/kernel/handle_table.h | 55 ++++++++++++++++++++++ src/core/hle/kernel/svc.cpp | 74 ++++++++++-------------------- 2 files changed, 80 insertions(+), 49 deletions(-) diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index d57188844..d6abdcd47 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/result.h" @@ -110,6 +111,16 @@ public: return DynamicObjectCast(GetGeneric(handle)); } + template + KAutoObject* GetObjectImpl(Handle handle) const { + if (!IsValid(handle)) { + return nullptr; + } + + auto* obj = objects_new[static_cast(handle >> 15)]; + return obj->DynamicCast(); + } + template KScopedAutoObject GetObject(Handle handle) const { if (handle == CurrentThread) { @@ -148,6 +159,48 @@ public: ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); + template + bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const { + // Try to convert and open all the handles. + size_t num_opened; + { + // Lock the table. + KScopedSpinLock lk(lock); + for (num_opened = 0; num_opened < num_handles; num_opened++) { + // Get the current handle. + const auto cur_handle = handles[num_opened]; + + // Get the object for the current handle. + KAutoObject* cur_object = this->GetObjectImpl(cur_handle); + if (cur_object == nullptr) { + break; + } + + // Cast the current object to the desired type. + T* cur_t = cur_object->DynamicCast(); + if (cur_t == nullptr) { + break; + } + + // Open a reference to the current object. + cur_t->Open(); + out[num_opened] = cur_t; + } + } + + // If we converted every object, succeed. + if (num_opened == num_handles) { + return true; + } + + // If we didn't convert entry object, close the ones we opened. + for (size_t i = 0; i < num_opened; i++) { + out[i]->Close(); + } + + return false; + } + private: /// Stores the Object referenced by the handle or null if the slot is empty. std::array, MAX_COUNT> objects; @@ -175,6 +228,8 @@ private: /// Head of the free slots linked list. u16 next_free_slot = 0; + mutable KSpinLock lock; + /// Underlying kernel instance that this handle table operates under. KernelCore& kernel; }; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 790839a4b..9e8184758 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -430,65 +430,41 @@ static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low, /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, - u64 handle_count, s64 nano_seconds) { - LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", - handles_address, handle_count, nano_seconds); + u64 num_handles, s64 nano_seconds) { + LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}", + handles_address, num_handles, nano_seconds); - auto& memory = system.Memory(); - if (!memory.IsValidVirtualAddress(handles_address)) { - LOG_ERROR(Kernel_SVC, - "Handle address is not a valid virtual address, handle_address=0x{:016X}", - handles_address); - return ResultInvalidPointer; - } - - static constexpr u64 MaxHandles = 0x40; - - if (handle_count > MaxHandles) { - LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}", - MaxHandles, handle_count); - return ResultOutOfRange; - } + // Ensure number of handles is valid. + R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); auto& kernel = system.Kernel(); - std::vector objects(handle_count); + std::vector objs(num_handles); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + Handle* handles = system.Memory().GetPointer(handles_address); - for (u64 i = 0; i < handle_count; ++i) { - const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); - - bool succeeded{}; - { - auto object = handle_table.Get(handle); - if (object) { - objects[i] = object; - succeeded = true; - } - } - - // TODO(bunnei): WORKAROUND WHILE WE HAVE TWO HANDLE TABLES - if (!succeeded) { - { - auto object = handle_table.GetObject(handle); - - if (object.IsNull()) { - LOG_ERROR(Kernel_SVC, "Object is a nullptr"); - return ResultInvalidHandle; - } - - objects[i] = object.GetPointerUnsafe(); - succeeded = true; - } - } + // Copy user handles. + if (num_handles > 0) { + // Convert the handles to objects. + R_UNLESS(handle_table.GetMultipleObjects(objs.data(), handles, + num_handles), + ResultInvalidHandle); } - return KSynchronizationObject::Wait(kernel, index, objects.data(), - static_cast(objects.size()), nano_seconds); + + // Ensure handles are closed when we're done. + SCOPE_EXIT({ + for (u64 i = 0; i < num_handles; ++i) { + objs[i]->Close(); + } + }); + + return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast(objs.size()), + nano_seconds); } static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, - s32 handle_count, u32 timeout_high, s32* index) { + s32 num_handles, u32 timeout_high, s32* index) { const s64 nano_seconds{(static_cast(timeout_high) << 32) | static_cast(timeout_low)}; - return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); + return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds); } /// Resumes a thread waiting on WaitSynchronization