diff options
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 903 |
1 files changed, 627 insertions, 276 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 7f5c0cc86..f9c606bc5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -32,6 +32,7 @@ #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/transfer_memory.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" #include "core/hle/result.h" @@ -130,16 +131,15 @@ enum class ResourceLimitValueType { LimitValue, }; -ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type, - ResourceLimitValueType value_type) { +ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, + u32 resource_type, ResourceLimitValueType value_type) { const auto type = static_cast<ResourceType>(resource_type); if (!IsValidResourceType(type)) { LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); return ERR_INVALID_ENUM_VALUE; } - const auto& kernel = Core::System::GetInstance().Kernel(); - const auto* const current_process = kernel.CurrentProcess(); + const auto* const current_process = system.Kernel().CurrentProcess(); ASSERT(current_process != nullptr); const auto resource_limit_object = @@ -159,7 +159,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_ty } // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. -static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { +static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) { LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB. @@ -174,11 +174,8 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { return ERR_INVALID_SIZE; } - auto& vm_manager = Core::CurrentProcess()->VMManager(); - const VAddr heap_base = vm_manager.GetHeapRegionBaseAddress(); - const auto alloc_result = - vm_manager.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite); - + auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); + const auto alloc_result = vm_manager.SetHeapSize(heap_size); if (alloc_result.Failed()) { return alloc_result.Code(); } @@ -187,7 +184,7 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { return RESULT_SUCCESS; } -static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) { +static ResultCode SetMemoryPermission(Core::System& system, VAddr addr, u64 size, u32 prot) { LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot); if (!Common::Is4KBAligned(addr)) { @@ -219,7 +216,7 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) { return ERR_INVALID_MEMORY_PERMISSIONS; } - auto* const current_process = Core::CurrentProcess(); + auto* const current_process = system.Kernel().CurrentProcess(); auto& vm_manager = current_process->VMManager(); if (!vm_manager.IsWithinAddressSpace(addr, size)) { @@ -244,7 +241,8 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) { return vm_manager.ReprotectRange(addr, size, converted_permissions); } -static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attribute) { +static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, + u32 attribute) { LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, size, mask, attribute); @@ -282,7 +280,7 @@ static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attr return ERR_INVALID_COMBINATION; } - auto& vm_manager = Core::CurrentProcess()->VMManager(); + auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); if (!vm_manager.IsWithinAddressSpace(address, size)) { LOG_ERROR(Kernel_SVC, "Given address (0x{:016X}) is outside the bounds of the address space.", address); @@ -293,11 +291,11 @@ static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attr } /// Maps a memory range into a different range. -static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { +static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - auto& vm_manager = Core::CurrentProcess()->VMManager(); + auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); if (result.IsError()) { @@ -308,11 +306,11 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { } /// Unmaps a region that was previously mapped with svcMapMemory -static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { +static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - auto& vm_manager = Core::CurrentProcess()->VMManager(); + auto& vm_manager = system.Kernel().CurrentProcess()->VMManager(); const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); if (result.IsError()) { @@ -323,7 +321,8 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { } /// Connect to an OS service given the port name, returns the handle to the port to out -static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { +static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, + VAddr port_name_address) { if (!Memory::IsValidVirtualAddress(port_name_address)) { LOG_ERROR(Kernel_SVC, "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", @@ -342,8 +341,8 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); - auto& kernel = Core::System::GetInstance().Kernel(); - auto it = kernel.FindNamedPort(port_name); + auto& kernel = system.Kernel(); + const auto it = kernel.FindNamedPort(port_name); if (!kernel.IsValidNamedPort(it)) { LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); return ERR_NOT_FOUND; @@ -355,14 +354,14 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session - auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); return RESULT_SUCCESS; } /// Makes a blocking IPC call to an OS service. -static ResultCode SendSyncRequest(Handle handle) { - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); +static ResultCode SendSyncRequest(Core::System& system, Handle handle) { + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle); if (!session) { LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); @@ -371,18 +370,18 @@ static ResultCode SendSyncRequest(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server // responds and cause a reschedule. - return session->SendSyncRequest(GetCurrentThread()); + return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread()); } /// Get the ID for the specified thread. -static ResultCode GetThreadId(u64* thread_id, Handle thread_handle) { +static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); @@ -394,10 +393,10 @@ static ResultCode GetThreadId(u64* thread_id, Handle thread_handle) { } /// Gets the ID of the specified process or a specified thread's owning process. -static ResultCode GetProcessId(u64* process_id, Handle handle) { +static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const SharedPtr<Process> process = handle_table.Get<Process>(handle); if (process) { *process_id = process->GetProcessID(); @@ -425,7 +424,7 @@ static ResultCode GetProcessId(u64* process_id, Handle handle) { /// Default thread wakeup callback for WaitSynchronization static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, SharedPtr<WaitObject> object, std::size_t index) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); if (reason == ThreadWakeupReason::Timeout) { thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); @@ -439,8 +438,8 @@ static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thr }; /// Wait for the given handles to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count, - s64 nano_seconds) { +static ResultCode WaitSynchronization(Core::System& system, Handle* 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); @@ -459,11 +458,11 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 return ERR_OUT_OF_RANGE; } - auto* const thread = GetCurrentThread(); + auto* const thread = system.CurrentScheduler().GetCurrentThread(); using ObjectPtr = Thread::ThreadWaitObjects::value_type; Thread::ThreadWaitObjects objects(handle_count); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); for (u64 i = 0; i < handle_count; ++i) { const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); @@ -503,38 +502,36 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 } thread->SetWaitObjects(std::move(objects)); - thread->SetStatus(ThreadStatus::WaitSynchAny); + thread->SetStatus(ThreadStatus::WaitSynch); // Create an event to wake the thread up after the specified nanosecond delay has passed thread->WakeAfterDelay(nano_seconds); thread->SetWakeupCallback(DefaultThreadWakeupCallback); - Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); return RESULT_TIMEOUT; } /// Resumes a thread waiting on WaitSynchronization -static ResultCode CancelSynchronization(Handle thread_handle) { +static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); return ERR_INVALID_HANDLE; } - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); - thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); - thread->ResumeFromWait(); + thread->CancelWait(); return RESULT_SUCCESS; } /// Attempts to locks a mutex, creating it if it does not already exist -static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, - Handle requesting_thread_handle) { +static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_handle, + VAddr mutex_addr, Handle requesting_thread_handle) { LOG_TRACE(Kernel_SVC, "called holding_thread_handle=0x{:08X}, mutex_addr=0x{:X}, " "requesting_current_thread_handle=0x{:08X}", @@ -551,13 +548,13 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, return ERR_INVALID_ADDRESS; } - auto& handle_table = Core::CurrentProcess()->GetHandleTable(); - return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, - requesting_thread_handle); + auto* const current_process = system.Kernel().CurrentProcess(); + return current_process->GetMutex().TryAcquire(mutex_addr, holding_thread_handle, + requesting_thread_handle); } /// Unlock a mutex -static ResultCode ArbitrateUnlock(VAddr mutex_addr) { +static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); if (Memory::IsKernelVirtualAddress(mutex_addr)) { @@ -571,7 +568,8 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) { return ERR_INVALID_ADDRESS; } - return Mutex::Release(mutex_addr); + auto* const current_process = system.Kernel().CurrentProcess(); + return current_process->GetMutex().Release(mutex_addr); } enum class BreakType : u32 { @@ -593,7 +591,7 @@ struct BreakReason { }; /// Break program execution -static void Break(u32 reason, u64 info1, u64 info2) { +static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { BreakReason break_reason{reason}; bool has_dumped_buffer{}; @@ -671,22 +669,24 @@ static void Break(u32 reason, u64 info1, u64 info2) { Debug_Emulated, "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", reason, info1, info2); + handle_debug_buffer(info1, info2); - Core::System::GetInstance() - .ArmInterface(static_cast<std::size_t>(GetCurrentThread()->GetProcessorID())) - .LogBacktrace(); + + auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); + const auto thread_processor_id = current_thread->GetProcessorID(); + system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); ASSERT(false); - Core::CurrentProcess()->PrepareForTermination(); + system.Kernel().CurrentProcess()->PrepareForTermination(); // Kill the current thread - GetCurrentThread()->Stop(); - Core::System::GetInstance().PrepareReschedule(); + current_thread->Stop(); + system.PrepareReschedule(); } } /// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString(VAddr address, u64 len) { +static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { if (len == 0) { return; } @@ -697,7 +697,8 @@ static void OutputDebugString(VAddr address, u64 len) { } /// Gets system/memory information for the current process -static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) { +static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, + u64 info_sub_id) { LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, info_sub_id, handle); @@ -709,13 +710,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) MapRegionSize = 3, HeapRegionBaseAddr = 4, HeapRegionSize = 5, - TotalMemoryUsage = 6, - TotalHeapUsage = 7, + TotalPhysicalMemoryAvailable = 6, + TotalPhysicalMemoryUsed = 7, IsCurrentProcessBeingDebugged = 8, RegisterResourceLimit = 9, IdleTickCount = 10, RandomEntropy = 11, - PerformanceCounter = 0xF0000002, + ThreadTickCount = 0xF0000002, // 2.0.0+ ASLRRegionBaseAddr = 12, ASLRRegionSize = 13, @@ -729,7 +730,9 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) PrivilegedProcessId = 19, // 5.0.0+ UserExceptionContextAddr = 20, - ThreadTickCount = 0xF0000002, + // 6.0.0+ + TotalPhysicalMemoryAvailableWithoutMmHeap = 21, + TotalPhysicalMemoryUsedWithoutMmHeap = 22, }; const auto info_id_type = static_cast<GetInfoType>(info_id); @@ -745,17 +748,20 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) case GetInfoType::ASLRRegionSize: case GetInfoType::NewMapRegionBaseAddr: case GetInfoType::NewMapRegionSize: - case GetInfoType::TotalMemoryUsage: - case GetInfoType::TotalHeapUsage: + case GetInfoType::TotalPhysicalMemoryAvailable: + case GetInfoType::TotalPhysicalMemoryUsed: case GetInfoType::IsVirtualAddressMemoryEnabled: case GetInfoType::PersonalMmHeapUsage: case GetInfoType::TitleId: - case GetInfoType::UserExceptionContextAddr: { + case GetInfoType::UserExceptionContextAddr: + case GetInfoType::TotalPhysicalMemoryAvailableWithoutMmHeap: + case GetInfoType::TotalPhysicalMemoryUsedWithoutMmHeap: { if (info_sub_id != 0) { return ERR_INVALID_ENUM_VALUE; } - const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& current_process_handle_table = + system.Kernel().CurrentProcess()->GetHandleTable(); const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle)); if (!process) { return ERR_INVALID_HANDLE; @@ -802,12 +808,12 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) *result = process->VMManager().GetNewMapRegionSize(); return RESULT_SUCCESS; - case GetInfoType::TotalMemoryUsage: - *result = process->VMManager().GetTotalMemoryUsage(); + case GetInfoType::TotalPhysicalMemoryAvailable: + *result = process->GetTotalPhysicalMemoryAvailable(); return RESULT_SUCCESS; - case GetInfoType::TotalHeapUsage: - *result = process->VMManager().GetTotalHeapUsage(); + case GetInfoType::TotalPhysicalMemoryUsed: + *result = process->GetTotalPhysicalMemoryUsed(); return RESULT_SUCCESS; case GetInfoType::IsVirtualAddressMemoryEnabled: @@ -824,6 +830,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) *result = 0; return RESULT_SUCCESS; + case GetInfoType::TotalPhysicalMemoryAvailableWithoutMmHeap: + *result = process->GetTotalPhysicalMemoryAvailable(); + return RESULT_SUCCESS; + + case GetInfoType::TotalPhysicalMemoryUsedWithoutMmHeap: + *result = process->GetTotalPhysicalMemoryUsedWithoutMmHeap(); + return RESULT_SUCCESS; + default: break; } @@ -845,7 +859,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) return ERR_INVALID_COMBINATION; } - Process* const current_process = Core::CurrentProcess(); + Process* const current_process = system.Kernel().CurrentProcess(); HandleTable& handle_table = current_process->GetHandleTable(); const auto resource_limit = current_process->GetResourceLimit(); if (!resource_limit) { @@ -876,7 +890,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) return ERR_INVALID_COMBINATION; } - *result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id); + *result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id); return RESULT_SUCCESS; case GetInfoType::PrivilegedProcessId: @@ -893,15 +907,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) return ERR_INVALID_COMBINATION; } - const auto thread = - Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); + const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<Thread>( + static_cast<Handle>(handle)); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", static_cast<Handle>(handle)); return ERR_INVALID_HANDLE; } - const auto& system = Core::System::GetInstance(); const auto& core_timing = system.CoreTiming(); const auto& scheduler = system.CurrentScheduler(); const auto* const current_thread = scheduler.GetCurrentThread(); @@ -928,13 +941,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) } /// Sets the thread activity -static ResultCode SetThreadActivity(Handle handle, u32 activity) { +static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); if (activity > static_cast<u32>(ThreadActivity::Paused)) { return ERR_INVALID_ENUM_VALUE; } - const auto* current_process = Core::CurrentProcess(); + const auto* current_process = system.Kernel().CurrentProcess(); const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); @@ -951,7 +964,7 @@ static ResultCode SetThreadActivity(Handle handle, u32 activity) { return ERR_INVALID_HANDLE; } - if (thread == GetCurrentThread()) { + if (thread == system.CurrentScheduler().GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); return ERR_BUSY; } @@ -961,10 +974,10 @@ static ResultCode SetThreadActivity(Handle handle, u32 activity) { } /// Gets the thread context -static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { +static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); - const auto* current_process = Core::CurrentProcess(); + const auto* current_process = system.Kernel().CurrentProcess(); const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); @@ -981,7 +994,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { return ERR_INVALID_HANDLE; } - if (thread == GetCurrentThread()) { + if (thread == system.CurrentScheduler().GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); return ERR_BUSY; } @@ -1002,10 +1015,10 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { } /// Gets the priority for the specified thread -static ResultCode GetThreadPriority(u32* priority, Handle handle) { +static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { LOG_TRACE(Kernel_SVC, "called"); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); @@ -1017,7 +1030,7 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) { } /// Sets the priority for the specified thread -static ResultCode SetThreadPriority(Handle handle, u32 priority) { +static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { LOG_TRACE(Kernel_SVC, "called"); if (priority > THREADPRIO_LOWEST) { @@ -1028,7 +1041,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { return ERR_INVALID_THREAD_PRIORITY; } - const auto* const current_process = Core::CurrentProcess(); + const auto* const current_process = system.Kernel().CurrentProcess(); SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { @@ -1038,18 +1051,18 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { thread->SetPriority(priority); - Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); return RESULT_SUCCESS; } /// Get which CPU core is executing the current thread -static u32 GetCurrentProcessorNumber() { +static u32 GetCurrentProcessorNumber(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); - return GetCurrentThread()->GetProcessorID(); + return system.CurrentScheduler().GetCurrentThread()->GetProcessorID(); } -static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, - u32 permissions) { +static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, + u64 size, u32 permissions) { LOG_TRACE(Kernel_SVC, "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", shared_memory_handle, addr, size, permissions); @@ -1083,7 +1096,7 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s return ERR_INVALID_MEMORY_PERMISSIONS; } - auto* const current_process = Core::CurrentProcess(); + auto* const current_process = system.Kernel().CurrentProcess(); auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); if (!shared_memory) { LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", @@ -1101,7 +1114,8 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s return shared_memory->Map(*current_process, addr, permissions_type, MemoryPermission::DontCare); } -static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { +static ResultCode UnmapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, + u64 size) { LOG_WARNING(Kernel_SVC, "called, shared_memory_handle=0x{:08X}, addr=0x{:X}, size=0x{:X}", shared_memory_handle, addr, size); @@ -1126,7 +1140,7 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 return ERR_INVALID_ADDRESS_STATE; } - auto* const current_process = Core::CurrentProcess(); + auto* const current_process = system.Kernel().CurrentProcess(); auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); if (!shared_memory) { LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", @@ -1141,13 +1155,14 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 return ERR_INVALID_MEMORY_RANGE; } - return shared_memory->Unmap(*current_process, addr); + return shared_memory->Unmap(*current_process, addr, size); } -static ResultCode QueryProcessMemory(VAddr memory_info_address, VAddr page_info_address, - Handle process_handle, VAddr address) { +static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, + VAddr page_info_address, Handle process_handle, + VAddr address) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); SharedPtr<Process> process = handle_table.Get<Process>(process_handle); if (!process) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", @@ -1173,20 +1188,156 @@ static ResultCode QueryProcessMemory(VAddr memory_info_address, VAddr page_info_ return RESULT_SUCCESS; } -static ResultCode QueryMemory(VAddr memory_info_address, VAddr page_info_address, - VAddr query_address) { +static ResultCode QueryMemory(Core::System& system, VAddr memory_info_address, + VAddr page_info_address, VAddr query_address) { LOG_TRACE(Kernel_SVC, "called, memory_info_address=0x{:016X}, page_info_address=0x{:016X}, " "query_address=0x{:016X}", memory_info_address, page_info_address, query_address); - return QueryProcessMemory(memory_info_address, page_info_address, CurrentProcess, + return QueryProcessMemory(system, memory_info_address, page_info_address, CurrentProcess, query_address); } +static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address, + u64 src_address, u64 size) { + LOG_DEBUG(Kernel_SVC, + "called. process_handle=0x{:08X}, dst_address=0x{:016X}, " + "src_address=0x{:016X}, size=0x{:016X}", + process_handle, dst_address, src_address, size); + + if (!Common::Is4KBAligned(src_address)) { + LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", + src_address); + return ERR_INVALID_ADDRESS; + } + + if (!Common::Is4KBAligned(dst_address)) { + LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", + dst_address); + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size); + return ERR_INVALID_SIZE; + } + + if (!IsValidAddressRange(dst_address, size)) { + LOG_ERROR(Kernel_SVC, + "Destination address range overflows the address space (dst_address=0x{:016X}, " + "size=0x{:016X}).", + dst_address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsValidAddressRange(src_address, size)) { + LOG_ERROR(Kernel_SVC, + "Source address range overflows the address space (src_address=0x{:016X}, " + "size=0x{:016X}).", + src_address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + auto process = handle_table.Get<Process>(process_handle); + if (!process) { + LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", + process_handle); + return ERR_INVALID_HANDLE; + } + + auto& vm_manager = process->VMManager(); + if (!vm_manager.IsWithinAddressSpace(src_address, size)) { + LOG_ERROR(Kernel_SVC, + "Source address range is not within the address space (src_address=0x{:016X}, " + "size=0x{:016X}).", + src_address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + if (!vm_manager.IsWithinASLRRegion(dst_address, size)) { + LOG_ERROR(Kernel_SVC, + "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " + "size=0x{:016X}).", + dst_address, size); + return ERR_INVALID_MEMORY_RANGE; + } + + return vm_manager.MapCodeMemory(dst_address, src_address, size); +} + +static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, + u64 dst_address, u64 src_address, u64 size) { + LOG_DEBUG(Kernel_SVC, + "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, " + "size=0x{:016X}", + process_handle, dst_address, src_address, size); + + if (!Common::Is4KBAligned(dst_address)) { + LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", + dst_address); + return ERR_INVALID_ADDRESS; + } + + if (!Common::Is4KBAligned(src_address)) { + LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", + src_address); + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size); + return ERR_INVALID_SIZE; + } + + if (!IsValidAddressRange(dst_address, size)) { + LOG_ERROR(Kernel_SVC, + "Destination address range overflows the address space (dst_address=0x{:016X}, " + "size=0x{:016X}).", + dst_address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsValidAddressRange(src_address, size)) { + LOG_ERROR(Kernel_SVC, + "Source address range overflows the address space (src_address=0x{:016X}, " + "size=0x{:016X}).", + src_address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + auto process = handle_table.Get<Process>(process_handle); + if (!process) { + LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", + process_handle); + return ERR_INVALID_HANDLE; + } + + auto& vm_manager = process->VMManager(); + if (!vm_manager.IsWithinAddressSpace(src_address, size)) { + LOG_ERROR(Kernel_SVC, + "Source address range is not within the address space (src_address=0x{:016X}, " + "size=0x{:016X}).", + src_address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + if (!vm_manager.IsWithinASLRRegion(dst_address, size)) { + LOG_ERROR(Kernel_SVC, + "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " + "size=0x{:016X}).", + dst_address, size); + return ERR_INVALID_MEMORY_RANGE; + } + + return vm_manager.UnmapCodeMemory(dst_address, src_address, size); +} + /// Exits the current process -static void ExitProcess() { - auto* current_process = Core::CurrentProcess(); +static void ExitProcess(Core::System& system) { + auto* current_process = system.Kernel().CurrentProcess(); LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running, @@ -1195,20 +1346,20 @@ static void ExitProcess() { current_process->PrepareForTermination(); // Kill the current thread - GetCurrentThread()->Stop(); + system.CurrentScheduler().GetCurrentThread()->Stop(); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); } /// Creates a new thread -static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, - u32 priority, s32 processor_id) { - LOG_TRACE(Kernel_SVC, +static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, + VAddr stack_top, u32 priority, s32 processor_id) { + LOG_DEBUG(Kernel_SVC, "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, " "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", entry_point, arg, stack_top, priority, processor_id, *out_handle); - auto* const current_process = Core::CurrentProcess(); + auto* const current_process = system.Kernel().CurrentProcess(); if (processor_id == THREADPROCESSORID_IDEAL) { // Set the target CPU to the one specified by the process. @@ -1239,31 +1390,33 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V return ERR_INVALID_THREAD_PRIORITY; } - const std::string name = fmt::format("thread-{:X}", entry_point); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); CASCADE_RESULT(SharedPtr<Thread> thread, - Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top, + Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top, *current_process)); - const auto new_guest_handle = current_process->GetHandleTable().Create(thread); - if (new_guest_handle.Failed()) { + const auto new_thread_handle = current_process->GetHandleTable().Create(thread); + if (new_thread_handle.Failed()) { LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", - new_guest_handle.Code().raw); - return new_guest_handle.Code(); + new_thread_handle.Code().raw); + return new_thread_handle.Code(); } - thread->SetGuestHandle(*new_guest_handle); - *out_handle = *new_guest_handle; + *out_handle = *new_thread_handle; + + // Set the thread name for debugging purposes. + thread->SetName( + fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); - Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); return RESULT_SUCCESS; } /// Starts the thread for the provided handle -static ResultCode StartThread(Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); +static ResultCode StartThread(Core::System& system, Handle thread_handle) { + LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", @@ -1276,23 +1429,25 @@ static ResultCode StartThread(Handle thread_handle) { thread->ResumeFromWait(); if (thread->GetStatus() == ThreadStatus::Ready) { - Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); } return RESULT_SUCCESS; } /// Called when a thread exits -static void ExitThread() { - LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC()); +static void ExitThread(Core::System& system) { + LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); - ExitCurrentThread(); - Core::System::GetInstance().PrepareReschedule(); + auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); + current_thread->Stop(); + system.CurrentScheduler().RemoveThread(current_thread); + system.PrepareReschedule(); } /// Sleep the current thread -static void SleepThread(s64 nanoseconds) { - LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); +static void SleepThread(Core::System& system, s64 nanoseconds) { + LOG_DEBUG(Kernel_SVC, "called nanoseconds={}", nanoseconds); enum class SleepType : s64 { YieldWithoutLoadBalancing = 0, @@ -1300,72 +1455,91 @@ static void SleepThread(s64 nanoseconds) { YieldAndWaitForLoadBalancing = -2, }; + auto& scheduler = system.CurrentScheduler(); + auto* const current_thread = scheduler.GetCurrentThread(); + if (nanoseconds <= 0) { - auto& scheduler{Core::System::GetInstance().CurrentScheduler()}; switch (static_cast<SleepType>(nanoseconds)) { case SleepType::YieldWithoutLoadBalancing: - scheduler.YieldWithoutLoadBalancing(GetCurrentThread()); + scheduler.YieldWithoutLoadBalancing(current_thread); break; case SleepType::YieldWithLoadBalancing: - scheduler.YieldWithLoadBalancing(GetCurrentThread()); + scheduler.YieldWithLoadBalancing(current_thread); break; case SleepType::YieldAndWaitForLoadBalancing: - scheduler.YieldAndWaitForLoadBalancing(GetCurrentThread()); + scheduler.YieldAndWaitForLoadBalancing(current_thread); break; default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); } } else { - // Sleep current thread and check for next thread to schedule - WaitCurrentThread_Sleep(); - - // Create an event to wake the thread up after the specified nanosecond delay has passed - GetCurrentThread()->WakeAfterDelay(nanoseconds); + current_thread->Sleep(nanoseconds); } // Reschedule all CPU cores - for (std::size_t i = 0; i < Core::NUM_CPU_CORES; ++i) - Core::System::GetInstance().CpuCore(i).PrepareReschedule(); + for (std::size_t i = 0; i < Core::NUM_CPU_CORES; ++i) { + system.CpuCore(i).PrepareReschedule(); + } } /// Wait process wide key atomic -static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, - Handle thread_handle, s64 nano_seconds) { +static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_addr, + VAddr condition_variable_addr, Handle thread_handle, + s64 nano_seconds) { LOG_TRACE( Kernel_SVC, "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", mutex_addr, condition_variable_addr, thread_handle, nano_seconds); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + if (Memory::IsKernelVirtualAddress(mutex_addr)) { + LOG_ERROR( + Kernel_SVC, + "Given mutex address must not be within the kernel address space. address=0x{:016X}", + mutex_addr); + return ERR_INVALID_ADDRESS_STATE; + } + + if (!Common::IsWordAligned(mutex_addr)) { + LOG_ERROR(Kernel_SVC, "Given mutex address must be word-aligned. address=0x{:016X}", + mutex_addr); + return ERR_INVALID_ADDRESS; + } + + auto* const current_process = system.Kernel().CurrentProcess(); + const auto& handle_table = current_process->GetHandleTable(); SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); ASSERT(thread); - CASCADE_CODE(Mutex::Release(mutex_addr)); + const auto release_result = current_process->GetMutex().Release(mutex_addr); + if (release_result.IsError()) { + return release_result; + } - SharedPtr<Thread> current_thread = GetCurrentThread(); + SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->SetCondVarWaitAddress(condition_variable_addr); current_thread->SetMutexWaitAddress(mutex_addr); current_thread->SetWaitHandle(thread_handle); - current_thread->SetStatus(ThreadStatus::WaitMutex); + current_thread->SetStatus(ThreadStatus::WaitCondVar); current_thread->InvalidateWakeupCallback(); current_thread->WakeAfterDelay(nano_seconds); // Note: Deliberately don't attempt to inherit the lock owner's priority. - Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); + system.CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); return RESULT_SUCCESS; } /// Signal process wide key -static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) { +static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_variable_addr, + s32 target) { LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", condition_variable_addr, target); - const auto RetrieveWaitingThreads = [](std::size_t core_index, - std::vector<SharedPtr<Thread>>& waiting_threads, - VAddr condvar_addr) { - const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); + const auto RetrieveWaitingThreads = [&system](std::size_t core_index, + std::vector<SharedPtr<Thread>>& waiting_threads, + VAddr condvar_addr) { + const auto& scheduler = system.Scheduler(core_index); const auto& thread_list = scheduler.GetThreadList(); for (const auto& thread : thread_list) { @@ -1390,10 +1564,10 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target // them all. std::size_t last = waiting_threads.size(); if (target != -1) - last = target; + last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); // If there are no threads waiting on this condition variable, just exit - if (last > waiting_threads.size()) + if (last == 0) return RESULT_SUCCESS; for (std::size_t index = 0; index < last; ++index) { @@ -1401,9 +1575,11 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); - std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex(); + // liberate Cond Var Thread. + thread->SetCondVarWaitAddress(0); - auto& monitor = Core::System::GetInstance().Monitor(); + const std::size_t current_core = system.CurrentCoreIndex(); + auto& monitor = system.Monitor(); // Atomically read the value of the mutex. u32 mutex_val = 0; @@ -1419,10 +1595,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target } } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(), thread->GetWaitHandle())); - if (mutex_val == 0) { // We were able to acquire the mutex, resume this thread. - ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); + ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); thread->ResumeFromWait(); auto* const lock_owner = thread->GetLockOwner(); @@ -1432,8 +1607,8 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target thread->SetLockOwner(nullptr); thread->SetMutexWaitAddress(0); - thread->SetCondVarWaitAddress(0); thread->SetWaitHandle(0); + system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); } else { // Atomically signal that the mutex now has a waiting thread. do { @@ -1449,15 +1624,14 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto owner = handle_table.Get<Thread>(owner_handle); ASSERT(owner); - ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); + ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); thread->InvalidateWakeupCallback(); + thread->SetStatus(ThreadStatus::WaitMutex); owner->AddMutexWaiter(thread); - - Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); } } @@ -1465,75 +1639,56 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target } // Wait for an address (via Address Arbiter) -static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) { +static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, s32 value, + s64 timeout) { LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address, type, value, timeout); + // If the passed address is a kernel virtual address, return invalid memory state. if (Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); return ERR_INVALID_ADDRESS_STATE; } + // If the address is not properly aligned to 4 bytes, return invalid address. if (!Common::IsWordAligned(address)) { LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address); return ERR_INVALID_ADDRESS; } - auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); - switch (static_cast<AddressArbiter::ArbitrationType>(type)) { - case AddressArbiter::ArbitrationType::WaitIfLessThan: - return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false); - case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: - return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true); - case AddressArbiter::ArbitrationType::WaitIfEqual: - return address_arbiter.WaitForAddressIfEqual(address, value, timeout); - default: - LOG_ERROR(Kernel_SVC, - "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " - "or WaitIfEqual but got {}", - type); - return ERR_INVALID_ENUM_VALUE; - } + const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type); + auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); + return address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); } // Signals to an address (via Address Arbiter) -static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) { +static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value, + s32 num_to_wake) { LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address, type, value, num_to_wake); + // If the passed address is a kernel virtual address, return invalid memory state. if (Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); return ERR_INVALID_ADDRESS_STATE; } + // If the address is not properly aligned to 4 bytes, return invalid address. if (!Common::IsWordAligned(address)) { LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address); return ERR_INVALID_ADDRESS; } - auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter(); - switch (static_cast<AddressArbiter::SignalType>(type)) { - case AddressArbiter::SignalType::Signal: - return address_arbiter.SignalToAddress(address, num_to_wake); - case AddressArbiter::SignalType::IncrementAndSignalIfEqual: - return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); - case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: - return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, - num_to_wake); - default: - LOG_ERROR(Kernel_SVC, - "Invalid signal type, expected Signal, IncrementAndSignalIfEqual " - "or ModifyByWaitingCountAndSignalIfEqual but got {}", - type); - return ERR_INVALID_ENUM_VALUE; - } + const auto signal_type = static_cast<AddressArbiter::SignalType>(type); + auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); + return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake); } /// This returns the total CPU ticks elapsed since the CPU was powered-on -static u64 GetSystemTick() { +static u64 GetSystemTick(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); - auto& core_timing = Core::System::GetInstance().CoreTiming(); + auto& core_timing = system.CoreTiming(); const u64 result{core_timing.GetTicks()}; // Advance time to defeat dumb games that busy-wait for the frame to end. @@ -1543,18 +1698,18 @@ static u64 GetSystemTick() { } /// Close a handle -static ResultCode CloseHandle(Handle handle) { +static ResultCode CloseHandle(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); - auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); return handle_table.Close(handle); } /// Clears the signaled state of an event or process. -static ResultCode ResetSignal(Handle handle) { +static ResultCode ResetSignal(Core::System& system, Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto event = handle_table.Get<ReadableEvent>(handle); if (event) { @@ -1571,7 +1726,8 @@ static ResultCode ResetSignal(Handle handle) { } /// Creates a TransferMemory object -static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { +static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, + u32 permissions) { LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, permissions); @@ -1599,19 +1755,129 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 return ERR_INVALID_MEMORY_PERMISSIONS; } - auto& kernel = Core::System::GetInstance().Kernel(); - auto process = kernel.CurrentProcess(); - auto& handle_table = process->GetHandleTable(); - const auto shared_mem_handle = SharedMemory::Create(kernel, process, size, perms, perms, addr); + auto& kernel = system.Kernel(); + auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms); - CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); + auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + const auto result = handle_table.Create(std::move(transfer_mem_handle)); + if (result.Failed()) { + return result.Code(); + } + + *handle = *result; return RESULT_SUCCESS; } -static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) { +static ResultCode MapTransferMemory(Core::System& system, Handle handle, VAddr address, u64 size, + u32 permission_raw) { + LOG_DEBUG(Kernel_SVC, + "called. handle=0x{:08X}, address=0x{:016X}, size=0x{:016X}, permissions=0x{:08X}", + handle, address, size, permission_raw); + + if (!Common::Is4KBAligned(address)) { + LOG_ERROR(Kernel_SVC, "Transfer memory addresses must be 4KB aligned (size=0x{:016X}).", + address); + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, + "Transfer memory sizes must be 4KB aligned and not be zero (size=0x{:016X}).", + size); + return ERR_INVALID_SIZE; + } + + if (!IsValidAddressRange(address, size)) { + LOG_ERROR(Kernel_SVC, + "Given address and size overflows the 64-bit range (address=0x{:016X}, " + "size=0x{:016X}).", + address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto permissions = static_cast<MemoryPermission>(permission_raw); + if (permissions != MemoryPermission::None && permissions != MemoryPermission::Read && + permissions != MemoryPermission::ReadWrite) { + LOG_ERROR(Kernel_SVC, "Invalid transfer memory permissions given (permissions=0x{:08X}).", + permission_raw); + return ERR_INVALID_STATE; + } + + const auto& kernel = system.Kernel(); + const auto* const current_process = kernel.CurrentProcess(); + const auto& handle_table = current_process->GetHandleTable(); + + auto transfer_memory = handle_table.Get<TransferMemory>(handle); + if (!transfer_memory) { + LOG_ERROR(Kernel_SVC, "Nonexistent transfer memory handle given (handle=0x{:08X}).", + handle); + return ERR_INVALID_HANDLE; + } + + if (!current_process->VMManager().IsWithinASLRRegion(address, size)) { + LOG_ERROR(Kernel_SVC, + "Given address and size don't fully fit within the ASLR region " + "(address=0x{:016X}, size=0x{:016X}).", + address, size); + return ERR_INVALID_MEMORY_RANGE; + } + + return transfer_memory->MapMemory(address, size, permissions); +} + +static ResultCode UnmapTransferMemory(Core::System& system, Handle handle, VAddr address, + u64 size) { + LOG_DEBUG(Kernel_SVC, "called. handle=0x{:08X}, address=0x{:016X}, size=0x{:016X}", handle, + address, size); + + if (!Common::Is4KBAligned(address)) { + LOG_ERROR(Kernel_SVC, "Transfer memory addresses must be 4KB aligned (size=0x{:016X}).", + address); + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, + "Transfer memory sizes must be 4KB aligned and not be zero (size=0x{:016X}).", + size); + return ERR_INVALID_SIZE; + } + + if (!IsValidAddressRange(address, size)) { + LOG_ERROR(Kernel_SVC, + "Given address and size overflows the 64-bit range (address=0x{:016X}, " + "size=0x{:016X}).", + address, size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto& kernel = system.Kernel(); + const auto* const current_process = kernel.CurrentProcess(); + const auto& handle_table = current_process->GetHandleTable(); + + auto transfer_memory = handle_table.Get<TransferMemory>(handle); + if (!transfer_memory) { + LOG_ERROR(Kernel_SVC, "Nonexistent transfer memory handle given (handle=0x{:08X}).", + handle); + return ERR_INVALID_HANDLE; + } + + if (!current_process->VMManager().IsWithinASLRRegion(address, size)) { + LOG_ERROR(Kernel_SVC, + "Given address and size don't fully fit within the ASLR region " + "(address=0x{:016X}, size=0x{:016X}).", + address, size); + return ERR_INVALID_MEMORY_RANGE; + } + + return transfer_memory->UnmapMemory(address, size); +} + +static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, + u64* mask) { LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", @@ -1625,57 +1891,65 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) return RESULT_SUCCESS; } -static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle, - mask, core); +static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, + u64 affinity_mask) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", + thread_handle, core, affinity_mask); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", - thread_handle); - return ERR_INVALID_HANDLE; - } + const auto* const current_process = system.Kernel().CurrentProcess(); if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) { - const u8 ideal_cpu_core = thread->GetOwnerProcess()->GetIdealCore(); + const u8 ideal_cpu_core = current_process->GetIdealCore(); ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL)); // Set the target CPU to the ideal core specified by the process. core = ideal_cpu_core; - mask = 1ULL << core; - } - - if (mask == 0) { - LOG_ERROR(Kernel_SVC, "Mask is 0"); - return ERR_INVALID_COMBINATION; - } + affinity_mask = 1ULL << core; + } else { + const u64 core_mask = current_process->GetCoreMask(); + + if ((core_mask | affinity_mask) != core_mask) { + LOG_ERROR( + Kernel_SVC, + "Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})", + core_mask, affinity_mask); + return ERR_INVALID_PROCESSOR_ID; + } - /// This value is used to only change the affinity mask without changing the current ideal core. - static constexpr u32 OnlyChangeMask = static_cast<u32>(-3); + if (affinity_mask == 0) { + LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero."); + return ERR_INVALID_COMBINATION; + } - if (core == OnlyChangeMask) { - core = thread->GetIdealCore(); - } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) { - LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core); - return ERR_INVALID_PROCESSOR_ID; + if (core < Core::NUM_CPU_CORES) { + if ((affinity_mask & (1ULL << core)) == 0) { + LOG_ERROR(Kernel_SVC, + "Core is not enabled for the current mask, core={}, mask={:016X}", core, + affinity_mask); + return ERR_INVALID_COMBINATION; + } + } else if (core != static_cast<u32>(THREADPROCESSORID_DONT_CARE) && + core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) { + LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core); + return ERR_INVALID_PROCESSOR_ID; + } } - // Error out if the input core isn't enabled in the input mask. - if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { - LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}", - core, mask); - return ERR_INVALID_COMBINATION; + const auto& handle_table = current_process->GetHandleTable(); + const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", + thread_handle); + return ERR_INVALID_HANDLE; } - thread->ChangeCore(core, mask); - + thread->ChangeCore(core, affinity_mask); return RESULT_SUCCESS; } -static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions, - u32 remote_permissions) { +static ResultCode CreateSharedMemory(Core::System& system, Handle* handle, u64 size, + u32 local_permissions, u32 remote_permissions) { LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, local_permissions, remote_permissions); if (size == 0) { @@ -1711,7 +1985,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss return ERR_INVALID_MEMORY_PERMISSIONS; } - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); auto process = kernel.CurrentProcess(); auto& handle_table = process->GetHandleTable(); auto shared_mem_handle = SharedMemory::Create(kernel, process, size, local_perms, remote_perms); @@ -1720,12 +1994,12 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss return RESULT_SUCCESS; } -static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) { +static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { LOG_DEBUG(Kernel_SVC, "called"); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); const auto [readable_event, writable_event] = - WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent"); + WritableEvent::CreateEventPair(kernel, ResetType::Manual, "CreateEvent"); HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); @@ -1748,10 +2022,10 @@ static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) { return RESULT_SUCCESS; } -static ResultCode ClearEvent(Handle handle) { +static ResultCode ClearEvent(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto writable_event = handle_table.Get<WritableEvent>(handle); if (writable_event) { @@ -1769,10 +2043,10 @@ static ResultCode ClearEvent(Handle handle) { return ERR_INVALID_HANDLE; } -static ResultCode SignalEvent(Handle handle) { +static ResultCode SignalEvent(Core::System& system, Handle handle) { LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); - HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable(); + HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto writable_event = handle_table.Get<WritableEvent>(handle); if (!writable_event) { @@ -1784,7 +2058,7 @@ static ResultCode SignalEvent(Handle handle) { return RESULT_SUCCESS; } -static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { +static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); // This function currently only allows retrieving a process' status. @@ -1792,7 +2066,7 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { Status, }; - const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto process = handle_table.Get<Process>(process_handle); if (!process) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", @@ -1810,10 +2084,10 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { return RESULT_SUCCESS; } -static ResultCode CreateResourceLimit(Handle* out_handle) { +static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { LOG_DEBUG(Kernel_SVC, "called"); - auto& kernel = Core::System::GetInstance().Kernel(); + auto& kernel = system.Kernel(); auto resource_limit = ResourceLimit::Create(kernel); auto* const current_process = kernel.CurrentProcess(); @@ -1828,11 +2102,11 @@ static ResultCode CreateResourceLimit(Handle* out_handle) { return RESULT_SUCCESS; } -static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit, - u32 resource_type) { +static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value, + Handle resource_limit, u32 resource_type) { LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); - const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type, + const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, ResourceLimitValueType::LimitValue); if (limit_value.Failed()) { return limit_value.Code(); @@ -1842,11 +2116,11 @@ static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_lim return RESULT_SUCCESS; } -static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit, - u32 resource_type) { +static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value, + Handle resource_limit, u32 resource_type) { LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); - const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type, + const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, ResourceLimitValueType::CurrentValue); if (current_value.Failed()) { return current_value.Code(); @@ -1856,7 +2130,8 @@ static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_l return RESULT_SUCCESS; } -static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) { +static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit, + u32 resource_type, u64 value) { LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, resource_type, value); @@ -1866,8 +2141,7 @@ static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource return ERR_INVALID_ENUM_VALUE; } - auto& kernel = Core::System::GetInstance().Kernel(); - auto* const current_process = kernel.CurrentProcess(); + auto* const current_process = system.Kernel().CurrentProcess(); ASSERT(current_process != nullptr); auto resource_limit_object = @@ -1891,9 +2165,86 @@ static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource return RESULT_SUCCESS; } +static ResultCode GetProcessList(Core::System& system, u32* out_num_processes, + VAddr out_process_ids, u32 out_process_ids_size) { + LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}", + out_process_ids, out_process_ids_size); + + // If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail. + if ((out_process_ids_size & 0xF0000000) != 0) { + LOG_ERROR(Kernel_SVC, + "Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}", + out_process_ids_size); + return ERR_OUT_OF_RANGE; + } + + const auto& kernel = system.Kernel(); + const auto& vm_manager = kernel.CurrentProcess()->VMManager(); + const auto total_copy_size = out_process_ids_size * sizeof(u64); + + if (out_process_ids_size > 0 && + !vm_manager.IsWithinAddressSpace(out_process_ids, total_copy_size)) { + LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", + out_process_ids, out_process_ids + total_copy_size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto& process_list = kernel.GetProcessList(); + const auto num_processes = process_list.size(); + const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); + + for (std::size_t i = 0; i < copy_amount; ++i) { + Memory::Write64(out_process_ids, process_list[i]->GetProcessID()); + out_process_ids += sizeof(u64); + } + + *out_num_processes = static_cast<u32>(num_processes); + return RESULT_SUCCESS; +} + +static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids, + u32 out_thread_ids_size, Handle debug_handle) { + // TODO: Handle this case when debug events are supported. + UNIMPLEMENTED_IF(debug_handle != InvalidHandle); + + LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}", + out_thread_ids, out_thread_ids_size); + + // If the size is negative or larger than INT32_MAX / sizeof(u64) + if ((out_thread_ids_size & 0xF0000000) != 0) { + LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}", + out_thread_ids_size); + return ERR_OUT_OF_RANGE; + } + + const auto* const current_process = system.Kernel().CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); + const auto total_copy_size = out_thread_ids_size * sizeof(u64); + + if (out_thread_ids_size > 0 && + !vm_manager.IsWithinAddressSpace(out_thread_ids, total_copy_size)) { + LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", + out_thread_ids, out_thread_ids + total_copy_size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto& thread_list = current_process->GetThreadList(); + const auto num_threads = thread_list.size(); + const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); + + auto list_iter = thread_list.cbegin(); + for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { + Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID()); + out_thread_ids += sizeof(u64); + } + + *out_num_threads = static_cast<u32>(num_threads); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { - using Func = void(); + using Func = void(Core::System&); u32 id; Func* func; @@ -1956,7 +2307,7 @@ static const FunctionDef SVC_Table[] = { {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"}, - {0x36, nullptr, "Unknown"}, + {0x36, nullptr, "SynchronizePreemptionState"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, {0x39, nullptr, "Unknown"}, @@ -1983,8 +2334,8 @@ static const FunctionDef SVC_Table[] = { {0x4E, nullptr, "ReadWriteRegister"}, {0x4F, nullptr, "SetProcessActivity"}, {0x50, SvcWrap<CreateSharedMemory>, "CreateSharedMemory"}, - {0x51, nullptr, "MapTransferMemory"}, - {0x52, nullptr, "UnmapTransferMemory"}, + {0x51, SvcWrap<MapTransferMemory>, "MapTransferMemory"}, + {0x52, SvcWrap<UnmapTransferMemory>, "UnmapTransferMemory"}, {0x53, nullptr, "CreateInterruptEvent"}, {0x54, nullptr, "QueryPhysicalAddress"}, {0x55, nullptr, "QueryIoMapping"}, @@ -2003,8 +2354,8 @@ static const FunctionDef SVC_Table[] = { {0x62, nullptr, "TerminateDebugProcess"}, {0x63, nullptr, "GetDebugEvent"}, {0x64, nullptr, "ContinueDebugEvent"}, - {0x65, nullptr, "GetProcessList"}, - {0x66, nullptr, "GetThreadList"}, + {0x65, SvcWrap<GetProcessList>, "GetProcessList"}, + {0x66, SvcWrap<GetThreadList>, "GetThreadList"}, {0x67, nullptr, "GetDebugThreadContext"}, {0x68, nullptr, "SetDebugThreadContext"}, {0x69, nullptr, "QueryDebugProcessMemory"}, @@ -2021,8 +2372,8 @@ static const FunctionDef SVC_Table[] = { {0x74, nullptr, "MapProcessMemory"}, {0x75, nullptr, "UnmapProcessMemory"}, {0x76, SvcWrap<QueryProcessMemory>, "QueryProcessMemory"}, - {0x77, nullptr, "MapProcessCodeMemory"}, - {0x78, nullptr, "UnmapProcessCodeMemory"}, + {0x77, SvcWrap<MapProcessCodeMemory>, "MapProcessCodeMemory"}, + {0x78, SvcWrap<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"}, {0x79, nullptr, "CreateProcess"}, {0x7A, nullptr, "StartProcess"}, {0x7B, nullptr, "TerminateProcess"}, @@ -2042,16 +2393,16 @@ static const FunctionDef* GetSVCInfo(u32 func_num) { MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); -void CallSVC(u32 immediate) { +void CallSVC(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); // Lock the global kernel mutex when we enter the kernel HLE. - std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + std::lock_guard lock{HLE::g_hle_lock}; const FunctionDef* info = GetSVCInfo(immediate); if (info) { if (info->func) { - info->func(); + info->func(system); } else { LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name); } |