summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2021-05-07 23:30:17 -0700
committerGravatar GitHub2021-05-07 23:30:17 -0700
commitfaa067f175cbf5e916ed75776817f0046e6731c4 (patch)
tree8ab02a72a6e4d6578848c8da2c02af02684aeec7 /src/core/hle/kernel/svc.cpp
parentMerge pull request #6287 from lioncash/ldr-copy (diff)
parenthle: kernel: KPageTable: CanContain should not be constexpr. (diff)
downloadyuzu-faa067f175cbf5e916ed75776817f0046e6731c4.tar.gz
yuzu-faa067f175cbf5e916ed75776817f0046e6731c4.tar.xz
yuzu-faa067f175cbf5e916ed75776817f0046e6731c4.zip
Merge pull request #6266 from bunnei/kautoobject-refactor
Kernel Rework: Migrate kernel objects to KAutoObject
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp995
1 files changed, 466 insertions, 529 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index bebb86154..52011be9c 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -21,15 +21,16 @@
21#include "core/core_timing.h" 21#include "core/core_timing.h"
22#include "core/core_timing_util.h" 22#include "core/core_timing_util.h"
23#include "core/cpu_manager.h" 23#include "core/cpu_manager.h"
24#include "core/hle/kernel/client_port.h"
25#include "core/hle/kernel/client_session.h"
26#include "core/hle/kernel/handle_table.h"
27#include "core/hle/kernel/k_address_arbiter.h" 24#include "core/hle/kernel/k_address_arbiter.h"
25#include "core/hle/kernel/k_client_port.h"
26#include "core/hle/kernel/k_client_session.h"
28#include "core/hle/kernel/k_condition_variable.h" 27#include "core/hle/kernel/k_condition_variable.h"
29#include "core/hle/kernel/k_event.h" 28#include "core/hle/kernel/k_event.h"
29#include "core/hle/kernel/k_handle_table.h"
30#include "core/hle/kernel/k_memory_block.h" 30#include "core/hle/kernel/k_memory_block.h"
31#include "core/hle/kernel/k_memory_layout.h" 31#include "core/hle/kernel/k_memory_layout.h"
32#include "core/hle/kernel/k_page_table.h" 32#include "core/hle/kernel/k_page_table.h"
33#include "core/hle/kernel/k_process.h"
33#include "core/hle/kernel/k_readable_event.h" 34#include "core/hle/kernel/k_readable_event.h"
34#include "core/hle/kernel/k_resource_limit.h" 35#include "core/hle/kernel/k_resource_limit.h"
35#include "core/hle/kernel/k_scheduler.h" 36#include "core/hle/kernel/k_scheduler.h"
@@ -38,16 +39,15 @@
38#include "core/hle/kernel/k_shared_memory.h" 39#include "core/hle/kernel/k_shared_memory.h"
39#include "core/hle/kernel/k_synchronization_object.h" 40#include "core/hle/kernel/k_synchronization_object.h"
40#include "core/hle/kernel/k_thread.h" 41#include "core/hle/kernel/k_thread.h"
42#include "core/hle/kernel/k_transfer_memory.h"
41#include "core/hle/kernel/k_writable_event.h" 43#include "core/hle/kernel/k_writable_event.h"
42#include "core/hle/kernel/kernel.h" 44#include "core/hle/kernel/kernel.h"
43#include "core/hle/kernel/physical_core.h" 45#include "core/hle/kernel/physical_core.h"
44#include "core/hle/kernel/process.h"
45#include "core/hle/kernel/svc.h" 46#include "core/hle/kernel/svc.h"
46#include "core/hle/kernel/svc_results.h" 47#include "core/hle/kernel/svc_results.h"
47#include "core/hle/kernel/svc_types.h" 48#include "core/hle/kernel/svc_types.h"
48#include "core/hle/kernel/svc_wrap.h" 49#include "core/hle/kernel/svc_wrap.h"
49#include "core/hle/kernel/time_manager.h" 50#include "core/hle/kernel/time_manager.h"
50#include "core/hle/kernel/transfer_memory.h"
51#include "core/hle/lock.h" 51#include "core/hle/lock.h"
52#include "core/hle/result.h" 52#include "core/hle/result.h"
53#include "core/hle/service/service.h" 53#include "core/hle/service/service.h"
@@ -113,7 +113,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
113 LOG_ERROR(Kernel_SVC, 113 LOG_ERROR(Kernel_SVC,
114 "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", 114 "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
115 dst_addr, size); 115 dst_addr, size);
116 return ResultInvalidMemoryRange; 116 return ResultInvalidMemoryRegion;
117 } 117 }
118 118
119 if (manager.IsInsideHeapRegion(dst_addr, size)) { 119 if (manager.IsInsideHeapRegion(dst_addr, size)) {
@@ -121,7 +121,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
121 "Destination does not fit within the heap region, addr=0x{:016X}, " 121 "Destination does not fit within the heap region, addr=0x{:016X}, "
122 "size=0x{:016X}", 122 "size=0x{:016X}",
123 dst_addr, size); 123 dst_addr, size);
124 return ResultInvalidMemoryRange; 124 return ResultInvalidMemoryRegion;
125 } 125 }
126 126
127 if (manager.IsInsideAliasRegion(dst_addr, size)) { 127 if (manager.IsInsideAliasRegion(dst_addr, size)) {
@@ -129,7 +129,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
129 "Destination does not fit within the map region, addr=0x{:016X}, " 129 "Destination does not fit within the map region, addr=0x{:016X}, "
130 "size=0x{:016X}", 130 "size=0x{:016X}",
131 dst_addr, size); 131 dst_addr, size);
132 return ResultInvalidMemoryRange; 132 return ResultInvalidMemoryRegion;
133 } 133 }
134 134
135 return RESULT_SUCCESS; 135 return RESULT_SUCCESS;
@@ -141,38 +141,6 @@ enum class ResourceLimitValueType {
141 PeakValue, 141 PeakValue,
142}; 142};
143 143
144ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
145 u32 resource_type, ResourceLimitValueType value_type) {
146 std::lock_guard lock{HLE::g_hle_lock};
147 const auto type = static_cast<LimitableResource>(resource_type);
148 if (!IsValidResourceType(type)) {
149 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
150 return ResultInvalidEnumValue;
151 }
152
153 const auto* const current_process = system.Kernel().CurrentProcess();
154 ASSERT(current_process != nullptr);
155
156 const auto resource_limit_object =
157 current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
158 if (!resource_limit_object) {
159 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
160 resource_limit);
161 return ResultInvalidHandle;
162 }
163
164 switch (value_type) {
165 case ResourceLimitValueType::CurrentValue:
166 return MakeResult(resource_limit_object->GetCurrentValue(type));
167 case ResourceLimitValueType::LimitValue:
168 return MakeResult(resource_limit_object->GetLimitValue(type));
169 case ResourceLimitValueType::PeakValue:
170 return MakeResult(resource_limit_object->GetPeakValue(type));
171 default:
172 LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type);
173 return ResultInvalidEnumValue;
174 }
175}
176} // Anonymous namespace 144} // Anonymous namespace
177 145
178/// Set the process heap to a given Size. It can both extend and shrink the heap. 146/// Set the process heap to a given Size. It can both extend and shrink the heap.
@@ -291,11 +259,8 @@ static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr
291} 259}
292 260
293/// Connect to an OS service given the port name, returns the handle to the port to out 261/// Connect to an OS service given the port name, returns the handle to the port to out
294static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, 262static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) {
295 VAddr port_name_address) {
296 std::lock_guard lock{HLE::g_hle_lock};
297 auto& memory = system.Memory(); 263 auto& memory = system.Memory();
298
299 if (!memory.IsValidVirtualAddress(port_name_address)) { 264 if (!memory.IsValidVirtualAddress(port_name_address)) {
300 LOG_ERROR(Kernel_SVC, 265 LOG_ERROR(Kernel_SVC,
301 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", 266 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
@@ -314,21 +279,33 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
314 279
315 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); 280 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
316 281
282 // Get the current handle table.
317 auto& kernel = system.Kernel(); 283 auto& kernel = system.Kernel();
284 auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
285
286 // Find the client port.
318 const auto it = kernel.FindNamedPort(port_name); 287 const auto it = kernel.FindNamedPort(port_name);
319 if (!kernel.IsValidNamedPort(it)) { 288 if (!kernel.IsValidNamedPort(it)) {
320 LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); 289 LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
321 return ResultNotFound; 290 return ResultNotFound;
322 } 291 }
292 auto port = it->second;
323 293
324 auto client_port = it->second; 294 // Reserve a handle for the port.
295 // NOTE: Nintendo really does write directly to the output handle here.
296 R_TRY(handle_table.Reserve(out));
297 auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); });
325 298
326 std::shared_ptr<ClientSession> client_session; 299 // Create a session.
327 CASCADE_RESULT(client_session, client_port->Connect()); 300 KClientSession* session{};
301 R_TRY(port->CreateSession(std::addressof(session)));
328 302
329 // Return the client session 303 // Register the session in the table, close the extra reference.
330 auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 304 handle_table.Register(*out, session);
331 CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); 305 session->Close();
306
307 // We succeeded.
308 handle_guard.Cancel();
332 return RESULT_SUCCESS; 309 return RESULT_SUCCESS;
333} 310}
334 311
@@ -340,14 +317,12 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,
340 317
341/// Makes a blocking IPC call to an OS service. 318/// Makes a blocking IPC call to an OS service.
342static ResultCode SendSyncRequest(Core::System& system, Handle handle) { 319static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
320
343 auto& kernel = system.Kernel(); 321 auto& kernel = system.Kernel();
344 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
345 std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle);
346 if (!session) {
347 LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
348 return ResultInvalidHandle;
349 }
350 322
323 KScopedAutoObject session =
324 kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
325 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
351 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); 326 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
352 327
353 auto thread = kernel.CurrentScheduler()->GetCurrentThread(); 328 auto thread = kernel.CurrentScheduler()->GetCurrentThread();
@@ -355,7 +330,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
355 KScopedSchedulerLock lock(kernel); 330 KScopedSchedulerLock lock(kernel);
356 thread->SetState(ThreadState::Waiting); 331 thread->SetState(ThreadState::Waiting);
357 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); 332 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
358 session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); 333 session->SendSyncRequest(thread, system.Memory(), system.CoreTiming());
359 } 334 }
360 335
361 KSynchronizationObject* dummy{}; 336 KSynchronizationObject* dummy{};
@@ -368,18 +343,13 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
368 343
369/// Get the ID for the specified thread. 344/// Get the ID for the specified thread.
370static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { 345static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
371 LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
372
373 // Get the thread from its handle. 346 // Get the thread from its handle.
374 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 347 KScopedAutoObject thread =
375 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 348 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
376 if (!thread) { 349 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
377 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
378 return ResultInvalidHandle;
379 }
380 350
381 // Get the thread's id. 351 // Get the thread's id.
382 *out_thread_id = thread->GetThreadID(); 352 *out_thread_id = thread->GetId();
383 return RESULT_SUCCESS; 353 return RESULT_SUCCESS;
384} 354}
385 355
@@ -395,110 +365,101 @@ static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low,
395} 365}
396 366
397/// Gets the ID of the specified process or a specified thread's owning process. 367/// Gets the ID of the specified process or a specified thread's owning process.
398static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { 368static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle handle) {
399 LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); 369 LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
400 370
401 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 371 // Get the object from the handle table.
402 const std::shared_ptr<Process> process = handle_table.Get<Process>(handle); 372 KScopedAutoObject obj =
403 if (process) { 373 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>(
404 *process_id = process->GetProcessID(); 374 static_cast<Handle>(handle));
405 return RESULT_SUCCESS; 375 R_UNLESS(obj.IsNotNull(), ResultInvalidHandle);
376
377 // Get the process from the object.
378 KProcess* process = nullptr;
379 if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) {
380 // The object is a process, so we can use it directly.
381 process = p;
382 } else if (KThread* t = obj->DynamicCast<KThread*>(); t != nullptr) {
383 // The object is a thread, so we want to use its parent.
384 process = reinterpret_cast<KThread*>(obj.GetPointerUnsafe())->GetOwnerProcess();
385 } else {
386 // TODO(bunnei): This should also handle debug objects before returning.
387 UNIMPLEMENTED_MSG("Debug objects not implemented");
406 } 388 }
407 389
408 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 390 // Make sure the target process exists.
409 if (thread) { 391 R_UNLESS(process != nullptr, ResultInvalidHandle);
410 const Process* const owner_process = thread->GetOwnerProcess();
411 if (!owner_process) {
412 LOG_ERROR(Kernel_SVC, "Non-existent owning process encountered.");
413 return ResultInvalidHandle;
414 }
415
416 *process_id = owner_process->GetProcessID();
417 return RESULT_SUCCESS;
418 }
419 392
420 // NOTE: This should also handle debug objects before returning. 393 // Get the process id.
394 *out_process_id = process->GetId();
421 395
422 LOG_ERROR(Kernel_SVC, "Handle does not exist, handle=0x{:08X}", handle);
423 return ResultInvalidHandle; 396 return ResultInvalidHandle;
424} 397}
425 398
426static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, 399static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low,
427 Handle handle) { 400 u32* out_process_id_high, Handle handle) {
428 u64 process_id{}; 401 u64 out_process_id{};
429 const auto result = GetProcessId(system, &process_id, handle); 402 const auto result = GetProcessId(system, &out_process_id, handle);
430 *process_id_low = static_cast<u32>(process_id); 403 *out_process_id_low = static_cast<u32>(out_process_id);
431 *process_id_high = static_cast<u32>(process_id >> 32); 404 *out_process_id_high = static_cast<u32>(out_process_id >> 32);
432 return result; 405 return result;
433} 406}
434 407
435/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 408/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
436static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, 409static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
437 u64 handle_count, s64 nano_seconds) { 410 u64 num_handles, s64 nano_seconds) {
438 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", 411 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
439 handles_address, handle_count, nano_seconds); 412 handles_address, num_handles, nano_seconds);
440 413
441 auto& memory = system.Memory(); 414 // Ensure number of handles is valid.
442 if (!memory.IsValidVirtualAddress(handles_address)) { 415 R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
443 LOG_ERROR(Kernel_SVC,
444 "Handle address is not a valid virtual address, handle_address=0x{:016X}",
445 handles_address);
446 return ResultInvalidPointer;
447 }
448
449 static constexpr u64 MaxHandles = 0x40;
450
451 if (handle_count > MaxHandles) {
452 LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
453 MaxHandles, handle_count);
454 return ResultOutOfRange;
455 }
456 416
457 auto& kernel = system.Kernel(); 417 auto& kernel = system.Kernel();
458 std::vector<KSynchronizationObject*> objects(handle_count); 418 std::vector<KSynchronizationObject*> objs(num_handles);
459 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 419 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
420 Handle* handles = system.Memory().GetPointer<Handle>(handles_address);
460 421
461 for (u64 i = 0; i < handle_count; ++i) { 422 // Copy user handles.
462 const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); 423 if (num_handles > 0) {
463 const auto object = handle_table.Get<KSynchronizationObject>(handle); 424 // Convert the handles to objects.
425 R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
426 num_handles),
427 ResultInvalidHandle);
428 }
464 429
465 if (object == nullptr) { 430 // Ensure handles are closed when we're done.
466 LOG_ERROR(Kernel_SVC, "Object is a nullptr"); 431 SCOPE_EXIT({
467 return ResultInvalidHandle; 432 for (u64 i = 0; i < num_handles; ++i) {
433 objs[i]->Close();
468 } 434 }
435 });
469 436
470 objects[i] = object.get(); 437 return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
471 } 438 nano_seconds);
472 return KSynchronizationObject::Wait(kernel, index, objects.data(),
473 static_cast<s32>(objects.size()), nano_seconds);
474} 439}
475 440
476static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, 441static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
477 s32 handle_count, u32 timeout_high, s32* index) { 442 s32 num_handles, u32 timeout_high, s32* index) {
478 const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; 443 const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
479 return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); 444 return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds);
480} 445}
481 446
482/// Resumes a thread waiting on WaitSynchronization 447/// Resumes a thread waiting on WaitSynchronization
483static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { 448static ResultCode CancelSynchronization(Core::System& system, Handle handle) {
484 LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); 449 LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
485 450
486 // Get the thread from its handle. 451 // Get the thread from its handle.
487 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 452 KScopedAutoObject thread =
488 std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 453 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
489 454 static_cast<Handle>(handle));
490 if (!thread) {
491 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
492 return ResultInvalidHandle;
493 }
494 455
495 // Cancel the thread's wait. 456 // Cancel the thread's wait.
496 thread->WaitCancel(); 457 thread->WaitCancel();
497 return RESULT_SUCCESS; 458 return RESULT_SUCCESS;
498} 459}
499 460
500static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { 461static ResultCode CancelSynchronization32(Core::System& system, Handle handle) {
501 return CancelSynchronization(system, thread_handle); 462 return CancelSynchronization(system, handle);
502} 463}
503 464
504/// Attempts to locks a mutex 465/// Attempts to locks a mutex
@@ -678,7 +639,7 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
678} 639}
679 640
680/// Gets system/memory information for the current process 641/// Gets system/memory information for the current process
681static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, 642static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle,
682 u64 info_sub_id) { 643 u64 info_sub_id) {
683 std::lock_guard lock{HLE::g_hle_lock}; 644 std::lock_guard lock{HLE::g_hle_lock};
684 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, 645 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
@@ -744,10 +705,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
744 return ResultInvalidEnumValue; 705 return ResultInvalidEnumValue;
745 } 706 }
746 707
747 const auto& current_process_handle_table = 708 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
748 system.Kernel().CurrentProcess()->GetHandleTable(); 709 KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
749 const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle)); 710 if (process.IsNull()) {
750 if (!process) {
751 LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", 711 LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}",
752 info_id, info_sub_id, handle); 712 info_id, info_sub_id, handle);
753 return ResultInvalidHandle; 713 return ResultInvalidHandle;
@@ -851,21 +811,19 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
851 return ResultInvalidCombination; 811 return ResultInvalidCombination;
852 } 812 }
853 813
854 Process* const current_process = system.Kernel().CurrentProcess(); 814 KProcess* const current_process = system.Kernel().CurrentProcess();
855 HandleTable& handle_table = current_process->GetHandleTable(); 815 KHandleTable& handle_table = current_process->GetHandleTable();
856 const auto resource_limit = current_process->GetResourceLimit(); 816 const auto resource_limit = current_process->GetResourceLimit();
857 if (!resource_limit) { 817 if (!resource_limit) {
858 *result = KernelHandle::InvalidHandle; 818 *result = Svc::InvalidHandle;
859 // Yes, the kernel considers this a successful operation. 819 // Yes, the kernel considers this a successful operation.
860 return RESULT_SUCCESS; 820 return RESULT_SUCCESS;
861 } 821 }
862 822
863 const auto table_result = handle_table.Create(resource_limit); 823 Handle handle{};
864 if (table_result.Failed()) { 824 R_TRY(handle_table.Add(&handle, resource_limit));
865 return table_result.Code();
866 }
867 825
868 *result = *table_result; 826 *result = handle;
869 return RESULT_SUCCESS; 827 return RESULT_SUCCESS;
870 } 828 }
871 829
@@ -876,9 +834,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
876 return ResultInvalidHandle; 834 return ResultInvalidHandle;
877 } 835 }
878 836
879 if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { 837 if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) {
880 LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", 838 LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
881 Process::RANDOM_ENTROPY_SIZE, info_sub_id); 839 KProcess::RANDOM_ENTROPY_SIZE, info_sub_id);
882 return ResultInvalidCombination; 840 return ResultInvalidCombination;
883 } 841 }
884 842
@@ -899,9 +857,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
899 return ResultInvalidCombination; 857 return ResultInvalidCombination;
900 } 858 }
901 859
902 const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>( 860 KScopedAutoObject thread =
903 static_cast<Handle>(handle)); 861 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
904 if (!thread) { 862 static_cast<Handle>(handle));
863 if (thread.IsNull()) {
905 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", 864 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
906 static_cast<Handle>(handle)); 865 static_cast<Handle>(handle));
907 return ResultInvalidHandle; 866 return ResultInvalidHandle;
@@ -910,7 +869,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
910 const auto& core_timing = system.CoreTiming(); 869 const auto& core_timing = system.CoreTiming();
911 const auto& scheduler = *system.Kernel().CurrentScheduler(); 870 const auto& scheduler = *system.Kernel().CurrentScheduler();
912 const auto* const current_thread = scheduler.GetCurrentThread(); 871 const auto* const current_thread = scheduler.GetCurrentThread();
913 const bool same_thread = current_thread == thread.get(); 872 const bool same_thread = current_thread == thread.GetPointerUnsafe();
914 873
915 const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); 874 const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
916 u64 out_ticks = 0; 875 u64 out_ticks = 0;
@@ -966,10 +925,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
966 925
967 if (!(addr < addr + size)) { 926 if (!(addr < addr + size)) {
968 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); 927 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
969 return ResultInvalidMemoryRange; 928 return ResultInvalidMemoryRegion;
970 } 929 }
971 930
972 Process* const current_process{system.Kernel().CurrentProcess()}; 931 KProcess* const current_process{system.Kernel().CurrentProcess()};
973 auto& page_table{current_process->PageTable()}; 932 auto& page_table{current_process->PageTable()};
974 933
975 if (current_process->GetSystemResourceSize() == 0) { 934 if (current_process->GetSystemResourceSize() == 0) {
@@ -981,14 +940,14 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
981 LOG_ERROR(Kernel_SVC, 940 LOG_ERROR(Kernel_SVC,
982 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, 941 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
983 size); 942 size);
984 return ResultInvalidMemoryRange; 943 return ResultInvalidMemoryRegion;
985 } 944 }
986 945
987 if (page_table.IsOutsideAliasRegion(addr, size)) { 946 if (page_table.IsOutsideAliasRegion(addr, size)) {
988 LOG_ERROR(Kernel_SVC, 947 LOG_ERROR(Kernel_SVC,
989 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, 948 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
990 size); 949 size);
991 return ResultInvalidMemoryRange; 950 return ResultInvalidMemoryRegion;
992 } 951 }
993 952
994 return page_table.MapPhysicalMemory(addr, size); 953 return page_table.MapPhysicalMemory(addr, size);
@@ -1020,10 +979,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
1020 979
1021 if (!(addr < addr + size)) { 980 if (!(addr < addr + size)) {
1022 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); 981 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
1023 return ResultInvalidMemoryRange; 982 return ResultInvalidMemoryRegion;
1024 } 983 }
1025 984
1026 Process* const current_process{system.Kernel().CurrentProcess()}; 985 KProcess* const current_process{system.Kernel().CurrentProcess()};
1027 auto& page_table{current_process->PageTable()}; 986 auto& page_table{current_process->PageTable()};
1028 987
1029 if (current_process->GetSystemResourceSize() == 0) { 988 if (current_process->GetSystemResourceSize() == 0) {
@@ -1035,14 +994,14 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
1035 LOG_ERROR(Kernel_SVC, 994 LOG_ERROR(Kernel_SVC,
1036 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, 995 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
1037 size); 996 size);
1038 return ResultInvalidMemoryRange; 997 return ResultInvalidMemoryRegion;
1039 } 998 }
1040 999
1041 if (page_table.IsOutsideAliasRegion(addr, size)) { 1000 if (page_table.IsOutsideAliasRegion(addr, size)) {
1042 LOG_ERROR(Kernel_SVC, 1001 LOG_ERROR(Kernel_SVC,
1043 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, 1002 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
1044 size); 1003 size);
1045 return ResultInvalidMemoryRange; 1004 return ResultInvalidMemoryRegion;
1046 } 1005 }
1047 1006
1048 return page_table.UnmapPhysicalMemory(addr, size); 1007 return page_table.UnmapPhysicalMemory(addr, size);
@@ -1062,37 +1021,19 @@ static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
1062 constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { 1021 constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
1063 return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; 1022 return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
1064 }; 1023 };
1065 if (!IsValidThreadActivity(thread_activity)) { 1024 R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue);
1066 LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
1067 thread_activity);
1068 return ResultInvalidEnumValue;
1069 }
1070 1025
1071 // Get the thread from its handle. 1026 // Get the thread from its handle.
1072 auto& kernel = system.Kernel(); 1027 KScopedAutoObject thread =
1073 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1028 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1074 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1029 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1075 if (!thread) {
1076 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
1077 return ResultInvalidHandle;
1078 }
1079 1030
1080 // Check that the activity is being set on a non-current thread for the current process. 1031 // Check that the activity is being set on a non-current thread for the current process.
1081 if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { 1032 R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle);
1082 LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); 1033 R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy);
1083 return ResultInvalidHandle;
1084 }
1085 if (thread.get() == GetCurrentThreadPointer(kernel)) {
1086 LOG_ERROR(Kernel_SVC, "Thread is busy");
1087 return ResultBusy;
1088 }
1089 1034
1090 // Set the activity. 1035 // Set the activity.
1091 const auto set_result = thread->SetActivity(thread_activity); 1036 R_TRY(thread->SetActivity(thread_activity));
1092 if (set_result.IsError()) {
1093 LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
1094 return set_result;
1095 }
1096 1037
1097 return RESULT_SUCCESS; 1038 return RESULT_SUCCESS;
1098} 1039}
@@ -1107,36 +1048,55 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
1107 LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, 1048 LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
1108 thread_handle); 1049 thread_handle);
1109 1050
1051 auto& kernel = system.Kernel();
1052
1110 // Get the thread from its handle. 1053 // Get the thread from its handle.
1111 const auto* current_process = system.Kernel().CurrentProcess(); 1054 KScopedAutoObject thread =
1112 const std::shared_ptr<KThread> thread = 1055 kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1113 current_process->GetHandleTable().Get<KThread>(thread_handle); 1056 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1114 if (!thread) {
1115 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
1116 return ResultInvalidHandle;
1117 }
1118 1057
1119 // Require the handle be to a non-current thread in the current process. 1058 // Require the handle be to a non-current thread in the current process.
1120 if (thread->GetOwnerProcess() != current_process) { 1059 const auto* current_process = kernel.CurrentProcess();
1121 LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); 1060 R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
1122 return ResultInvalidHandle;
1123 }
1124 if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
1125 LOG_ERROR(Kernel_SVC, "Current thread is busy.");
1126 return ResultBusy;
1127 }
1128 1061
1129 // Get the thread context. 1062 // Verify that the thread isn't terminated.
1130 std::vector<u8> context; 1063 R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
1131 const auto context_result = thread->GetThreadContext3(context); 1064
1132 if (context_result.IsError()) { 1065 /// Check that the thread is not the current one.
1133 LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", 1066 /// NOTE: Nintendo does not check this, and thus the following loop will deadlock.
1134 context_result.raw); 1067 R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId);
1135 return context_result; 1068
1136 } 1069 // Try to get the thread context until the thread isn't current on any core.
1070 while (true) {
1071 KScopedSchedulerLock sl{kernel};
1137 1072
1138 // Copy the thread context to user space. 1073 // TODO(bunnei): Enforce that thread is suspended for debug here.
1139 system.Memory().WriteBlock(out_context, context.data(), context.size()); 1074
1075 // If the thread's raw state isn't runnable, check if it's current on some core.
1076 if (thread->GetRawState() != ThreadState::Runnable) {
1077 bool current = false;
1078 for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
1079 if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) {
1080 current = true;
1081 }
1082 break;
1083 }
1084
1085 // If the thread is current, retry until it isn't.
1086 if (current) {
1087 continue;
1088 }
1089 }
1090
1091 // Get the thread context.
1092 std::vector<u8> context;
1093 R_TRY(thread->GetThreadContext3(context));
1094
1095 // Copy the thread context to user space.
1096 system.Memory().WriteBlock(out_context, context.data(), context.size());
1097
1098 return RESULT_SUCCESS;
1099 }
1140 1100
1141 return RESULT_SUCCESS; 1101 return RESULT_SUCCESS;
1142} 1102}
@@ -1150,12 +1110,9 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
1150 LOG_TRACE(Kernel_SVC, "called"); 1110 LOG_TRACE(Kernel_SVC, "called");
1151 1111
1152 // Get the thread from its handle. 1112 // Get the thread from its handle.
1153 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1113 KScopedAutoObject thread =
1154 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 1114 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
1155 if (!thread) { 1115 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1156 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
1157 return ResultInvalidHandle;
1158 }
1159 1116
1160 // Get the thread's priority. 1117 // Get the thread's priority.
1161 *out_priority = thread->GetPriority(); 1118 *out_priority = thread->GetPriority();
@@ -1167,30 +1124,26 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, H
1167} 1124}
1168 1125
1169/// Sets the priority for the specified thread 1126/// Sets the priority for the specified thread
1170static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { 1127static ResultCode SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) {
1171 LOG_TRACE(Kernel_SVC, "called"); 1128 // Get the current process.
1129 KProcess& process = *system.Kernel().CurrentProcess();
1172 1130
1173 // Validate the priority. 1131 // Validate the priority.
1174 if (HighestThreadPriority > priority || priority > LowestThreadPriority) { 1132 R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
1175 LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); 1133 ResultInvalidPriority);
1176 return ResultInvalidPriority; 1134 R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
1177 }
1178 1135
1179 // Get the thread from its handle. 1136 // Get the thread from its handle.
1180 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1137 KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle);
1181 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 1138 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1182 if (!thread) {
1183 LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
1184 return ResultInvalidHandle;
1185 }
1186 1139
1187 // Set the thread priority. 1140 // Set the thread priority.
1188 thread->SetBasePriority(priority); 1141 thread->SetBasePriority(priority);
1189 return RESULT_SUCCESS; 1142 return RESULT_SUCCESS;
1190} 1143}
1191 1144
1192static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { 1145static ResultCode SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) {
1193 return SetThreadPriority(system, handle, priority); 1146 return SetThreadPriority(system, thread_handle, priority);
1194} 1147}
1195 1148
1196/// Get which CPU core is executing the current thread 1149/// Get which CPU core is executing the current thread
@@ -1203,82 +1156,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) {
1203 return GetCurrentProcessorNumber(system); 1156 return GetCurrentProcessorNumber(system);
1204} 1157}
1205 1158
1206static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, 1159constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
1207 u64 size, u32 permissions) { 1160 switch (perm) {
1208 std::lock_guard lock{HLE::g_hle_lock}; 1161 case Svc::MemoryPermission::Read:
1162 case Svc::MemoryPermission::ReadWrite:
1163 return true;
1164 default:
1165 return false;
1166 }
1167}
1168
1169constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
1170 return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
1171}
1172
1173static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
1174 u64 size, Svc::MemoryPermission map_perm) {
1209 LOG_TRACE(Kernel_SVC, 1175 LOG_TRACE(Kernel_SVC,
1210 "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", 1176 "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
1211 shared_memory_handle, addr, size, permissions); 1177 shmem_handle, address, size, map_perm);
1212 1178
1213 if (!Common::Is4KBAligned(addr)) { 1179 // Validate the address/size.
1214 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); 1180 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1215 return ResultInvalidAddress; 1181 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1216 } 1182 R_UNLESS(size > 0, ResultInvalidSize);
1183 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1217 1184
1218 if (size == 0) { 1185 // Validate the permission.
1219 LOG_ERROR(Kernel_SVC, "Size is 0"); 1186 R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
1220 return ResultInvalidSize;
1221 }
1222 1187
1223 if (!Common::Is4KBAligned(size)) { 1188 // Get the current process.
1224 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); 1189 auto& process = *system.Kernel().CurrentProcess();
1225 return ResultInvalidSize; 1190 auto& page_table = process.PageTable();
1226 }
1227 1191
1228 if (!IsValidAddressRange(addr, size)) { 1192 // Get the shared memory.
1229 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", 1193 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
1230 addr, size); 1194 R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
1231 return ResultInvalidCurrentMemory;
1232 }
1233 1195
1234 const auto permission_type = static_cast<MemoryPermission>(permissions); 1196 // Verify that the mapping is in range.
1235 if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { 1197 R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
1236 LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
1237 permissions);
1238 return ResultInvalidMemoryPermissions;
1239 }
1240 1198
1241 auto* const current_process{system.Kernel().CurrentProcess()}; 1199 // Add the shared memory to the process.
1242 auto& page_table{current_process->PageTable()}; 1200 R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
1243 1201
1244 if (page_table.IsInvalidRegion(addr, size)) { 1202 // Ensure that we clean up the shared memory if we fail to map it.
1245 LOG_ERROR(Kernel_SVC, 1203 auto guard =
1246 "Addr does not fit within the valid region, addr=0x{:016X}, " 1204 SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); });
1247 "size=0x{:016X}",
1248 addr, size);
1249 return ResultInvalidMemoryRange;
1250 }
1251 1205
1252 if (page_table.IsInsideHeapRegion(addr, size)) { 1206 // Map the shared memory.
1253 LOG_ERROR(Kernel_SVC, 1207 R_TRY(shmem->Map(process, address, size, map_perm));
1254 "Addr does not fit within the heap region, addr=0x{:016X}, "
1255 "size=0x{:016X}",
1256 addr, size);
1257 return ResultInvalidMemoryRange;
1258 }
1259 1208
1260 if (page_table.IsInsideAliasRegion(addr, size)) { 1209 // We succeeded.
1261 LOG_ERROR(Kernel_SVC, 1210 guard.Cancel();
1262 "Address does not fit within the map region, addr=0x{:016X}, " 1211 return RESULT_SUCCESS;
1263 "size=0x{:016X}", 1212}
1264 addr, size);
1265 return ResultInvalidMemoryRange;
1266 }
1267 1213
1268 auto shared_memory{current_process->GetHandleTable().Get<KSharedMemory>(shared_memory_handle)}; 1214static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
1269 if (!shared_memory) { 1215 u32 size, Svc::MemoryPermission map_perm) {
1270 LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", 1216 return MapSharedMemory(system, shmem_handle, address, size, map_perm);
1271 shared_memory_handle); 1217}
1272 return ResultInvalidHandle; 1218
1273 } 1219static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
1220 u64 size) {
1221 // Validate the address/size.
1222 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1223 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1224 R_UNLESS(size > 0, ResultInvalidSize);
1225 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1226
1227 // Get the current process.
1228 auto& process = *system.Kernel().CurrentProcess();
1229 auto& page_table = process.PageTable();
1230
1231 // Get the shared memory.
1232 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
1233 R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
1274 1234
1275 return shared_memory->Map(*current_process, addr, size, 1235 // Verify that the mapping is in range.
1276 static_cast<KMemoryPermission>(permission_type)); 1236 R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
1237
1238 // Unmap the shared memory.
1239 R_TRY(shmem->Unmap(process, address, size));
1240
1241 // Remove the shared memory from the process.
1242 process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
1243
1244 return RESULT_SUCCESS;
1277} 1245}
1278 1246
1279static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, 1247static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
1280 u32 size, u32 permissions) { 1248 u32 size) {
1281 return MapSharedMemory(system, shared_memory_handle, addr, size, permissions); 1249 return UnmapSharedMemory(system, shmem_handle, address, size);
1282} 1250}
1283 1251
1284static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, 1252static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
@@ -1287,8 +1255,8 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
1287 std::lock_guard lock{HLE::g_hle_lock}; 1255 std::lock_guard lock{HLE::g_hle_lock};
1288 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); 1256 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
1289 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1257 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1290 std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle); 1258 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
1291 if (!process) { 1259 if (process.IsNull()) {
1292 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", 1260 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
1293 process_handle); 1261 process_handle);
1294 return ResultInvalidHandle; 1262 return ResultInvalidHandle;
@@ -1369,8 +1337,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
1369 } 1337 }
1370 1338
1371 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1339 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1372 auto process = handle_table.Get<Process>(process_handle); 1340 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
1373 if (!process) { 1341 if (process.IsNull()) {
1374 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", 1342 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1375 process_handle); 1343 process_handle);
1376 return ResultInvalidHandle; 1344 return ResultInvalidHandle;
@@ -1390,7 +1358,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
1390 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " 1358 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1391 "size=0x{:016X}).", 1359 "size=0x{:016X}).",
1392 dst_address, size); 1360 dst_address, size);
1393 return ResultInvalidMemoryRange; 1361 return ResultInvalidMemoryRegion;
1394 } 1362 }
1395 1363
1396 return page_table.MapProcessCodeMemory(dst_address, src_address, size); 1364 return page_table.MapProcessCodeMemory(dst_address, src_address, size);
@@ -1437,8 +1405,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
1437 } 1405 }
1438 1406
1439 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1407 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1440 auto process = handle_table.Get<Process>(process_handle); 1408 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
1441 if (!process) { 1409 if (process.IsNull()) {
1442 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", 1410 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1443 process_handle); 1411 process_handle);
1444 return ResultInvalidHandle; 1412 return ResultInvalidHandle;
@@ -1458,7 +1426,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
1458 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " 1426 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1459 "size=0x{:016X}).", 1427 "size=0x{:016X}).",
1460 dst_address, size); 1428 dst_address, size);
1461 return ResultInvalidMemoryRange; 1429 return ResultInvalidMemoryRegion;
1462 } 1430 }
1463 1431
1464 return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); 1432 return page_table.UnmapProcessCodeMemory(dst_address, src_address, size);
@@ -1483,7 +1451,7 @@ static void ExitProcess32(Core::System& system) {
1483 ExitProcess(system); 1451 ExitProcess(system);
1484} 1452}
1485 1453
1486static constexpr bool IsValidCoreId(int32_t core_id) { 1454static constexpr bool IsValidVirtualCoreId(int32_t core_id) {
1487 return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); 1455 return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
1488} 1456}
1489 1457
@@ -1503,7 +1471,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1503 } 1471 }
1504 1472
1505 // Validate arguments. 1473 // Validate arguments.
1506 if (!IsValidCoreId(core_id)) { 1474 if (!IsValidVirtualCoreId(core_id)) {
1507 LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); 1475 LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
1508 return ResultInvalidCoreId; 1476 return ResultInvalidCoreId;
1509 } 1477 }
@@ -1521,35 +1489,42 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1521 return ResultInvalidPriority; 1489 return ResultInvalidPriority;
1522 } 1490 }
1523 1491
1492 // Reserve a new thread from the process resource limit (waiting up to 100ms).
1524 KScopedResourceReservation thread_reservation( 1493 KScopedResourceReservation thread_reservation(
1525 kernel.CurrentProcess(), LimitableResource::Threads, 1, 1494 kernel.CurrentProcess(), LimitableResource::Threads, 1,
1526 system.CoreTiming().GetGlobalTimeNs().count() + 100000000); 1495 system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
1527 if (!thread_reservation.Succeeded()) { 1496 if (!thread_reservation.Succeeded()) {
1528 LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); 1497 LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
1529 return ResultResourceLimitedExceeded; 1498 return ResultLimitReached;
1530 } 1499 }
1531 1500
1532 std::shared_ptr<KThread> thread; 1501 // Create the thread.
1533 { 1502 KThread* thread = KThread::Create(kernel);
1534 KScopedLightLock lk{process.GetStateLock()}; 1503 if (!thread) {
1535 CASCADE_RESULT(thread, 1504 LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached.");
1536 KThread::CreateUserThread(system, ThreadType::User, "", entry_point, 1505 return ResultOutOfResource;
1537 priority, arg, core_id, stack_bottom, &process));
1538 } 1506 }
1507 SCOPE_EXIT({ thread->Close(); });
1539 1508
1540 const auto new_thread_handle = process.GetHandleTable().Create(thread); 1509 // Initialize the thread.
1541 if (new_thread_handle.Failed()) { 1510 {
1542 LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", 1511 KScopedLightLock lk{process.GetStateLock()};
1543 new_thread_handle.Code().raw); 1512 R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom,
1544 return new_thread_handle.Code(); 1513 priority, core_id, &process));
1545 } 1514 }
1546 *out_handle = *new_thread_handle;
1547 1515
1548 // Set the thread name for debugging purposes. 1516 // Set the thread name for debugging purposes.
1549 thread->SetName( 1517 thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle));
1550 fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); 1518
1519 // Commit the thread reservation.
1551 thread_reservation.Commit(); 1520 thread_reservation.Commit();
1552 1521
1522 // Register the new thread.
1523 KThread::Register(kernel, thread);
1524
1525 // Add the thread to the handle table.
1526 R_TRY(process.GetHandleTable().Add(out_handle, thread));
1527
1553 return RESULT_SUCCESS; 1528 return RESULT_SUCCESS;
1554} 1529}
1555 1530
@@ -1563,21 +1538,15 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
1563 LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); 1538 LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
1564 1539
1565 // Get the thread from its handle. 1540 // Get the thread from its handle.
1566 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1541 KScopedAutoObject thread =
1567 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1542 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1568 if (!thread) { 1543 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1569 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
1570 return ResultInvalidHandle;
1571 }
1572 1544
1573 // Try to start the thread. 1545 // Try to start the thread.
1574 const auto run_result = thread->Run(); 1546 R_TRY(thread->Run());
1575 if (run_result.IsError()) { 1547
1576 LOG_ERROR(Kernel_SVC, 1548 // If we succeeded, persist a reference to the thread.
1577 "Unable to successfuly start thread (thread handle={:08X}, result={})", 1549 thread->Open();
1578 thread_handle, run_result.raw);
1579 return run_result;
1580 }
1581 1550
1582 return RESULT_SUCCESS; 1551 return RESULT_SUCCESS;
1583} 1552}
@@ -1591,7 +1560,7 @@ static void ExitThread(Core::System& system) {
1591 LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); 1560 LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
1592 1561
1593 auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); 1562 auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
1594 system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); 1563 system.GlobalSchedulerContext().RemoveThread(current_thread);
1595 current_thread->Exit(); 1564 current_thread->Exit();
1596} 1565}
1597 1566
@@ -1824,8 +1793,11 @@ static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high)
1824static ResultCode CloseHandle(Core::System& system, Handle handle) { 1793static ResultCode CloseHandle(Core::System& system, Handle handle) {
1825 LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); 1794 LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
1826 1795
1827 auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1796 // Remove the handle.
1828 return handle_table.Close(handle); 1797 R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle),
1798 ResultInvalidHandle);
1799
1800 return RESULT_SUCCESS;
1829} 1801}
1830 1802
1831static ResultCode CloseHandle32(Core::System& system, Handle handle) { 1803static ResultCode CloseHandle32(Core::System& system, Handle handle) {
@@ -1841,16 +1813,16 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) {
1841 1813
1842 // Try to reset as readable event. 1814 // Try to reset as readable event.
1843 { 1815 {
1844 auto readable_event = handle_table.Get<KReadableEvent>(handle); 1816 KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
1845 if (readable_event) { 1817 if (readable_event.IsNotNull()) {
1846 return readable_event->Reset(); 1818 return readable_event->Reset();
1847 } 1819 }
1848 } 1820 }
1849 1821
1850 // Try to reset as process. 1822 // Try to reset as process.
1851 { 1823 {
1852 auto process = handle_table.Get<Process>(handle); 1824 KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
1853 if (process) { 1825 if (process.IsNotNull()) {
1854 return process->Reset(); 1826 return process->Reset();
1855 } 1827 }
1856 } 1828 }
@@ -1864,65 +1836,68 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) {
1864 return ResetSignal(system, handle); 1836 return ResetSignal(system, handle);
1865} 1837}
1866 1838
1867/// Creates a TransferMemory object 1839static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
1868static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, 1840 switch (perm) {
1869 u32 permissions) { 1841 case MemoryPermission::None:
1870 std::lock_guard lock{HLE::g_hle_lock}; 1842 case MemoryPermission::Read:
1871 LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, 1843 case MemoryPermission::ReadWrite:
1872 permissions); 1844 return true;
1873 1845 default:
1874 if (!Common::Is4KBAligned(addr)) { 1846 return false;
1875 LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr);
1876 return ResultInvalidAddress;
1877 } 1847 }
1848}
1878 1849
1879 if (!Common::Is4KBAligned(size) || size == 0) { 1850/// Creates a TransferMemory object
1880 LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size); 1851static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
1881 return ResultInvalidAddress; 1852 MemoryPermission map_perm) {
1882 } 1853 auto& kernel = system.Kernel();
1883 1854
1884 if (!IsValidAddressRange(addr, size)) { 1855 // Validate the size.
1885 LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", 1856 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1886 addr, size); 1857 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1887 return ResultInvalidCurrentMemory; 1858 R_UNLESS(size > 0, ResultInvalidSize);
1888 } 1859 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1889 1860
1890 const auto perms{static_cast<MemoryPermission>(permissions)}; 1861 // Validate the permissions.
1891 if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) { 1862 R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
1892 LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", 1863
1893 permissions); 1864 // Get the current process and handle table.
1894 return ResultInvalidMemoryPermissions; 1865 auto& process = *kernel.CurrentProcess();
1895 } 1866 auto& handle_table = process.GetHandleTable();
1896 1867
1897 auto& kernel = system.Kernel();
1898 // Reserve a new transfer memory from the process resource limit. 1868 // Reserve a new transfer memory from the process resource limit.
1899 KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), 1869 KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
1900 LimitableResource::TransferMemory); 1870 LimitableResource::TransferMemory);
1901 if (!trmem_reservation.Succeeded()) { 1871 R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
1902 LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory");
1903 return ResultResourceLimitedExceeded;
1904 }
1905 auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size,
1906 static_cast<KMemoryPermission>(perms));
1907 1872
1908 if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { 1873 // Create the transfer memory.
1909 return reserve_result; 1874 KTransferMemory* trmem = KTransferMemory::Create(kernel);
1910 } 1875 R_UNLESS(trmem != nullptr, ResultOutOfResource);
1911 1876
1912 auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1877 // Ensure the only reference is in the handle table when we're done.
1913 const auto result{handle_table.Create(std::move(transfer_mem_handle))}; 1878 SCOPE_EXIT({ trmem->Close(); });
1914 if (result.Failed()) { 1879
1915 return result.Code(); 1880 // Ensure that the region is in range.
1916 } 1881 R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory);
1882
1883 // Initialize the transfer memory.
1884 R_TRY(trmem->Initialize(address, size, map_perm));
1885
1886 // Commit the reservation.
1917 trmem_reservation.Commit(); 1887 trmem_reservation.Commit();
1918 1888
1919 *handle = *result; 1889 // Register the transfer memory.
1890 KTransferMemory::Register(kernel, trmem);
1891
1892 // Add the transfer memory to the handle table.
1893 R_TRY(handle_table.Add(out, trmem));
1894
1920 return RESULT_SUCCESS; 1895 return RESULT_SUCCESS;
1921} 1896}
1922 1897
1923static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, 1898static ResultCode CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size,
1924 u32 permissions) { 1899 MemoryPermission map_perm) {
1925 return CreateTransferMemory(system, handle, addr, size, permissions); 1900 return CreateTransferMemory(system, out, address, size, map_perm);
1926} 1901}
1927 1902
1928static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, 1903static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
@@ -1930,19 +1905,12 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
1930 LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); 1905 LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
1931 1906
1932 // Get the thread from its handle. 1907 // Get the thread from its handle.
1933 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1908 KScopedAutoObject thread =
1934 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1909 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1935 if (!thread) { 1910 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1936 LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
1937 return ResultInvalidHandle;
1938 }
1939 1911
1940 // Get the core mask. 1912 // Get the core mask.
1941 const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); 1913 R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
1942 if (result.IsError()) {
1943 LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
1944 return result;
1945 }
1946 1914
1947 return RESULT_SUCCESS; 1915 return RESULT_SUCCESS;
1948} 1916}
@@ -1958,58 +1926,33 @@ static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle
1958 1926
1959static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, 1927static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
1960 u64 affinity_mask) { 1928 u64 affinity_mask) {
1961 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}",
1962 thread_handle, core_id, affinity_mask);
1963
1964 const auto& current_process = *system.Kernel().CurrentProcess();
1965
1966 // Determine the core id/affinity mask. 1929 // Determine the core id/affinity mask.
1967 if (core_id == Svc::IdealCoreUseProcessValue) { 1930 if (core_id == IdealCoreUseProcessValue) {
1968 core_id = current_process.GetIdealCoreId(); 1931 core_id = system.Kernel().CurrentProcess()->GetIdealCoreId();
1969 affinity_mask = (1ULL << core_id); 1932 affinity_mask = (1ULL << core_id);
1970 } else { 1933 } else {
1971 // Validate the affinity mask. 1934 // Validate the affinity mask.
1972 const u64 process_core_mask = current_process.GetCoreMask(); 1935 const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask();
1973 if ((affinity_mask | process_core_mask) != process_core_mask) { 1936 R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId);
1974 LOG_ERROR(Kernel_SVC, 1937 R_UNLESS(affinity_mask != 0, ResultInvalidCombination);
1975 "Affinity mask does match the process core mask (affinity mask={:016X}, core "
1976 "mask={:016X})",
1977 affinity_mask, process_core_mask);
1978 return ResultInvalidCoreId;
1979 }
1980 if (affinity_mask == 0) {
1981 LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
1982 return ResultInvalidCombination;
1983 }
1984 1938
1985 // Validate the core id. 1939 // Validate the core id.
1986 if (IsValidCoreId(core_id)) { 1940 if (IsValidVirtualCoreId(core_id)) {
1987 if (((1ULL << core_id) & affinity_mask) == 0) { 1941 R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
1988 LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
1989 return ResultInvalidCombination;
1990 }
1991 } else { 1942 } else {
1992 if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { 1943 R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
1993 LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); 1944 ResultInvalidCoreId);
1994 return ResultInvalidCoreId;
1995 }
1996 } 1945 }
1997 } 1946 }
1998 1947
1999 // Get the thread from its handle. 1948 // Get the thread from its handle.
2000 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1949 KScopedAutoObject thread =
2001 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1950 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
2002 if (!thread) { 1951 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
2003 LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
2004 return ResultInvalidHandle;
2005 }
2006 1952
2007 // Set the core mask. 1953 // Set the core mask.
2008 const auto set_result = thread->SetCoreMask(core_id, affinity_mask); 1954 R_TRY(thread->SetCoreMask(core_id, affinity_mask));
2009 if (set_result.IsError()) { 1955
2010 LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
2011 return set_result;
2012 }
2013 return RESULT_SUCCESS; 1956 return RESULT_SUCCESS;
2014} 1957}
2015 1958
@@ -2022,27 +1965,12 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle
2022static ResultCode SignalEvent(Core::System& system, Handle event_handle) { 1965static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
2023 LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); 1966 LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
2024 1967
2025 auto& kernel = system.Kernel();
2026 // Get the current handle table. 1968 // Get the current handle table.
2027 const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1969 const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
2028
2029 // Reserve a new event from the process resource limit.
2030 KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
2031 LimitableResource::Events);
2032 if (!event_reservation.Succeeded()) {
2033 LOG_ERROR(Kernel, "Could not reserve a new event");
2034 return ResultResourceLimitedExceeded;
2035 }
2036 1970
2037 // Get the writable event. 1971 // Get the writable event.
2038 auto writable_event = handle_table.Get<KWritableEvent>(event_handle); 1972 KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
2039 if (!writable_event) { 1973 R_UNLESS(writable_event.IsNotNull(), ResultInvalidHandle);
2040 LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
2041 return ResultInvalidHandle;
2042 }
2043
2044 // Commit the successfuly reservation.
2045 event_reservation.Commit();
2046 1974
2047 return writable_event->Signal(); 1975 return writable_event->Signal();
2048} 1976}
@@ -2059,16 +1987,16 @@ static ResultCode ClearEvent(Core::System& system, Handle event_handle) {
2059 1987
2060 // Try to clear the writable event. 1988 // Try to clear the writable event.
2061 { 1989 {
2062 auto writable_event = handle_table.Get<KWritableEvent>(event_handle); 1990 KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
2063 if (writable_event) { 1991 if (writable_event.IsNotNull()) {
2064 return writable_event->Clear(); 1992 return writable_event->Clear();
2065 } 1993 }
2066 } 1994 }
2067 1995
2068 // Try to clear the readable event. 1996 // Try to clear the readable event.
2069 { 1997 {
2070 auto readable_event = handle_table.Get<KReadableEvent>(event_handle); 1998 KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
2071 if (readable_event) { 1999 if (readable_event.IsNotNull()) {
2072 return readable_event->Clear(); 2000 return readable_event->Clear();
2073 } 2001 }
2074 } 2002 }
@@ -2087,34 +2015,40 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o
2087 2015
2088 // Get the kernel reference and handle table. 2016 // Get the kernel reference and handle table.
2089 auto& kernel = system.Kernel(); 2017 auto& kernel = system.Kernel();
2090 HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); 2018 auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
2019
2020 // Reserve a new event from the process resource limit
2021 KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
2022 LimitableResource::Events);
2023 R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
2091 2024
2092 // Create a new event. 2025 // Create a new event.
2093 const auto event = KEvent::Create(kernel, "CreateEvent"); 2026 KEvent* event = KEvent::Create(kernel);
2094 if (!event) { 2027 R_UNLESS(event != nullptr, ResultOutOfResource);
2095 LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
2096 return ResultOutOfResource;
2097 }
2098 2028
2099 // Initialize the event. 2029 // Initialize the event.
2100 event->Initialize(); 2030 event->Initialize("CreateEvent");
2031
2032 // Commit the thread reservation.
2033 event_reservation.Commit();
2034
2035 // Ensure that we clean up the event (and its only references are handle table) on function end.
2036 SCOPE_EXIT({
2037 event->GetWritableEvent().Close();
2038 event->GetReadableEvent().Close();
2039 });
2040
2041 // Register the event.
2042 KEvent::Register(kernel, event);
2101 2043
2102 // Add the writable event to the handle table. 2044 // Add the writable event to the handle table.
2103 const auto write_create_result = handle_table.Create(event->GetWritableEvent()); 2045 R_TRY(handle_table.Add(out_write, std::addressof(event->GetWritableEvent())));
2104 if (write_create_result.Failed()) {
2105 return write_create_result.Code();
2106 }
2107 *out_write = *write_create_result;
2108 2046
2109 // Add the writable event to the handle table. 2047 // Add the writable event to the handle table.
2110 auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); }); 2048 auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); });
2111 2049
2112 // Add the readable event to the handle table. 2050 // Add the readable event to the handle table.
2113 const auto read_create_result = handle_table.Create(event->GetReadableEvent()); 2051 R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent())));
2114 if (read_create_result.Failed()) {
2115 return read_create_result.Code();
2116 }
2117 *out_read = *read_create_result;
2118 2052
2119 // We succeeded. 2053 // We succeeded.
2120 handle_guard.Cancel(); 2054 handle_guard.Cancel();
@@ -2134,8 +2068,8 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
2134 }; 2068 };
2135 2069
2136 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 2070 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
2137 const auto process = handle_table.Get<Process>(process_handle); 2071 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
2138 if (!process) { 2072 if (process.IsNull()) {
2139 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", 2073 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
2140 process_handle); 2074 process_handle);
2141 return ResultInvalidHandle; 2075 return ResultInvalidHandle;
@@ -2152,83 +2086,86 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
2152} 2086}
2153 2087
2154static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { 2088static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) {
2155 std::lock_guard lock{HLE::g_hle_lock};
2156 LOG_DEBUG(Kernel_SVC, "called"); 2089 LOG_DEBUG(Kernel_SVC, "called");
2157 2090
2091 // Create a new resource limit.
2158 auto& kernel = system.Kernel(); 2092 auto& kernel = system.Kernel();
2159 auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming()); 2093 KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
2094 R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
2160 2095
2161 auto* const current_process = kernel.CurrentProcess(); 2096 // Ensure we don't leak a reference to the limit.
2162 ASSERT(current_process != nullptr); 2097 SCOPE_EXIT({ resource_limit->Close(); });
2163 2098
2164 const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); 2099 // Initialize the resource limit.
2165 if (handle.Failed()) { 2100 resource_limit->Initialize(&system.CoreTiming());
2166 return handle.Code(); 2101
2167 } 2102 // Register the limit.
2103 KResourceLimit::Register(kernel, resource_limit);
2104
2105 // Add the limit to the handle table.
2106 R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit));
2168 2107
2169 *out_handle = *handle;
2170 return RESULT_SUCCESS; 2108 return RESULT_SUCCESS;
2171} 2109}
2172 2110
2173static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value, 2111static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value,
2174 Handle resource_limit, u32 resource_type) { 2112 Handle resource_limit_handle,
2175 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); 2113 LimitableResource which) {
2114 LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
2115 which);
2176 2116
2177 const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, 2117 // Validate the resource.
2178 ResourceLimitValueType::LimitValue); 2118 R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
2179 if (limit_value.Failed()) { 2119
2180 return limit_value.Code(); 2120 // Get the resource limit.
2181 } 2121 auto& kernel = system.Kernel();
2122 KScopedAutoObject resource_limit =
2123 kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
2124 R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
2125
2126 // Get the limit value.
2127 *out_limit_value = resource_limit->GetLimitValue(which);
2182 2128
2183 *out_value = static_cast<u64>(*limit_value);
2184 return RESULT_SUCCESS; 2129 return RESULT_SUCCESS;
2185} 2130}
2186 2131
2187static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value, 2132static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value,
2188 Handle resource_limit, u32 resource_type) { 2133 Handle resource_limit_handle,
2189 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); 2134 LimitableResource which) {
2135 LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
2136 which);
2190 2137
2191 const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, 2138 // Validate the resource.
2192 ResourceLimitValueType::CurrentValue); 2139 R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
2193 if (current_value.Failed()) { 2140
2194 return current_value.Code(); 2141 // Get the resource limit.
2195 } 2142 auto& kernel = system.Kernel();
2143 KScopedAutoObject resource_limit =
2144 kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
2145 R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
2146
2147 // Get the current value.
2148 *out_current_value = resource_limit->GetCurrentValue(which);
2196 2149
2197 *out_value = static_cast<u64>(*current_value);
2198 return RESULT_SUCCESS; 2150 return RESULT_SUCCESS;
2199} 2151}
2200 2152
2201static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit, 2153static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
2202 u32 resource_type, u64 value) { 2154 LimitableResource which, u64 limit_value) {
2203 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, 2155 LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
2204 resource_type, value); 2156 resource_limit_handle, which, limit_value);
2205 2157
2206 const auto type = static_cast<LimitableResource>(resource_type); 2158 // Validate the resource.
2207 if (!IsValidResourceType(type)) { 2159 R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
2208 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
2209 return ResultInvalidEnumValue;
2210 }
2211
2212 auto* const current_process = system.Kernel().CurrentProcess();
2213 ASSERT(current_process != nullptr);
2214 2160
2215 auto resource_limit_object = 2161 // Get the resource limit.
2216 current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); 2162 auto& kernel = system.Kernel();
2217 if (!resource_limit_object) { 2163 KScopedAutoObject resource_limit =
2218 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", 2164 kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
2219 resource_limit); 2165 R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
2220 return ResultInvalidHandle;
2221 }
2222 2166
2223 const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value)); 2167 // Set the limit value.
2224 if (set_result.IsError()) { 2168 R_TRY(resource_limit->SetLimitValue(which, limit_value));
2225 LOG_ERROR(Kernel_SVC,
2226 "Attempted to lower resource limit ({}) for category '{}' below its current "
2227 "value ({})",
2228 resource_limit_object->GetLimitValue(type), resource_type,
2229 resource_limit_object->GetCurrentValue(type));
2230 return set_result;
2231 }
2232 2169
2233 return RESULT_SUCCESS; 2170 return RESULT_SUCCESS;
2234} 2171}
@@ -2351,7 +2288,7 @@ static const FunctionDef SVC_Table_32[] = {
2351 {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, 2288 {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"},
2352 {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, 2289 {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"},
2353 {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, 2290 {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"},
2354 {0x14, nullptr, "UnmapSharedMemory32"}, 2291 {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"},
2355 {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, 2292 {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"},
2356 {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, 2293 {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"},
2357 {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, 2294 {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"},
@@ -2546,7 +2483,7 @@ static const FunctionDef SVC_Table_64[] = {
2546 {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, 2483 {0x11, SvcWrap64<SignalEvent>, "SignalEvent"},
2547 {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, 2484 {0x12, SvcWrap64<ClearEvent>, "ClearEvent"},
2548 {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, 2485 {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"},
2549 {0x14, nullptr, "UnmapSharedMemory"}, 2486 {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"},
2550 {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, 2487 {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"},
2551 {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, 2488 {0x16, SvcWrap64<CloseHandle>, "CloseHandle"},
2552 {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, 2489 {0x17, SvcWrap64<ResetSignal>, "ResetSignal"},