diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 466e7cfe6..8cfb7f35a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -103,7 +103,6 @@ add_library(core STATIC hle/applets/mint.h hle/applets/swkbd.cpp hle/applets/swkbd.h - hle/function_wrappers.h hle/ipc.h hle/ipc_helpers.h hle/kernel/address_arbiter.cpp @@ -148,6 +147,7 @@ add_library(core STATIC hle/kernel/shared_page.h hle/kernel/svc.cpp hle/kernel/svc.h + hle/kernel/svc_wrapper.h hle/kernel/thread.cpp hle/kernel/thread.h hle/kernel/timer.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index e3965f2fe..19b6753a4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -72,7 +72,7 @@ private: class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks { public: explicit DynarmicUserCallbacks(ARM_Dynarmic& parent) - : parent(parent), timing(parent.system.CoreTiming()) {} + : parent(parent), timing(parent.system.CoreTiming()), svc_context(parent.system) {} ~DynarmicUserCallbacks() = default; std::uint8_t MemoryRead8(VAddr vaddr) override { @@ -123,7 +123,7 @@ public: } void CallSVC(std::uint32_t swi) override { - Kernel::CallSVC(swi); + svc_context.CallSVC(swi); } void ExceptionRaised(VAddr pc, Dynarmic::A32::Exception exception) override { @@ -158,6 +158,7 @@ public: ARM_Dynarmic& parent; Core::Timing& timing; + Kernel::SVCContext svc_context; }; ARM_Dynarmic::ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode) diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index c6be38873..4854eb23e 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -3864,7 +3864,7 @@ SWI_INST : { cpu->NumInstrsToExecute = num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs; num_instrs = 0; - Kernel::CallSVC(inst_cream->num & 0xFFFF); + Kernel::SVCContext{Core::System::GetInstance()}.CallSVC(inst_cream->num & 0xFFFF); // The kernel would call ERET to get here, which clears exclusive memory state. cpu->UnsetExclusiveMemoryAddress(); } diff --git a/src/core/core.cpp b/src/core/core.cpp index 52b27a6ca..40cedd2d7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -172,6 +172,8 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { timing = std::make_unique(); + kernel = std::make_unique(system_mode); + if (Settings::values.use_cpu_jit) { #ifdef ARCHITECTURE_x86_64 cpu_core = std::make_unique(*this, USER32MODE); @@ -197,7 +199,6 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { archive_manager = std::make_unique(*this); HW::Init(); - kernel = std::make_unique(system_mode); Service::Init(*this); GDBStub::Init(); diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h deleted file mode 100644 index 3fa555258..000000000 --- a/src/core/hle/function_wrappers.h +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" -#include "core/arm/arm_interface.h" -#include "core/core.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/svc.h" -#include "core/hle/result.h" -#include "core/memory.h" - -namespace HLE { - -static inline u32 Param(int n) { - return Core::CPU().GetReg(n); -} - -/** - * HLE a function return from the current ARM11 userland process - * @param res Result to return - */ -static inline void FuncReturn(u32 res) { - Core::CPU().SetReg(0, res); -} - -/** - * HLE a function return (64-bit) from the current ARM11 userland process - * @param res Result to return (64-bit) - * @todo Verify that this function is correct - */ -static inline void FuncReturn64(u64 res) { - Core::CPU().SetReg(0, (u32)(res & 0xFFFFFFFF)); - Core::CPU().SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Function wrappers that return type ResultCode - -template -void Wrap() { - FuncReturn(func(Param(0), Param(1), Param(2), Param(3)).raw); -} - -template -void Wrap() { - u32 param_1 = 0; - u32 retval = func(¶m_1, Param(0), Param(1), Param(2), Param(3), Param(4)).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - u32 param_1 = 0; - u32 retval = func(¶m_1, Param(0), Param(1), Param(2), Param(3), Param(4)).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - s32 param_1 = 0; - s32 retval = - func(¶m_1, Param(1), (s32)Param(2), (Param(3) != 0), (((s64)Param(4) << 32) | Param(0))) - .raw; - - Core::CPU().SetReg(1, (u32)param_1); - FuncReturn(retval); -} - -template -void Wrap() { - s32 param_1 = 0; - u32 retval = func(¶m_1, Param(1), (s32)Param(2), Param(3)).raw; - - Core::CPU().SetReg(1, (u32)param_1); - FuncReturn(retval); -} - -template -void Wrap() { - FuncReturn( - func(Param(0), Param(1), Param(2), Param(3), (((s64)Param(5) << 32) | Param(4))).raw); -} - -template -void Wrap() { - u32 param_1 = 0; - u32 retval = func(¶m_1).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - s32 retval = func(Param(0), (((s64)Param(3) << 32) | Param(2))).raw; - - FuncReturn(retval); -} - -template -void Wrap() { - Kernel::MemoryInfo memory_info = {}; - Kernel::PageInfo page_info = {}; - u32 retval = func(&memory_info, &page_info, Param(2)).raw; - Core::CPU().SetReg(1, memory_info.base_address); - Core::CPU().SetReg(2, memory_info.size); - Core::CPU().SetReg(3, memory_info.permission); - Core::CPU().SetReg(4, memory_info.state); - Core::CPU().SetReg(5, page_info.flags); - FuncReturn(retval); -} - -template -void Wrap() { - Kernel::MemoryInfo memory_info = {}; - Kernel::PageInfo page_info = {}; - u32 retval = func(&memory_info, &page_info, Param(2), Param(3)).raw; - Core::CPU().SetReg(1, memory_info.base_address); - Core::CPU().SetReg(2, memory_info.size); - Core::CPU().SetReg(3, memory_info.permission); - Core::CPU().SetReg(4, memory_info.state); - Core::CPU().SetReg(5, page_info.flags); - FuncReturn(retval); -} - -template -void Wrap() { - s32 param_1 = 0; - u32 retval = func(¶m_1, Param(1)).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - FuncReturn(func(Param(0), (s32)Param(1)).raw); -} - -template -void Wrap() { - u32 param_1 = 0; - u32 retval = func(¶m_1, Param(1)).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - FuncReturn(func(Param(0)).raw); -} - -template -void Wrap() { - u32 param_1 = 0; - u32 retval = func(¶m_1, Param(1), Param(2)).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - s32 param_1 = 0; - u32 retval = func(¶m_1, Param(1), Param(2)).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - s64 param_1 = 0; - u32 retval = func(¶m_1, Param(1), Param(2)).raw; - Core::CPU().SetReg(1, (u32)param_1); - Core::CPU().SetReg(2, (u32)(param_1 >> 32)); - FuncReturn(retval); -} - -template -void Wrap() { - u32 param_1 = 0; - // The last parameter is passed in R0 instead of R4 - u32 retval = func(¶m_1, Param(1), Param(2), Param(3), Param(0)).raw; - Core::CPU().SetReg(1, param_1); - FuncReturn(retval); -} - -template -void Wrap() { - s64 param1 = ((u64)Param(3) << 32) | Param(2); - s64 param2 = ((u64)Param(4) << 32) | Param(1); - FuncReturn(func(Param(0), param1, param2).raw); -} - -template -void Wrap() { - s64 param_1 = 0; - u32 retval = func(¶m_1, Param(1), Param(2)).raw; - Core::CPU().SetReg(1, (u32)param_1); - Core::CPU().SetReg(2, (u32)(param_1 >> 32)); - FuncReturn(retval); -} - -template -void Wrap() { - FuncReturn(func(Param(0), Param(1)).raw); -} - -template -void Wrap() { - Kernel::Handle param_1 = 0; - Kernel::Handle param_2 = 0; - u32 retval = func(¶m_1, ¶m_2, Param(2), Param(3)).raw; - Core::CPU().SetReg(1, param_1); - Core::CPU().SetReg(2, param_2); - FuncReturn(retval); -} - -template -void Wrap() { - Kernel::Handle param_1 = 0; - Kernel::Handle param_2 = 0; - u32 retval = func(¶m_1, ¶m_2).raw; - Core::CPU().SetReg(1, param_1); - Core::CPU().SetReg(2, param_2); - FuncReturn(retval); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Function wrappers that return type u32 - -template -void Wrap() { - FuncReturn(func()); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Function wrappers that return type s64 - -template -void Wrap() { - FuncReturn64(func()); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -/// Function wrappers that return type void - -template -void Wrap() { - func(((s64)Param(1) << 32) | Param(0)); -} - -template -void Wrap() { - func(Param(0), Param(1)); -} - -template -void Wrap() { - func((u8)Param(0)); -} - -} // namespace HLE diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 16bbddb24..53728a66d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -10,8 +10,8 @@ #include "common/microprofile.h" #include "common/scope_exit.h" #include "core/arm/arm_interface.h" +#include "core/core.h" #include "core/core_timing.h" -#include "core/hle/function_wrappers.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -28,6 +28,8 @@ #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_wrapper.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" #include "core/hle/kernel/vm_manager.h" @@ -55,9 +57,136 @@ enum ControlMemoryOperation { MEMOP_LINEAR = 0x10000, }; +struct MemoryInfo { + u32 base_address; + u32 size; + u32 permission; + u32 state; +}; + +struct PageInfo { + u32 flags; +}; + +/// Values accepted by svcGetSystemInfo's type parameter. +enum class SystemInfoType { + /** + * Reports total used memory for all regions or a specific one, according to the extra + * parameter. See `SystemInfoMemUsageRegion`. + */ + REGION_MEMORY_USAGE = 0, + /** + * Returns the memory usage for certain allocations done internally by the kernel. + */ + KERNEL_ALLOCATED_PAGES = 2, + /** + * "This returns the total number of processes which were launched directly by the kernel. + * For the ARM11 NATIVE_FIRM kernel, this is 5, for processes sm, fs, pm, loader, and pxi." + */ + KERNEL_SPAWNED_PIDS = 26, +}; + +/** + * Accepted by svcGetSystemInfo param with REGION_MEMORY_USAGE type. Selects a region to query + * memory usage of. + */ +enum class SystemInfoMemUsageRegion { + ALL = 0, + APPLICATION = 1, + SYSTEM = 2, + BASE = 3, +}; + +class SVC : public SVCWrapper { +public: + SVC(Core::System& system); + void CallSVC(u32 immediate); + +private: + Core::System& system; + Kernel::KernelSystem& kernel; + + friend class SVCWrapper; + + // ARM interfaces + + u32 GetReg(std::size_t n); + void SetReg(std::size_t n, u32 value); + + // SVC interfaces + + ResultCode ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32 operation, + u32 permissions); + void ExitProcess(); + ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions); + ResultCode UnmapMemoryBlock(Handle handle, u32 addr); + ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address); + ResultCode SendSyncRequest(Handle handle); + ResultCode CloseHandle(Handle handle); + ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds); + ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count, + bool wait_all, s64 nano_seconds); + ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, + Handle reply_target); + ResultCode CreateAddressArbiter(Handle* out_handle); + ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds); + void Break(u8 break_reason); + void OutputDebugString(VAddr address, s32 len); + ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle); + ResultCode GetResourceLimitCurrentValues(VAddr values, Handle resource_limit_handle, + VAddr names, u32 name_count); + ResultCode GetResourceLimitLimitValues(VAddr values, Handle resource_limit_handle, VAddr names, + u32 name_count); + ResultCode CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr stack_top, + u32 priority, s32 processor_id); + void ExitThread(); + ResultCode GetThreadPriority(u32* priority, Handle handle); + ResultCode SetThreadPriority(Handle handle, u32 priority); + ResultCode CreateMutex(Handle* out_handle, u32 initial_locked); + ResultCode ReleaseMutex(Handle handle); + ResultCode GetProcessId(u32* process_id, Handle process_handle); + ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle); + ResultCode GetThreadId(u32* thread_id, Handle handle); + ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count); + ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count); + ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, + Handle process_handle, u32 addr); + ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr); + ResultCode CreateEvent(Handle* out_handle, u32 reset_type); + ResultCode DuplicateHandle(Handle* out, Handle handle); + ResultCode SignalEvent(Handle handle); + ResultCode ClearEvent(Handle handle); + ResultCode CreateTimer(Handle* out_handle, u32 reset_type); + ResultCode ClearTimer(Handle handle); + ResultCode SetTimer(Handle handle, s64 initial, s64 interval); + ResultCode CancelTimer(Handle handle); + void SleepThread(s64 nanoseconds); + s64 GetSystemTick(); + ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, + u32 other_permission); + ResultCode CreatePort(Handle* server_port, Handle* client_port, VAddr name_address, + u32 max_sessions); + ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_port_handle); + ResultCode CreateSession(Handle* server_session, Handle* client_session); + ResultCode AcceptSession(Handle* out_server_session, Handle server_port_handle); + ResultCode GetSystemInfo(s64* out, u32 type, s32 param); + ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type); + + struct FunctionDef { + using Func = void (SVC::*)(); + + u32 id; + Func func; + const char* name; + }; + + static const FunctionDef SVC_Table[]; + static const FunctionDef* GetSVCInfo(u32 func_num); +}; + /// Map application or GSP heap memory -static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, - u32 permissions) { +ResultCode SVC::ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32 operation, + u32 permissions) { LOG_DEBUG(Kernel_SVC, "called operation=0x{:08X}, addr0=0x{:08X}, addr1=0x{:08X}, " "size=0x{:X}, permissions=0x{:08X}", @@ -83,7 +212,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add } VMAPermission vma_permissions = (VMAPermission)permissions; - auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess(); + auto& process = *kernel.GetCurrentProcess(); switch (operation & MEMOP_OPERATION_MASK) { case MEMOP_FREE: { @@ -140,8 +269,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add return RESULT_SUCCESS; } -static void ExitProcess() { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +void SVC::ExitProcess() { SharedPtr current_process = kernel.GetCurrentProcess(); LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->process_id); @@ -169,19 +297,18 @@ static void ExitProcess() { // Kill the current thread kernel.GetThreadManager().GetCurrentThread()->Stop(); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); } /// Maps a memory block to specified address -static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { +ResultCode SVC::MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { LOG_TRACE(Kernel_SVC, "called memblock=0x{:08X}, addr=0x{:08X}, mypermissions=0x{:08X}, " "otherpermission={}", handle, addr, permissions, other_permissions); SharedPtr shared_memory = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - handle); + kernel.GetCurrentProcess()->handle_table.Get(handle); if (shared_memory == nullptr) return ERR_INVALID_HANDLE; @@ -195,8 +322,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o case MemoryPermission::WriteExecute: case MemoryPermission::ReadWriteExecute: case MemoryPermission::DontCare: - return shared_memory->Map(Core::System::GetInstance().Kernel().GetCurrentProcess().get(), - addr, permissions_type, + return shared_memory->Map(kernel.GetCurrentProcess().get(), addr, permissions_type, static_cast(other_permissions)); default: LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); @@ -205,12 +331,12 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o return ERR_INVALID_COMBINATION; } -static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { +ResultCode SVC::UnmapMemoryBlock(Handle handle, u32 addr) { LOG_TRACE(Kernel_SVC, "called memblock=0x{:08X}, addr=0x{:08X}", handle, addr); // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr current_process = kernel.GetCurrentProcess(); SharedPtr shared_memory = current_process->handle_table.Get(handle); if (shared_memory == nullptr) return ERR_INVALID_HANDLE; @@ -219,7 +345,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { } /// Connect to an OS service given the port name, returns the handle to the port to out -static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { +ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) { if (!Memory::IsValidVirtualAddress(port_name_address)) return ERR_NOT_FOUND; @@ -231,8 +357,6 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); - KernelSystem& kernel = Core::System::GetInstance().Kernel(); - auto it = kernel.named_ports.find(port_name); if (it == kernel.named_ports.end()) { LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); @@ -250,8 +374,7 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { } /// Makes a blocking IPC call to an OS service. -static ResultCode SendSyncRequest(Handle handle) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::SendSyncRequest(Handle handle) { SharedPtr session = kernel.GetCurrentProcess()->handle_table.Get(handle); if (session == nullptr) { @@ -260,20 +383,19 @@ static ResultCode SendSyncRequest(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); return session->SendSyncRequest(kernel.GetThreadManager().GetCurrentThread()); } /// Close a handle -static ResultCode CloseHandle(Handle handle) { +ResultCode SVC::CloseHandle(Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); - return Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Close(handle); + return kernel.GetCurrentProcess()->handle_table.Close(handle); } /// Wait for a handle to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) { auto object = kernel.GetCurrentProcess()->handle_table.Get(handle); Thread* thread = kernel.GetThreadManager().GetCurrentThread(); @@ -311,7 +433,7 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { // don't have to do anything else here. }; - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread // resumes due to a signal in its wait objects. @@ -325,9 +447,8 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { } /// Wait for the given handles to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count, - bool wait_all, s64 nano_seconds) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count, + bool wait_all, s64 nano_seconds) { Thread* thread = kernel.GetThreadManager().GetCurrentThread(); if (!Memory::IsValidVirtualAddress(handles_address)) @@ -400,7 +521,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand // The wait_all case does not update the output index. }; - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); // This value gets set to -1 by default in this case, it is not modified after this. *out = -1; @@ -460,7 +581,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get())); }; - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a // signal in one of its wait objects. @@ -498,8 +619,8 @@ static ResultCode ReceiveIPCRequest(SharedPtr server_session, } /// In a single operation, sends a IPC reply and waits for a new request. -static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, - Handle reply_target) { +ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, + Handle reply_target) { if (!Memory::IsValidVirtualAddress(handles_address)) return ERR_INVALID_POINTER; @@ -510,7 +631,6 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ using ObjectPtr = SharedPtr; std::vector objects(handle_count); - KernelSystem& kernel = Core::System::GetInstance().Kernel(); SharedPtr current_process = kernel.GetCurrentProcess(); for (int i = 0; i < handle_count; ++i) { @@ -614,7 +734,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get())); }; - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error. @@ -624,8 +744,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ } /// Create an address arbiter (to allocate access to shared resources) -static ResultCode CreateAddressArbiter(Handle* out_handle) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::CreateAddressArbiter(Handle* out_handle) { SharedPtr arbiter = kernel.CreateAddressArbiter(); CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(arbiter))); @@ -634,13 +753,10 @@ static ResultCode CreateAddressArbiter(Handle* out_handle) { } /// Arbitrate address -static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, - s64 nanoseconds) { +ResultCode SVC::ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}, address=0x{:08X}, type=0x{:08X}, value=0x{:08X}", handle, address, type, value); - KernelSystem& kernel = Core::System::GetInstance().Kernel(); - SharedPtr arbiter = kernel.GetCurrentProcess()->handle_table.Get(handle); if (arbiter == nullptr) @@ -651,12 +767,12 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val static_cast(type), address, value, nanoseconds); // TODO(Subv): Identify in which specific cases this call should cause a reschedule. - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); return res; } -static void Break(u8 break_reason) { +void SVC::Break(u8 break_reason) { LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); std::string reason_str; switch (break_reason) { @@ -677,7 +793,7 @@ static void Break(u8 break_reason) { } /// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString(VAddr address, int len) { +void SVC::OutputDebugString(VAddr address, s32 len) { if (len <= 0) { return; } @@ -688,10 +804,10 @@ static void OutputDebugString(VAddr address, int len) { } /// Get resource limit -static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) { +ResultCode SVC::GetResourceLimit(Handle* resource_limit, Handle process_handle) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr current_process = kernel.GetCurrentProcess(); SharedPtr process = current_process->handle_table.Get(process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; @@ -702,14 +818,13 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle } /// Get resource limit current values -static ResultCode GetResourceLimitCurrentValues(VAddr values, Handle resource_limit_handle, - VAddr names, u32 name_count) { +ResultCode SVC::GetResourceLimitCurrentValues(VAddr values, Handle resource_limit_handle, + VAddr names, u32 name_count) { LOG_TRACE(Kernel_SVC, "called resource_limit={:08X}, names={:08X}, name_count={}", resource_limit_handle, names, name_count); SharedPtr resource_limit = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - resource_limit_handle); + kernel.GetCurrentProcess()->handle_table.Get(resource_limit_handle); if (resource_limit == nullptr) return ERR_INVALID_HANDLE; @@ -723,14 +838,13 @@ static ResultCode GetResourceLimitCurrentValues(VAddr values, Handle resource_li } /// Get resource limit max values -static ResultCode GetResourceLimitLimitValues(VAddr values, Handle resource_limit_handle, - VAddr names, u32 name_count) { +ResultCode SVC::GetResourceLimitLimitValues(VAddr values, Handle resource_limit_handle, VAddr names, + u32 name_count) { LOG_TRACE(Kernel_SVC, "called resource_limit={:08X}, names={:08X}, name_count={}", resource_limit_handle, names, name_count); SharedPtr resource_limit = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - resource_limit_handle); + kernel.GetCurrentProcess()->handle_table.Get(resource_limit_handle); if (resource_limit == nullptr) return ERR_INVALID_HANDLE; @@ -744,15 +858,15 @@ static ResultCode GetResourceLimitLimitValues(VAddr values, Handle resource_limi } /// Creates a new thread -static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point, u32 arg, - u32 stack_top, s32 processor_id) { +ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr stack_top, + u32 priority, s32 processor_id) { std::string name = fmt::format("thread-{:08X}", entry_point); if (priority > ThreadPrioLowest) { return ERR_OUT_OF_RANGE; } - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr current_process = kernel.GetCurrentProcess(); SharedPtr& resource_limit = current_process->resource_limit; if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { @@ -782,16 +896,16 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point break; } - CASCADE_RESULT(SharedPtr thread, Core::System::GetInstance().Kernel().CreateThread( - name, entry_point, priority, arg, processor_id, - stack_top, *current_process)); + CASCADE_RESULT(SharedPtr thread, + kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top, + *current_process)); thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO); // 0x03C00000 CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(thread))); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); LOG_TRACE(Kernel_SVC, "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " @@ -802,17 +916,16 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point } /// Called when a thread exits -static void ExitThread() { - LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC()); +void SVC::ExitThread() { + LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", system.CPU().GetPC()); - Core::System::GetInstance().Kernel().GetThreadManager().ExitCurrentThread(); - Core::System::GetInstance().PrepareReschedule(); + kernel.GetThreadManager().ExitCurrentThread(); + system.PrepareReschedule(); } /// Gets the priority for the specified thread -static ResultCode GetThreadPriority(u32* priority, Handle handle) { - const SharedPtr thread = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); +ResultCode SVC::GetThreadPriority(u32* priority, Handle handle) { + const SharedPtr thread = kernel.GetCurrentProcess()->handle_table.Get(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -821,20 +934,18 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) { } /// Sets the priority for the specified thread -static ResultCode SetThreadPriority(Handle handle, u32 priority) { +ResultCode SVC::SetThreadPriority(Handle handle, u32 priority) { if (priority > ThreadPrioLowest) { return ERR_OUT_OF_RANGE; } - SharedPtr thread = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + SharedPtr thread = kernel.GetCurrentProcess()->handle_table.Get(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; // Note: The kernel uses the current process's resource limit instead of // the one from the thread owner's resource limit. - SharedPtr& resource_limit = - Core::System::GetInstance().Kernel().GetCurrentProcess()->resource_limit; + SharedPtr& resource_limit = kernel.GetCurrentProcess()->resource_limit; if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { return ERR_NOT_AUTHORIZED; } @@ -846,15 +957,14 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { for (auto& mutex : thread->pending_mutexes) mutex->UpdatePriority(); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); return RESULT_SUCCESS; } /// Create a mutex -static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::CreateMutex(Handle* out_handle, u32 initial_locked) { SharedPtr mutex = kernel.CreateMutex(initial_locked != 0); - mutex->name = fmt::format("mutex-{:08x}", Core::CPU().GetReg(14)); + mutex->name = fmt::format("mutex-{:08x}", system.CPU().GetReg(14)); CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(mutex))); LOG_TRACE(Kernel_SVC, "called initial_locked={} : created handle=0x{:08X}", @@ -864,11 +974,9 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { } /// Release a mutex -static ResultCode ReleaseMutex(Handle handle) { +ResultCode SVC::ReleaseMutex(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); - KernelSystem& kernel = Core::System::GetInstance().Kernel(); - SharedPtr mutex = kernel.GetCurrentProcess()->handle_table.Get(handle); if (mutex == nullptr) return ERR_INVALID_HANDLE; @@ -877,12 +985,11 @@ static ResultCode ReleaseMutex(Handle handle) { } /// Get the ID of the specified process -static ResultCode GetProcessId(u32* process_id, Handle process_handle) { +ResultCode SVC::GetProcessId(u32* process_id, Handle process_handle) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); const SharedPtr process = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - process_handle); + kernel.GetCurrentProcess()->handle_table.Get(process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; @@ -891,12 +998,11 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { } /// Get the ID of the process that owns the specified thread -static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { +ResultCode SVC::GetProcessIdOfThread(u32* process_id, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const SharedPtr thread = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - thread_handle); + kernel.GetCurrentProcess()->handle_table.Get(thread_handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -909,11 +1015,10 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { } /// Get the ID for the specified thread. -static ResultCode GetThreadId(u32* thread_id, Handle handle) { +ResultCode SVC::GetThreadId(u32* thread_id, Handle handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", handle); - const SharedPtr thread = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + const SharedPtr thread = kernel.GetCurrentProcess()->handle_table.Get(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -922,11 +1027,10 @@ static ResultCode GetThreadId(u32* thread_id, Handle handle) { } /// Creates a semaphore -static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { CASCADE_RESULT(SharedPtr semaphore, kernel.CreateSemaphore(initial_count, max_count)); - semaphore->name = fmt::format("semaphore-{:08x}", Core::CPU().GetReg(14)); + semaphore->name = fmt::format("semaphore-{:08x}", system.CPU().GetReg(14)); CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(semaphore))); @@ -936,12 +1040,11 @@ static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max } /// Releases a certain number of slots in a semaphore -static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { +ResultCode SVC::ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { LOG_TRACE(Kernel_SVC, "called release_count={}, handle=0x{:08X}", release_count, handle); SharedPtr semaphore = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - handle); + kernel.GetCurrentProcess()->handle_table.Get(handle); if (semaphore == nullptr) return ERR_INVALID_HANDLE; @@ -951,11 +1054,10 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) } /// Query process memory -static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, - Handle process_handle, u32 addr) { +ResultCode SVC::QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, + Handle process_handle, u32 addr) { SharedPtr process = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - process_handle); + kernel.GetCurrentProcess()->handle_table.Get(process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; @@ -975,15 +1077,14 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf } /// Query memory -static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) { +ResultCode SVC::QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) { return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr); } /// Create an event -static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::CreateEvent(Handle* out_handle, u32 reset_type) { SharedPtr evt = kernel.CreateEvent(static_cast(reset_type), - fmt::format("event-{:08x}", Core::CPU().GetReg(14))); + fmt::format("event-{:08x}", system.CPU().GetReg(14))); CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(evt))); LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type, @@ -992,20 +1093,17 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { } /// Duplicates a kernel handle -static ResultCode DuplicateHandle(Handle* out, Handle handle) { - CASCADE_RESULT( - *out, - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Duplicate(handle)); +ResultCode SVC::DuplicateHandle(Handle* out, Handle handle) { + CASCADE_RESULT(*out, kernel.GetCurrentProcess()->handle_table.Duplicate(handle)); LOG_TRACE(Kernel_SVC, "duplicated 0x{:08X} to 0x{:08X}", handle, *out); return RESULT_SUCCESS; } /// Signals an event -static ResultCode SignalEvent(Handle handle) { +ResultCode SVC::SignalEvent(Handle handle) { LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle); - SharedPtr evt = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + SharedPtr evt = kernel.GetCurrentProcess()->handle_table.Get(handle); if (evt == nullptr) return ERR_INVALID_HANDLE; @@ -1015,11 +1113,10 @@ static ResultCode SignalEvent(Handle handle) { } /// Clears an event -static ResultCode ClearEvent(Handle handle) { +ResultCode SVC::ClearEvent(Handle handle) { LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle); - SharedPtr evt = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + SharedPtr evt = kernel.GetCurrentProcess()->handle_table.Get(handle); if (evt == nullptr) return ERR_INVALID_HANDLE; @@ -1028,10 +1125,9 @@ static ResultCode ClearEvent(Handle handle) { } /// Creates a timer -static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::CreateTimer(Handle* out_handle, u32 reset_type) { SharedPtr timer = kernel.CreateTimer( - static_cast(reset_type), fmt ::format("timer-{:08x}", Core::CPU().GetReg(14))); + static_cast(reset_type), fmt ::format("timer-{:08x}", system.CPU().GetReg(14))); CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(timer))); LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type, @@ -1040,11 +1136,10 @@ static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { } /// Clears a timer -static ResultCode ClearTimer(Handle handle) { +ResultCode SVC::ClearTimer(Handle handle) { LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); - SharedPtr timer = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + SharedPtr timer = kernel.GetCurrentProcess()->handle_table.Get(handle); if (timer == nullptr) return ERR_INVALID_HANDLE; @@ -1053,15 +1148,14 @@ static ResultCode ClearTimer(Handle handle) { } /// Starts a timer -static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { +ResultCode SVC::SetTimer(Handle handle, s64 initial, s64 interval) { LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); if (initial < 0 || interval < 0) { return ERR_OUT_OF_RANGE_KERNEL; } - SharedPtr timer = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + SharedPtr timer = kernel.GetCurrentProcess()->handle_table.Get(handle); if (timer == nullptr) return ERR_INVALID_HANDLE; @@ -1071,11 +1165,10 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { } /// Cancels a timer -static ResultCode CancelTimer(Handle handle) { +ResultCode SVC::CancelTimer(Handle handle) { LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); - SharedPtr timer = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + SharedPtr timer = kernel.GetCurrentProcess()->handle_table.Get(handle); if (timer == nullptr) return ERR_INVALID_HANDLE; @@ -1085,10 +1178,9 @@ static ResultCode CancelTimer(Handle handle) { } /// Sleep the current thread -static void SleepThread(s64 nanoseconds) { +void SVC::SleepThread(s64 nanoseconds) { LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); - KernelSystem& kernel = Core::System::GetInstance().Kernel(); ThreadManager& thread_manager = kernel.GetThreadManager(); // Don't attempt to yield execution if there are no available threads to run, @@ -1102,21 +1194,21 @@ static void SleepThread(s64 nanoseconds) { // Create an event to wake the thread up after the specified nanosecond delay has passed thread_manager.GetCurrentThread()->WakeAfterDelay(nanoseconds); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); } /// This returns the total CPU ticks elapsed since the CPU was powered-on -static s64 GetSystemTick() { - s64 result = Core::System::GetInstance().CoreTiming().GetTicks(); +s64 SVC::GetSystemTick() { + s64 result = system.CoreTiming().GetTicks(); // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end. // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b - Core::System::GetInstance().CoreTiming().AddTicks(150); + system.CoreTiming().AddTicks(150); return result; } /// Creates a memory block at the specified address with the specified permissions and size -static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, - u32 other_permission) { +ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, + u32 other_permission) { if (size % Memory::PAGE_SIZE != 0) return ERR_MISALIGNED_SIZE; @@ -1148,7 +1240,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 return ERR_INVALID_ADDRESS; } - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr current_process = kernel.GetCurrentProcess(); // When trying to create a memory block with address = 0, // if the process has the Shared Device Memory flag in the exheader, @@ -1158,7 +1250,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 if (addr == 0 && current_process->flags.shared_device_mem) region = current_process->flags.memory_region; - shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory( + shared_memory = kernel.CreateSharedMemory( current_process.get(), size, static_cast(my_permission), static_cast(other_permission), addr, region); CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(shared_memory))); @@ -1167,12 +1259,11 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 return RESULT_SUCCESS; } -static ResultCode CreatePort(Handle* server_port, Handle* client_port, VAddr name_address, - u32 max_sessions) { +ResultCode SVC::CreatePort(Handle* server_port, Handle* client_port, VAddr name_address, + u32 max_sessions) { // TODO(Subv): Implement named ports. ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented"); - KernelSystem& kernel = Core::System::GetInstance().Kernel(); SharedPtr current_process = kernel.GetCurrentProcess(); auto ports = kernel.CreatePortPair(max_sessions); @@ -1187,8 +1278,8 @@ static ResultCode CreatePort(Handle* server_port, Handle* client_port, VAddr nam return RESULT_SUCCESS; } -static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) { - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); +ResultCode SVC::CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) { + SharedPtr current_process = kernel.GetCurrentProcess(); SharedPtr client_port = current_process->handle_table.Get(client_port_handle); if (client_port == nullptr) @@ -1199,8 +1290,7 @@ static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_ return RESULT_SUCCESS; } -static ResultCode CreateSession(Handle* server_session, Handle* client_session) { - KernelSystem& kernel = Core::System::GetInstance().Kernel(); +ResultCode SVC::CreateSession(Handle* server_session, Handle* client_session) { auto sessions = kernel.CreateSessionPair(); SharedPtr current_process = kernel.GetCurrentProcess(); @@ -1215,8 +1305,8 @@ static ResultCode CreateSession(Handle* server_session, Handle* client_session) return RESULT_SUCCESS; } -static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_handle) { - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); +ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_handle) { + SharedPtr current_process = kernel.GetCurrentProcess(); SharedPtr server_port = current_process->handle_table.Get(server_port_handle); if (server_port == nullptr) @@ -1227,11 +1317,9 @@ static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_h return RESULT_SUCCESS; } -static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { +ResultCode SVC::GetSystemInfo(s64* out, u32 type, s32 param) { LOG_TRACE(Kernel_SVC, "called type={} param={}", type, param); - KernelSystem& kernel = Core::System::GetInstance().Kernel(); - switch ((SystemInfoType)type) { case SystemInfoType::REGION_MEMORY_USAGE: switch ((SystemInfoMemUsageRegion)param) { @@ -1272,12 +1360,11 @@ static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { return RESULT_SUCCESS; } -static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { +ResultCode SVC::GetProcessInfo(s64* out, Handle process_handle, u32 type) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X} type={}", process_handle, type); SharedPtr process = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - process_handle); + kernel.GetCurrentProcess()->handle_table.Get(process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; @@ -1319,79 +1406,69 @@ static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { return RESULT_SUCCESS; } -namespace { -struct FunctionDef { - using Func = void(); - - u32 id; - Func* func; - const char* name; -}; -} // namespace - -static const FunctionDef SVC_Table[] = { +const SVC::FunctionDef SVC::SVC_Table[] = { {0x00, nullptr, "Unknown"}, - {0x01, HLE::Wrap, "ControlMemory"}, - {0x02, HLE::Wrap, "QueryMemory"}, - {0x03, ExitProcess, "ExitProcess"}, + {0x01, &SVC::Wrap<&SVC::ControlMemory>, "ControlMemory"}, + {0x02, &SVC::Wrap<&SVC::QueryMemory>, "QueryMemory"}, + {0x03, &SVC::ExitProcess, "ExitProcess"}, {0x04, nullptr, "GetProcessAffinityMask"}, {0x05, nullptr, "SetProcessAffinityMask"}, {0x06, nullptr, "GetProcessIdealProcessor"}, {0x07, nullptr, "SetProcessIdealProcessor"}, - {0x08, HLE::Wrap, "CreateThread"}, - {0x09, ExitThread, "ExitThread"}, - {0x0A, HLE::Wrap, "SleepThread"}, - {0x0B, HLE::Wrap, "GetThreadPriority"}, - {0x0C, HLE::Wrap, "SetThreadPriority"}, + {0x08, &SVC::Wrap<&SVC::CreateThread>, "CreateThread"}, + {0x09, &SVC::ExitThread, "ExitThread"}, + {0x0A, &SVC::Wrap<&SVC::SleepThread>, "SleepThread"}, + {0x0B, &SVC::Wrap<&SVC::GetThreadPriority>, "GetThreadPriority"}, + {0x0C, &SVC::Wrap<&SVC::SetThreadPriority>, "SetThreadPriority"}, {0x0D, nullptr, "GetThreadAffinityMask"}, {0x0E, nullptr, "SetThreadAffinityMask"}, {0x0F, nullptr, "GetThreadIdealProcessor"}, {0x10, nullptr, "SetThreadIdealProcessor"}, {0x11, nullptr, "GetCurrentProcessorNumber"}, {0x12, nullptr, "Run"}, - {0x13, HLE::Wrap, "CreateMutex"}, - {0x14, HLE::Wrap, "ReleaseMutex"}, - {0x15, HLE::Wrap, "CreateSemaphore"}, - {0x16, HLE::Wrap, "ReleaseSemaphore"}, - {0x17, HLE::Wrap, "CreateEvent"}, - {0x18, HLE::Wrap, "SignalEvent"}, - {0x19, HLE::Wrap, "ClearEvent"}, - {0x1A, HLE::Wrap, "CreateTimer"}, - {0x1B, HLE::Wrap, "SetTimer"}, - {0x1C, HLE::Wrap, "CancelTimer"}, - {0x1D, HLE::Wrap, "ClearTimer"}, - {0x1E, HLE::Wrap, "CreateMemoryBlock"}, - {0x1F, HLE::Wrap, "MapMemoryBlock"}, - {0x20, HLE::Wrap, "UnmapMemoryBlock"}, - {0x21, HLE::Wrap, "CreateAddressArbiter"}, - {0x22, HLE::Wrap, "ArbitrateAddress"}, - {0x23, HLE::Wrap, "CloseHandle"}, - {0x24, HLE::Wrap, "WaitSynchronization1"}, - {0x25, HLE::Wrap, "WaitSynchronizationN"}, + {0x13, &SVC::Wrap<&SVC::CreateMutex>, "CreateMutex"}, + {0x14, &SVC::Wrap<&SVC::ReleaseMutex>, "ReleaseMutex"}, + {0x15, &SVC::Wrap<&SVC::CreateSemaphore>, "CreateSemaphore"}, + {0x16, &SVC::Wrap<&SVC::ReleaseSemaphore>, "ReleaseSemaphore"}, + {0x17, &SVC::Wrap<&SVC::CreateEvent>, "CreateEvent"}, + {0x18, &SVC::Wrap<&SVC::SignalEvent>, "SignalEvent"}, + {0x19, &SVC::Wrap<&SVC::ClearEvent>, "ClearEvent"}, + {0x1A, &SVC::Wrap<&SVC::CreateTimer>, "CreateTimer"}, + {0x1B, &SVC::Wrap<&SVC::SetTimer>, "SetTimer"}, + {0x1C, &SVC::Wrap<&SVC::CancelTimer>, "CancelTimer"}, + {0x1D, &SVC::Wrap<&SVC::ClearTimer>, "ClearTimer"}, + {0x1E, &SVC::Wrap<&SVC::CreateMemoryBlock>, "CreateMemoryBlock"}, + {0x1F, &SVC::Wrap<&SVC::MapMemoryBlock>, "MapMemoryBlock"}, + {0x20, &SVC::Wrap<&SVC::UnmapMemoryBlock>, "UnmapMemoryBlock"}, + {0x21, &SVC::Wrap<&SVC::CreateAddressArbiter>, "CreateAddressArbiter"}, + {0x22, &SVC::Wrap<&SVC::ArbitrateAddress>, "ArbitrateAddress"}, + {0x23, &SVC::Wrap<&SVC::CloseHandle>, "CloseHandle"}, + {0x24, &SVC::Wrap<&SVC::WaitSynchronization1>, "WaitSynchronization1"}, + {0x25, &SVC::Wrap<&SVC::WaitSynchronizationN>, "WaitSynchronizationN"}, {0x26, nullptr, "SignalAndWait"}, - {0x27, HLE::Wrap, "DuplicateHandle"}, - {0x28, HLE::Wrap, "GetSystemTick"}, + {0x27, &SVC::Wrap<&SVC::DuplicateHandle>, "DuplicateHandle"}, + {0x28, &SVC::Wrap<&SVC::GetSystemTick>, "GetSystemTick"}, {0x29, nullptr, "GetHandleInfo"}, - {0x2A, HLE::Wrap, "GetSystemInfo"}, - {0x2B, HLE::Wrap, "GetProcessInfo"}, + {0x2A, &SVC::Wrap<&SVC::GetSystemInfo>, "GetSystemInfo"}, + {0x2B, &SVC::Wrap<&SVC::GetProcessInfo>, "GetProcessInfo"}, {0x2C, nullptr, "GetThreadInfo"}, - {0x2D, HLE::Wrap, "ConnectToPort"}, + {0x2D, &SVC::Wrap<&SVC::ConnectToPort>, "ConnectToPort"}, {0x2E, nullptr, "SendSyncRequest1"}, {0x2F, nullptr, "SendSyncRequest2"}, {0x30, nullptr, "SendSyncRequest3"}, {0x31, nullptr, "SendSyncRequest4"}, - {0x32, HLE::Wrap, "SendSyncRequest"}, + {0x32, &SVC::Wrap<&SVC::SendSyncRequest>, "SendSyncRequest"}, {0x33, nullptr, "OpenProcess"}, {0x34, nullptr, "OpenThread"}, - {0x35, HLE::Wrap, "GetProcessId"}, - {0x36, HLE::Wrap, "GetProcessIdOfThread"}, - {0x37, HLE::Wrap, "GetThreadId"}, - {0x38, HLE::Wrap, "GetResourceLimit"}, - {0x39, HLE::Wrap, "GetResourceLimitLimitValues"}, - {0x3A, HLE::Wrap, "GetResourceLimitCurrentValues"}, + {0x35, &SVC::Wrap<&SVC::GetProcessId>, "GetProcessId"}, + {0x36, &SVC::Wrap<&SVC::GetProcessIdOfThread>, "GetProcessIdOfThread"}, + {0x37, &SVC::Wrap<&SVC::GetThreadId>, "GetThreadId"}, + {0x38, &SVC::Wrap<&SVC::GetResourceLimit>, "GetResourceLimit"}, + {0x39, &SVC::Wrap<&SVC::GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"}, + {0x3A, &SVC::Wrap<&SVC::GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, {0x3B, nullptr, "GetThreadContext"}, - {0x3C, HLE::Wrap, "Break"}, - {0x3D, HLE::Wrap, "OutputDebugString"}, + {0x3C, &SVC::Wrap<&SVC::Break>, "Break"}, + {0x3D, &SVC::Wrap<&SVC::OutputDebugString>, "OutputDebugString"}, {0x3E, nullptr, "ControlPerformanceCounter"}, {0x3F, nullptr, "Unknown"}, {0x40, nullptr, "Unknown"}, @@ -1401,15 +1478,15 @@ static const FunctionDef SVC_Table[] = { {0x44, nullptr, "Unknown"}, {0x45, nullptr, "Unknown"}, {0x46, nullptr, "Unknown"}, - {0x47, HLE::Wrap, "CreatePort"}, - {0x48, HLE::Wrap, "CreateSessionToPort"}, - {0x49, HLE::Wrap, "CreateSession"}, - {0x4A, HLE::Wrap, "AcceptSession"}, + {0x47, &SVC::Wrap<&SVC::CreatePort>, "CreatePort"}, + {0x48, &SVC::Wrap<&SVC::CreateSessionToPort>, "CreateSessionToPort"}, + {0x49, &SVC::Wrap<&SVC::CreateSession>, "CreateSession"}, + {0x4A, &SVC::Wrap<&SVC::AcceptSession>, "AcceptSession"}, {0x4B, nullptr, "ReplyAndReceive1"}, {0x4C, nullptr, "ReplyAndReceive2"}, {0x4D, nullptr, "ReplyAndReceive3"}, {0x4E, nullptr, "ReplyAndReceive4"}, - {0x4F, HLE::Wrap, "ReplyAndReceive"}, + {0x4F, &SVC::Wrap<&SVC::ReplyAndReceive>, "ReplyAndReceive"}, {0x50, nullptr, "BindInterrupt"}, {0x51, nullptr, "UnbindInterrupt"}, {0x52, nullptr, "InvalidateProcessDataCache"}, @@ -1455,10 +1532,10 @@ static const FunctionDef SVC_Table[] = { {0x7A, nullptr, "AddCodeSegment"}, {0x7B, nullptr, "Backdoor"}, {0x7C, nullptr, "KernelSetState"}, - {0x7D, HLE::Wrap, "QueryProcessMemory"}, + {0x7D, &SVC::Wrap<&SVC::QueryProcessMemory>, "QueryProcessMemory"}, }; -static const FunctionDef* GetSVCInfo(u32 func_num) { +const SVC::FunctionDef* SVC::GetSVCInfo(u32 func_num) { if (func_num >= ARRAY_SIZE(SVC_Table)) { LOG_ERROR(Kernel_SVC, "unknown svc=0x{:02X}", func_num); return nullptr; @@ -1468,24 +1545,40 @@ static const FunctionDef* GetSVCInfo(u32 func_num) { MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); -void CallSVC(u32 immediate) { +void SVC::CallSVC(u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); // Lock the global kernel mutex when we enter the kernel HLE. std::lock_guard lock(HLE::g_hle_lock); - DEBUG_ASSERT_MSG(Core::System::GetInstance().Kernel().GetCurrentProcess()->status == - ProcessStatus::Running, + DEBUG_ASSERT_MSG(kernel.GetCurrentProcess()->status == ProcessStatus::Running, "Running threads from exiting processes is unimplemented"); const FunctionDef* info = GetSVCInfo(immediate); if (info) { if (info->func) { - info->func(); + (this->*(info->func))(); } else { LOG_ERROR(Kernel_SVC, "unimplemented SVC function {}(..)", info->name); } } } +SVC::SVC(Core::System& system) : system(system), kernel(system.Kernel()) {} + +u32 SVC::GetReg(std::size_t n) { + return system.CPU().GetReg(static_cast(n)); +} + +void SVC::SetReg(std::size_t n, u32 value) { + system.CPU().SetReg(static_cast(n), value); +} + +SVCContext::SVCContext(Core::System& system) : impl(std::make_unique(system)) {} +SVCContext::~SVCContext() = default; + +void SVCContext::CallSVC(u32 immediate) { + impl->CallSVC(immediate); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index 94f1933f5..efddff9e8 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h @@ -4,50 +4,25 @@ #pragma once +#include #include "common/common_types.h" +namespace Core { +class System; +} // namespace Core + namespace Kernel { -struct MemoryInfo { - u32 base_address; - u32 size; - u32 permission; - u32 state; -}; +class SVC; -struct PageInfo { - u32 flags; -}; +class SVCContext { +public: + SVCContext(Core::System& system); + ~SVCContext(); + void CallSVC(u32 immediate); -/// Values accepted by svcGetSystemInfo's type parameter. -enum class SystemInfoType { - /** - * Reports total used memory for all regions or a specific one, according to the extra - * parameter. See `SystemInfoMemUsageRegion`. - */ - REGION_MEMORY_USAGE = 0, - /** - * Returns the memory usage for certain allocations done internally by the kernel. - */ - KERNEL_ALLOCATED_PAGES = 2, - /** - * "This returns the total number of processes which were launched directly by the kernel. - * For the ARM11 NATIVE_FIRM kernel, this is 5, for processes sm, fs, pm, loader, and pxi." - */ - KERNEL_SPAWNED_PIDS = 26, +private: + std::unique_ptr impl; }; -/** - * Accepted by svcGetSystemInfo param with REGION_MEMORY_USAGE type. Selects a region to query - * memory usage of. - */ -enum class SystemInfoMemUsageRegion { - ALL = 0, - APPLICATION = 1, - SYSTEM = 2, - BASE = 3, -}; - -void CallSVC(u32 immediate); - } // namespace Kernel diff --git a/src/core/hle/kernel/svc_wrapper.h b/src/core/hle/kernel/svc_wrapper.h new file mode 100644 index 000000000..b4fbbe0de --- /dev/null +++ b/src/core/hle/kernel/svc_wrapper.h @@ -0,0 +1,294 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "common/common_types.h" + +namespace Kernel { + +/* + * This class defines the SVC ABI, and provides a wrapper template for translating between ARM + * registers and SVC parameters and return value. The SVC context class should inherit from this + * class using CRTP (`class SVC : public SVCWrapper {...}`), and use the Wrap() template to + * convert a SVC function interface to a void()-type function that interacts with registers + * interface GetReg() and SetReg(). + */ +template +class SVCWrapper { +protected: + template + void Wrap() { + WrapHelper::Call(*static_cast(this), F); + }; + +private: + // A special param index represents the return value + static constexpr std::size_t INDEX_RETURN = ~(std::size_t)0; + + struct ParamSlot { + // whether the slot is used for a param + bool used; + + // index of a param in the function signature, starting from 0, or special value + // INDEX_RETURN + std::size_t param_index; + + // index of a 32-bit word within the param + std::size_t word_index; + }; + + // Size in words of the given type in ARM ABI + template + static constexpr std::size_t WordSize() { + static_assert(std::is_trivially_copyable_v); + if constexpr (std::is_pointer_v) { + return 1; + } else if constexpr (std::is_same_v) { + return 1; + } else { + return (sizeof(T) - 1) / 4 + 1; + } + } + + // Size in words of the given type in ARM ABI with pointer removed + template + static constexpr std::size_t OutputWordSize() { + if constexpr (std::is_pointer_v) { + return WordSize>(); + } else { + return 0; + } + } + + // Describes the register assignments of a SVC + struct SVCABI { + static constexpr std::size_t RegCount = 8; + + // Register assignments for input params. + // For example, in[0] records which input param and word r0 stores + std::array in{}; + + // Register assignments for output params. + // For example, out[0] records which output param (with pointer removed) and word r0 stores + std::array out{}; + + // Search the register assignments for a word of a param + constexpr std::size_t GetRegisterIndex(std::size_t param_index, + std::size_t word_index) const { + for (std::size_t slot = 0; slot < RegCount; ++slot) { + if (in[slot].used && in[slot].param_index == param_index && + in[slot].word_index == word_index) { + return slot; + } + if (out[slot].used && out[slot].param_index == param_index && + out[slot].word_index == word_index) { + return slot; + } + } + // should throw, but gcc bugs out here + return 0x12345678; + } + }; + + // Generates ABI info for a given SVC signature R(Context::)(T...) + template + static constexpr SVCABI GetSVCABI() { + constexpr std::size_t param_count = sizeof...(T); + std::array param_is_output{{std::is_pointer_v...}}; + std::array param_size{{WordSize()...}}; + std::array output_param_size{{OutputWordSize()...}}; + std::array param_need_align{ + {(std::is_same_v || std::is_same_v)...}}; + + // derives ARM ABI, which assigns all params to r0~r3 and then stack + std::array armabi_reg{}; + std::array armabi_stack{}; + std::size_t reg_pos = 0; + std::size_t stack_pos = 0; + for (std::size_t i = 0; i < param_count; ++i) { + if (param_need_align[i]) { + reg_pos += reg_pos % 2; + } + for (std::size_t j = 0; j < param_size[i]; ++j) { + if (reg_pos == 4) { + armabi_stack[stack_pos++] = ParamSlot{true, i, j}; + } else { + armabi_reg[reg_pos++] = ParamSlot{true, i, j}; + } + } + } + + // now derives SVC ABI which is a modified version of ARM ABI + + SVCABI mod_abi{}; + std::size_t out_pos = 0; // next available output register + + // assign return value to output registers + if constexpr (!std::is_void_v) { + for (std::size_t j = 0; j < WordSize(); ++j) { + mod_abi.out[out_pos++] = {true, INDEX_RETURN, j}; + } + } + + // assign output params (pointer-type params) to output registers + for (std::size_t i = 0; i < param_count; ++i) { + if (param_is_output[i]) { + for (std::size_t j = 0; j < output_param_size[i]; ++j) { + mod_abi.out[out_pos++] = ParamSlot{true, i, j}; + } + } + } + + // assign input params (non-pointer-type params) to input registers + stack_pos = 0; // next available stack param + for (std::size_t k = 0; k < mod_abi.in.size(); ++k) { + if (k < armabi_reg.size() && armabi_reg[k].used && + !param_is_output[armabi_reg[k].param_index]) { + // If this is within the ARM ABI register range and it is a used input param, use + // the same register position + mod_abi.in[k] = armabi_reg[k]; + } else { + // Otherwise, assign it with the next available stack input + // If all stack inputs have been allocated, this would do nothing + // and leaves the slot unused. + // Loop until an input stack param is found + while (stack_pos < armabi_stack.size() && + (!armabi_stack[stack_pos].used || + param_is_output[armabi_stack[stack_pos].param_index])) { + ++stack_pos; + } + // Reassign the stack param to the free register + if (stack_pos < armabi_stack.size()) { + mod_abi.in[k] = armabi_stack[stack_pos++]; + } + } + } + + return mod_abi; + } + + template + static constexpr std::array GetRegIndicesImpl( + SVCABI abi, std::index_sequence) { + return {{abi.GetRegisterIndex(param_index, indices)...}}; + } + + // Gets assigned register index for the param_index-th param of word_size in a function with + // signature R(Context::)(Ts...) + template + static constexpr std::array GetRegIndices() { + constexpr SVCABI abi = GetSVCABI(); + return GetRegIndicesImpl(abi, + std::make_index_sequence{}); + } + + // Gets the value for the param_index-th param of word_size in a function with signature + // R(Context::)(Ts...) + // T is the param type, which must be a non-pointer as it is an input param. + // Must hold: Ts[param_index] == T + template + static void GetParam(Context& context, T& value) { + static_assert(!std::is_pointer_v, "T should not be a pointer"); + constexpr auto regi = GetRegIndices(), R, Ts...>(); + if constexpr (std::is_class_v || std::is_union_v) { + std::array()> buf; + for (std::size_t i = 0; i < WordSize(); ++i) { + buf[i] = context.GetReg(regi[i]); + } + std::memcpy(&value, &buf, sizeof(T)); + } else if constexpr (WordSize() == 2) { + u64 l = context.GetReg(regi[0]); + u64 h = context.GetReg(regi[1]); + value = static_cast(l | (h << 32)); + } else if constexpr (std::is_same_v) { + // TODO: Is this correct or should only test the lowest byte? + value = context.GetReg(regi[0]) != 0; + } else { + value = static_cast(context.GetReg(regi[0])); + } + } + + // Sets the value for the param_index-th param of word_size in a function with signature + // R(Context::)(Ts...) + // T is the param type with pointer removed, which was originally a pointer-type output param + // Must hold: (Ts[param_index] == T*) || (R==T && param_index == INDEX_RETURN) + template + static void SetParam(Context& context, const T& value) { + static_assert(!std::is_pointer_v, "T should have pointer removed before passing in"); + constexpr auto regi = GetRegIndices(), R, Ts...>(); + if constexpr (std::is_class_v || std::is_union_v) { + std::array()> buf; + std::memcpy(&buf, &value, sizeof(T)); + for (std::size_t i = 0; i < WordSize(); ++i) { + context.SetReg(regi[i], buf[i]); + } + } else if constexpr (WordSize() == 2) { + u64 u = static_cast(value); + context.SetReg(regi[0], static_cast(u & 0xFFFFFFFF)); + context.SetReg(regi[1], static_cast(u >> 32)); + } else { + u32 u = static_cast(value); + context.SetReg(regi[0], u); + } + } + + template + struct WrapPass; + + template + struct WrapPass { + // Do I/O for the param T in function R(Context::svc)(Us..., T, Ts...) and then move on to + // the next param. + + // Us are params whose I/O is already handled. + // T is the current param to do I/O. + // Ts are params whose I/O is not handled yet. + template + static void Call(Context& context, SVCT svc, Us... u) { + static_assert(std::is_same_v); + constexpr std::size_t current_param_index = sizeof...(Us); + if constexpr (std::is_pointer_v) { + using OutputT = std::remove_pointer_t; + OutputT output; + WrapPass::Call(context, svc, u..., &output); + SetParam(context, output); + } else { + T input; + GetParam(context, input); + WrapPass::Call(context, svc, u..., input); + } + } + }; + + template + struct WrapPass { + // Call function R(Context::svc)(Us...) and transfer the return value to registers + template + static void Call(Context& context, SVCT svc, Us... u) { + static_assert(std::is_same_v); + if constexpr (std::is_void_v) { + (context.*svc)(u...); + } else { + R r = (context.*svc)(u...); + SetParam(context, r); + } + } + }; + + template + struct WrapHelper; + + template + struct WrapHelper { + static void Call(Context& context, R (Context::*svc)(T...)) { + WrapPass::Call(context, svc /*Empty for Us*/); + } + }; +}; + +} // namespace Kernel diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 47b6e2b23..1543d7bd8 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -216,10 +216,7 @@ union ResultCode { : raw(description.FormatValue(description_) | module.FormatValue(module_) | summary.FormatValue(summary_) | level.FormatValue(level_)) {} - constexpr ResultCode& operator=(const ResultCode& o) { - raw = o.raw; - return *this; - } + constexpr ResultCode& operator=(const ResultCode& o) = default; constexpr bool IsSuccess() const { return is_error.ExtractValue(raw) == 0;