summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/handle_table.h55
-rw-r--r--src/core/hle/kernel/svc.cpp70
2 files changed, 78 insertions, 47 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 @@
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/hle/kernel/k_auto_object.h" 12#include "core/hle/kernel/k_auto_object.h"
13#include "core/hle/kernel/k_spin_lock.h"
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/object.h" 15#include "core/hle/kernel/object.h"
15#include "core/hle/result.h" 16#include "core/hle/result.h"
@@ -111,6 +112,16 @@ public:
111 } 112 }
112 113
113 template <typename T = KAutoObject> 114 template <typename T = KAutoObject>
115 KAutoObject* GetObjectImpl(Handle handle) const {
116 if (!IsValid(handle)) {
117 return nullptr;
118 }
119
120 auto* obj = objects_new[static_cast<u16>(handle >> 15)];
121 return obj->DynamicCast<T*>();
122 }
123
124 template <typename T = KAutoObject>
114 KScopedAutoObject<T> GetObject(Handle handle) const { 125 KScopedAutoObject<T> GetObject(Handle handle) const {
115 if (handle == CurrentThread) { 126 if (handle == CurrentThread) {
116 return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast<T*>(); 127 return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast<T*>();
@@ -148,6 +159,48 @@ public:
148 159
149 ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); 160 ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type);
150 161
162 template <typename T>
163 bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
164 // Try to convert and open all the handles.
165 size_t num_opened;
166 {
167 // Lock the table.
168 KScopedSpinLock lk(lock);
169 for (num_opened = 0; num_opened < num_handles; num_opened++) {
170 // Get the current handle.
171 const auto cur_handle = handles[num_opened];
172
173 // Get the object for the current handle.
174 KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
175 if (cur_object == nullptr) {
176 break;
177 }
178
179 // Cast the current object to the desired type.
180 T* cur_t = cur_object->DynamicCast<T*>();
181 if (cur_t == nullptr) {
182 break;
183 }
184
185 // Open a reference to the current object.
186 cur_t->Open();
187 out[num_opened] = cur_t;
188 }
189 }
190
191 // If we converted every object, succeed.
192 if (num_opened == num_handles) {
193 return true;
194 }
195
196 // If we didn't convert entry object, close the ones we opened.
197 for (size_t i = 0; i < num_opened; i++) {
198 out[i]->Close();
199 }
200
201 return false;
202 }
203
151private: 204private:
152 /// Stores the Object referenced by the handle or null if the slot is empty. 205 /// Stores the Object referenced by the handle or null if the slot is empty.
153 std::array<std::shared_ptr<Object>, MAX_COUNT> objects; 206 std::array<std::shared_ptr<Object>, MAX_COUNT> objects;
@@ -175,6 +228,8 @@ private:
175 /// Head of the free slots linked list. 228 /// Head of the free slots linked list.
176 u16 next_free_slot = 0; 229 u16 next_free_slot = 0;
177 230
231 mutable KSpinLock lock;
232
178 /// Underlying kernel instance that this handle table operates under. 233 /// Underlying kernel instance that this handle table operates under.
179 KernelCore& kernel; 234 KernelCore& kernel;
180}; 235};
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,
430 430
431/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 431/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
432static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, 432static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
433 u64 handle_count, s64 nano_seconds) { 433 u64 num_handles, s64 nano_seconds) {
434 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", 434 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
435 handles_address, handle_count, nano_seconds); 435 handles_address, num_handles, nano_seconds);
436 436
437 auto& memory = system.Memory(); 437 // Ensure number of handles is valid.
438 if (!memory.IsValidVirtualAddress(handles_address)) { 438 R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
439 LOG_ERROR(Kernel_SVC,
440 "Handle address is not a valid virtual address, handle_address=0x{:016X}",
441 handles_address);
442 return ResultInvalidPointer;
443 }
444
445 static constexpr u64 MaxHandles = 0x40;
446
447 if (handle_count > MaxHandles) {
448 LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
449 MaxHandles, handle_count);
450 return ResultOutOfRange;
451 }
452 439
453 auto& kernel = system.Kernel(); 440 auto& kernel = system.Kernel();
454 std::vector<KSynchronizationObject*> objects(handle_count); 441 std::vector<KSynchronizationObject*> objs(num_handles);
455 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 442 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
443 Handle* handles = system.Memory().GetPointer<Handle>(handles_address);
456 444
457 for (u64 i = 0; i < handle_count; ++i) { 445 // Copy user handles.
458 const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); 446 if (num_handles > 0) {
447 // Convert the handles to objects.
448 R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
449 num_handles),
450 ResultInvalidHandle);
451 }
459 452
460 bool succeeded{}; 453 // Ensure handles are closed when we're done.
461 { 454 SCOPE_EXIT({
462 auto object = handle_table.Get<KSynchronizationObject>(handle); 455 for (u64 i = 0; i < num_handles; ++i) {
463 if (object) { 456 objs[i]->Close();
464 objects[i] = object;
465 succeeded = true;
466 }
467 } 457 }
458 });
468 459
469 // TODO(bunnei): WORKAROUND WHILE WE HAVE TWO HANDLE TABLES 460 return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
470 if (!succeeded) { 461 nano_seconds);
471 {
472 auto object = handle_table.GetObject<KSynchronizationObject>(handle);
473
474 if (object.IsNull()) {
475 LOG_ERROR(Kernel_SVC, "Object is a nullptr");
476 return ResultInvalidHandle;
477 }
478
479 objects[i] = object.GetPointerUnsafe();
480 succeeded = true;
481 }
482 }
483 }
484 return KSynchronizationObject::Wait(kernel, index, objects.data(),
485 static_cast<s32>(objects.size()), nano_seconds);
486} 462}
487 463
488static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, 464static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
489 s32 handle_count, u32 timeout_high, s32* index) { 465 s32 num_handles, u32 timeout_high, s32* index) {
490 const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; 466 const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
491 return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); 467 return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds);
492} 468}
493 469
494/// Resumes a thread waiting on WaitSynchronization 470/// Resumes a thread waiting on WaitSynchronization