mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	SVC: use context and generic templates
This commit is contained in:
		
							parent
							
								
									28513c5177
								
							
						
					
					
						commit
						aec8b1e375
					
				
					 8 changed files with 568 additions and 483 deletions
				
			
		|  | @ -116,7 +116,6 @@ add_library(core STATIC | |||
|     hle/kernel/errors.h | ||||
|     hle/kernel/event.cpp | ||||
|     hle/kernel/event.h | ||||
|     hle/kernel/function_wrappers.h | ||||
|     hle/kernel/handle_table.cpp | ||||
|     hle/kernel/handle_table.h | ||||
|     hle/kernel/hle_ipc.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 | ||||
|  |  | |||
|  | @ -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::SVC svc_context; | ||||
| }; | ||||
| 
 | ||||
| ARM_Dynarmic::ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode) | ||||
|  |  | |||
|  | @ -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::SVC{Core::System::GetInstance()}.CallSVC(inst_cream->num & 0xFFFF); | ||||
|         // The kernel would call ERET to get here, which clears exclusive memory state.
 | ||||
|         cpu->UnsetExclusiveMemoryAddress(); | ||||
|     } | ||||
|  |  | |||
|  | @ -172,6 +172,8 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { | |||
| 
 | ||||
|     timing = std::make_unique<Timing>(); | ||||
| 
 | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>(system_mode); | ||||
| 
 | ||||
|     if (Settings::values.use_cpu_jit) { | ||||
| #ifdef ARCHITECTURE_x86_64 | ||||
|         cpu_core = std::make_unique<ARM_Dynarmic>(*this, USER32MODE); | ||||
|  | @ -197,7 +199,6 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { | |||
|     archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this); | ||||
| 
 | ||||
|     HW::Init(); | ||||
|     kernel = std::make_unique<Kernel::KernelSystem>(system_mode); | ||||
|     Service::Init(*this); | ||||
|     GDBStub::Init(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 <ResultCode func(u32, u32, u32, u32)> | ||||
| void Wrap() { | ||||
|     FuncReturn(func(Param(0), Param(1), Param(2), Param(3)).raw); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(u32*, u32, u32, u32, u32, u32)> | ||||
| 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 <ResultCode func(u32*, u32, u32, u32, u32, s32)> | ||||
| 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 <ResultCode func(s32*, VAddr, s32, bool, s64)> | ||||
| 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 <ResultCode func(s32*, VAddr, s32, u32)> | ||||
| 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 <ResultCode func(u32, u32, u32, u32, s64)> | ||||
| void Wrap() { | ||||
|     FuncReturn( | ||||
|         func(Param(0), Param(1), Param(2), Param(3), (((s64)Param(5) << 32) | Param(4))).raw); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(u32*)> | ||||
| void Wrap() { | ||||
|     u32 param_1 = 0; | ||||
|     u32 retval = func(¶m_1).raw; | ||||
|     Core::CPU().SetReg(1, param_1); | ||||
|     FuncReturn(retval); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(u32, s64)> | ||||
| void Wrap() { | ||||
|     s32 retval = func(Param(0), (((s64)Param(3) << 32) | Param(2))).raw; | ||||
| 
 | ||||
|     FuncReturn(retval); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(Kernel::MemoryInfo*, Kernel::PageInfo*, u32)> | ||||
| 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 <ResultCode func(Kernel::MemoryInfo*, Kernel::PageInfo*, Kernel::Handle, u32)> | ||||
| 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 <ResultCode func(s32*, u32)> | ||||
| void Wrap() { | ||||
|     s32 param_1 = 0; | ||||
|     u32 retval = func(¶m_1, Param(1)).raw; | ||||
|     Core::CPU().SetReg(1, param_1); | ||||
|     FuncReturn(retval); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(u32, s32)> | ||||
| void Wrap() { | ||||
|     FuncReturn(func(Param(0), (s32)Param(1)).raw); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(u32*, u32)> | ||||
| void Wrap() { | ||||
|     u32 param_1 = 0; | ||||
|     u32 retval = func(¶m_1, Param(1)).raw; | ||||
|     Core::CPU().SetReg(1, param_1); | ||||
|     FuncReturn(retval); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(u32)> | ||||
| void Wrap() { | ||||
|     FuncReturn(func(Param(0)).raw); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(u32*, s32, s32)> | ||||
| 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 <ResultCode func(s32*, u32, s32)> | ||||
| 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 <ResultCode func(s64*, u32, s32)> | ||||
| 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 <ResultCode func(u32*, u32, u32, u32, u32)> | ||||
| 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 <ResultCode func(u32, s64, s64)> | ||||
| 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 <ResultCode func(s64*, Kernel::Handle, u32)> | ||||
| 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 <ResultCode func(Kernel::Handle, u32)> | ||||
| void Wrap() { | ||||
|     FuncReturn(func(Param(0), Param(1)).raw); | ||||
| } | ||||
| 
 | ||||
| template <ResultCode func(Kernel::Handle*, Kernel::Handle*, VAddr, u32)> | ||||
| 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 <ResultCode func(Kernel::Handle*, Kernel::Handle*)> | ||||
| 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 <u32 func()> | ||||
| void Wrap() { | ||||
|     FuncReturn(func()); | ||||
| } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Function wrappers that return type s64
 | ||||
| 
 | ||||
| template <s64 func()> | ||||
| void Wrap() { | ||||
|     FuncReturn64(func()); | ||||
| } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| /// Function wrappers that return type void
 | ||||
| 
 | ||||
| template <void func(s64)> | ||||
| void Wrap() { | ||||
|     func(((s64)Param(1) << 32) | Param(0)); | ||||
| } | ||||
| 
 | ||||
| template <void func(VAddr, int len)> | ||||
| void Wrap() { | ||||
|     func(Param(0), Param(1)); | ||||
| } | ||||
| 
 | ||||
| template <void func(u8)> | ||||
| void Wrap() { | ||||
|     func((u8)Param(0)); | ||||
| } | ||||
| 
 | ||||
| } // namespace HLE
 | ||||
|  | @ -10,13 +10,13 @@ | |||
| #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/kernel/address_arbiter.h" | ||||
| #include "core/hle/kernel/client_port.h" | ||||
| #include "core/hle/kernel/client_session.h" | ||||
| #include "core/hle/kernel/errors.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/kernel/function_wrappers.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/ipc.h" | ||||
| #include "core/hle/kernel/memory.h" | ||||
|  | @ -28,6 +28,7 @@ | |||
| #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/thread.h" | ||||
| #include "core/hle/kernel/timer.h" | ||||
| #include "core/hle/kernel/vm_manager.h" | ||||
|  | @ -56,8 +57,8 @@ enum ControlMemoryOperation { | |||
| }; | ||||
| 
 | ||||
| /// 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 +84,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 +141,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<Process> current_process = kernel.GetCurrentProcess(); | ||||
|     LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->process_id); | ||||
| 
 | ||||
|  | @ -169,19 +169,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<SharedMemory> shared_memory = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<SharedMemory>( | ||||
|             handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<SharedMemory>(handle); | ||||
|     if (shared_memory == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -195,8 +194,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<MemoryPermission>(other_permissions)); | ||||
|     default: | ||||
|         LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); | ||||
|  | @ -205,12 +203,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<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
|     SharedPtr<SharedMemory> shared_memory = current_process->handle_table.Get<SharedMemory>(handle); | ||||
|     if (shared_memory == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
|  | @ -219,7 +217,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 +229,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 +246,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<ClientSession> session = | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<ClientSession>(handle); | ||||
|     if (session == nullptr) { | ||||
|  | @ -260,20 +255,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<WaitObject>(handle); | ||||
|     Thread* thread = kernel.GetThreadManager().GetCurrentThread(); | ||||
| 
 | ||||
|  | @ -311,7 +305,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 +319,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 +393,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 +453,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 +491,8 @@ static ResultCode ReceiveIPCRequest(SharedPtr<ServerSession> 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 +503,6 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ | |||
|     using ObjectPtr = SharedPtr<WaitObject>; | ||||
|     std::vector<ObjectPtr> objects(handle_count); | ||||
| 
 | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
| 
 | ||||
|     for (int i = 0; i < handle_count; ++i) { | ||||
|  | @ -614,7 +606,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 +616,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<AddressArbiter> arbiter = kernel.CreateAddressArbiter(); | ||||
|     CASCADE_RESULT(*out_handle, | ||||
|                    kernel.GetCurrentProcess()->handle_table.Create(std::move(arbiter))); | ||||
|  | @ -634,13 +625,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<AddressArbiter> arbiter = | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<AddressArbiter>(handle); | ||||
|     if (arbiter == nullptr) | ||||
|  | @ -651,12 +639,12 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val | |||
|                                   static_cast<ArbitrationType>(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 +665,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 +676,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<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
|     SharedPtr<Process> process = current_process->handle_table.Get<Process>(process_handle); | ||||
|     if (process == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
|  | @ -702,14 +690,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<ResourceLimit> resource_limit = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<ResourceLimit>( | ||||
|             resource_limit_handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(resource_limit_handle); | ||||
|     if (resource_limit == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -723,14 +710,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<ResourceLimit> resource_limit = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<ResourceLimit>( | ||||
|             resource_limit_handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<ResourceLimit>(resource_limit_handle); | ||||
|     if (resource_limit == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -744,15 +730,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<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
| 
 | ||||
|     SharedPtr<ResourceLimit>& resource_limit = current_process->resource_limit; | ||||
|     if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { | ||||
|  | @ -782,16 +768,16 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point | |||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     CASCADE_RESULT(SharedPtr<Thread> thread, Core::System::GetInstance().Kernel().CreateThread( | ||||
|                                                  name, entry_point, priority, arg, processor_id, | ||||
|                                                  stack_top, *current_process)); | ||||
|     CASCADE_RESULT(SharedPtr<Thread> 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 +788,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> thread = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>(handle); | ||||
| ResultCode SVC::GetThreadPriority(u32* priority, Handle handle) { | ||||
|     const SharedPtr<Thread> thread = kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle); | ||||
|     if (thread == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -821,20 +806,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> thread = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>(handle); | ||||
|     SharedPtr<Thread> thread = kernel.GetCurrentProcess()->handle_table.Get<Thread>(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<ResourceLimit>& resource_limit = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->resource_limit; | ||||
|     SharedPtr<ResourceLimit>& resource_limit = kernel.GetCurrentProcess()->resource_limit; | ||||
|     if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { | ||||
|         return ERR_NOT_AUTHORIZED; | ||||
|     } | ||||
|  | @ -846,15 +829,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> 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 +846,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> mutex = kernel.GetCurrentProcess()->handle_table.Get<Mutex>(handle); | ||||
|     if (mutex == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
|  | @ -877,12 +857,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> process = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Process>( | ||||
|             process_handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); | ||||
|     if (process == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -891,12 +870,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> thread = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>( | ||||
|             thread_handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<Thread>(thread_handle); | ||||
|     if (thread == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -909,11 +887,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> thread = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Thread>(handle); | ||||
|     const SharedPtr<Thread> thread = kernel.GetCurrentProcess()->handle_table.Get<Thread>(handle); | ||||
|     if (thread == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -922,11 +899,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> 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 +912,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> semaphore = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Semaphore>( | ||||
|             handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<Semaphore>(handle); | ||||
|     if (semaphore == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -951,11 +926,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> process = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Process>( | ||||
|             process_handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); | ||||
|     if (process == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -975,15 +949,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<Event> evt = kernel.CreateEvent(static_cast<ResetType>(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 +965,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<Event> evt = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Event>(handle); | ||||
|     SharedPtr<Event> evt = kernel.GetCurrentProcess()->handle_table.Get<Event>(handle); | ||||
|     if (evt == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -1015,11 +985,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<Event> evt = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Event>(handle); | ||||
|     SharedPtr<Event> evt = kernel.GetCurrentProcess()->handle_table.Get<Event>(handle); | ||||
|     if (evt == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -1028,10 +997,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> timer = kernel.CreateTimer( | ||||
|         static_cast<ResetType>(reset_type), fmt ::format("timer-{:08x}", Core::CPU().GetReg(14))); | ||||
|         static_cast<ResetType>(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 +1008,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> timer = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Timer>(handle); | ||||
|     SharedPtr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle); | ||||
|     if (timer == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -1053,15 +1020,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> timer = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Timer>(handle); | ||||
|     SharedPtr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle); | ||||
|     if (timer == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -1071,11 +1037,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> timer = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Timer>(handle); | ||||
|     SharedPtr<Timer> timer = kernel.GetCurrentProcess()->handle_table.Get<Timer>(handle); | ||||
|     if (timer == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -1085,10 +1050,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 +1066,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 +1112,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 | |||
|         return ERR_INVALID_ADDRESS; | ||||
|     } | ||||
| 
 | ||||
|     SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     SharedPtr<Process> 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 +1122,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<MemoryPermission>(my_permission), | ||||
|         static_cast<MemoryPermission>(other_permission), addr, region); | ||||
|     CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(shared_memory))); | ||||
|  | @ -1167,12 +1131,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<Process> current_process = kernel.GetCurrentProcess(); | ||||
| 
 | ||||
|     auto ports = kernel.CreatePortPair(max_sessions); | ||||
|  | @ -1187,8 +1150,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<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
| ResultCode SVC::CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) { | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
|     SharedPtr<ClientPort> client_port = | ||||
|         current_process->handle_table.Get<ClientPort>(client_port_handle); | ||||
|     if (client_port == nullptr) | ||||
|  | @ -1199,8 +1162,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<Process> current_process = kernel.GetCurrentProcess(); | ||||
|  | @ -1215,8 +1177,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<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
| ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_handle) { | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
|     SharedPtr<ServerPort> server_port = | ||||
|         current_process->handle_table.Get<ServerPort>(server_port_handle); | ||||
|     if (server_port == nullptr) | ||||
|  | @ -1227,11 +1189,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 +1232,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> process = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Process>( | ||||
|             process_handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<Process>(process_handle); | ||||
|     if (process == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|  | @ -1319,79 +1278,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>, "ControlMemory"}, | ||||
|     {0x02, HLE::Wrap<QueryMemory>, "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>, "CreateThread"}, | ||||
|     {0x09, ExitThread, "ExitThread"}, | ||||
|     {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, | ||||
|     {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, | ||||
|     {0x0C, HLE::Wrap<SetThreadPriority>, "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>, "CreateMutex"}, | ||||
|     {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"}, | ||||
|     {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"}, | ||||
|     {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"}, | ||||
|     {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, | ||||
|     {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, | ||||
|     {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, | ||||
|     {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"}, | ||||
|     {0x1B, HLE::Wrap<SetTimer>, "SetTimer"}, | ||||
|     {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"}, | ||||
|     {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"}, | ||||
|     {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"}, | ||||
|     {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"}, | ||||
|     {0x20, HLE::Wrap<UnmapMemoryBlock>, "UnmapMemoryBlock"}, | ||||
|     {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"}, | ||||
|     {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"}, | ||||
|     {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"}, | ||||
|     {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"}, | ||||
|     {0x25, HLE::Wrap<WaitSynchronizationN>, "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>, "DuplicateHandle"}, | ||||
|     {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, | ||||
|     {0x27, &SVC::Wrap<&SVC::DuplicateHandle>, "DuplicateHandle"}, | ||||
|     {0x28, &SVC::Wrap<&SVC::GetSystemTick>, "GetSystemTick"}, | ||||
|     {0x29, nullptr, "GetHandleInfo"}, | ||||
|     {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"}, | ||||
|     {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"}, | ||||
|     {0x2A, &SVC::Wrap<&SVC::GetSystemInfo>, "GetSystemInfo"}, | ||||
|     {0x2B, &SVC::Wrap<&SVC::GetProcessInfo>, "GetProcessInfo"}, | ||||
|     {0x2C, nullptr, "GetThreadInfo"}, | ||||
|     {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, | ||||
|     {0x2D, &SVC::Wrap<&SVC::ConnectToPort>, "ConnectToPort"}, | ||||
|     {0x2E, nullptr, "SendSyncRequest1"}, | ||||
|     {0x2F, nullptr, "SendSyncRequest2"}, | ||||
|     {0x30, nullptr, "SendSyncRequest3"}, | ||||
|     {0x31, nullptr, "SendSyncRequest4"}, | ||||
|     {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"}, | ||||
|     {0x32, &SVC::Wrap<&SVC::SendSyncRequest>, "SendSyncRequest"}, | ||||
|     {0x33, nullptr, "OpenProcess"}, | ||||
|     {0x34, nullptr, "OpenThread"}, | ||||
|     {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"}, | ||||
|     {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"}, | ||||
|     {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, | ||||
|     {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, | ||||
|     {0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"}, | ||||
|     {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "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>, "Break"}, | ||||
|     {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"}, | ||||
|     {0x3C, &SVC::Wrap<&SVC::Break>, "Break"}, | ||||
|     {0x3D, &SVC::Wrap<&SVC::OutputDebugString>, "OutputDebugString"}, | ||||
|     {0x3E, nullptr, "ControlPerformanceCounter"}, | ||||
|     {0x3F, nullptr, "Unknown"}, | ||||
|     {0x40, nullptr, "Unknown"}, | ||||
|  | @ -1401,15 +1350,15 @@ static const FunctionDef SVC_Table[] = { | |||
|     {0x44, nullptr, "Unknown"}, | ||||
|     {0x45, nullptr, "Unknown"}, | ||||
|     {0x46, nullptr, "Unknown"}, | ||||
|     {0x47, HLE::Wrap<CreatePort>, "CreatePort"}, | ||||
|     {0x48, HLE::Wrap<CreateSessionToPort>, "CreateSessionToPort"}, | ||||
|     {0x49, HLE::Wrap<CreateSession>, "CreateSession"}, | ||||
|     {0x4A, HLE::Wrap<AcceptSession>, "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>, "ReplyAndReceive"}, | ||||
|     {0x4F, &SVC::Wrap<&SVC::ReplyAndReceive>, "ReplyAndReceive"}, | ||||
|     {0x50, nullptr, "BindInterrupt"}, | ||||
|     {0x51, nullptr, "UnbindInterrupt"}, | ||||
|     {0x52, nullptr, "InvalidateProcessDataCache"}, | ||||
|  | @ -1455,10 +1404,10 @@ static const FunctionDef SVC_Table[] = { | |||
|     {0x7A, nullptr, "AddCodeSegment"}, | ||||
|     {0x7B, nullptr, "Backdoor"}, | ||||
|     {0x7C, nullptr, "KernelSetState"}, | ||||
|     {0x7D, HLE::Wrap<QueryProcessMemory>, "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 +1417,33 @@ 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<std::recursive_mutex> 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<int>(n)); | ||||
| } | ||||
| 
 | ||||
| void SVC::SetReg(std::size_t n, u32 value) { | ||||
|     system.CPU().SetReg(static_cast<int>(n), value); | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -5,9 +5,20 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/svc_wrapper.h" | ||||
| #include "core/hle/result.h" | ||||
| 
 | ||||
| class ARM_Interface; | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
| } // namespace Core
 | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class KernelSystem; | ||||
| 
 | ||||
| struct MemoryInfo { | ||||
|     u32 base_address; | ||||
|     u32 size; | ||||
|  | @ -48,6 +59,91 @@ enum class SystemInfoMemUsageRegion { | |||
|     BASE = 3, | ||||
| }; | ||||
| 
 | ||||
| void CallSVC(u32 immediate); | ||||
| class SVC : public SVCWrapper<SVC> { | ||||
| public: | ||||
|     SVC(Core::System& system); | ||||
|     void CallSVC(u32 immediate); | ||||
| 
 | ||||
| private: | ||||
|     Core::System& system; | ||||
|     Kernel::KernelSystem& kernel; | ||||
| 
 | ||||
|     friend class SVCWrapper<SVC>; | ||||
| 
 | ||||
|     // 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); | ||||
| }; | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
							
								
								
									
										294
									
								
								src/core/hle/kernel/svc_wrapper.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								src/core/hle/kernel/svc_wrapper.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <array> | ||||
| #include <cstring> | ||||
| #include <type_traits> | ||||
| #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<SVC> {...}`), 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 <typename Context> | ||||
| class SVCWrapper { | ||||
| protected: | ||||
|     template <auto F> | ||||
|     void Wrap() { | ||||
|         WrapHelper<decltype(F)>::Call(*static_cast<Context*>(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 <typename T> | ||||
|     static constexpr std::size_t WordSize() { | ||||
|         static_assert(std::is_trivially_copyable_v<T>); | ||||
|         if constexpr (std::is_pointer_v<T>) { | ||||
|             return 1; | ||||
|         } else if constexpr (std::is_same_v<T, bool>) { | ||||
|             return 1; | ||||
|         } else { | ||||
|             return (sizeof(T) - 1) / 4 + 1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Size in words of the given type in ARM ABI with pointer removed
 | ||||
|     template <typename T> | ||||
|     static constexpr std::size_t OutputWordSize() { | ||||
|         if constexpr (std::is_pointer_v<T>) { | ||||
|             return WordSize<std::remove_pointer_t<T>>(); | ||||
|         } 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<ParamSlot, RegCount> in{}; | ||||
| 
 | ||||
|         // Register assignments for output params.
 | ||||
|         // For example, out[0] records which output param (with pointer removed) and word r0 stores
 | ||||
|         std::array<ParamSlot, RegCount> 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 <typename R, typename... T> | ||||
|     static constexpr SVCABI GetSVCABI() { | ||||
|         constexpr std::size_t param_count = sizeof...(T); | ||||
|         std::array<bool, param_count> param_is_output{{std::is_pointer_v<T>...}}; | ||||
|         std::array<std::size_t, param_count> param_size{{WordSize<T>()...}}; | ||||
|         std::array<std::size_t, param_count> output_param_size{{OutputWordSize<T>()...}}; | ||||
|         std::array<bool, param_count> param_need_align{ | ||||
|             {(std::is_same_v<T, u64> || std::is_same_v<T, s64>)...}}; | ||||
| 
 | ||||
|         // derives ARM ABI, which assigns all params to r0~r3 and then stack
 | ||||
|         std::array<ParamSlot, 4> armabi_reg{}; | ||||
|         std::array<ParamSlot, 4> 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<R>) { | ||||
|             for (std::size_t j = 0; j < WordSize<R>(); ++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 <std::size_t param_index, std::size_t word_size, std::size_t... indices> | ||||
|     static constexpr std::array<std::size_t, word_size> GetRegIndicesImpl( | ||||
|         SVCABI abi, std::index_sequence<indices...>) { | ||||
|         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 <std::size_t param_index, std::size_t word_size, typename R, typename... Ts> | ||||
|     static constexpr std::array<std::size_t, word_size> GetRegIndices() { | ||||
|         constexpr SVCABI abi = GetSVCABI<R, Ts...>(); | ||||
|         return GetRegIndicesImpl<param_index, word_size>(abi, | ||||
|                                                          std::make_index_sequence<word_size>{}); | ||||
|     } | ||||
| 
 | ||||
|     // 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 <std::size_t param_index, typename T, typename R, typename... Ts> | ||||
|     static void GetParam(Context& context, T& value) { | ||||
|         static_assert(!std::is_pointer_v<T>, "T should not be a pointer"); | ||||
|         constexpr auto regi = GetRegIndices<param_index, WordSize<T>(), R, Ts...>(); | ||||
|         if constexpr (std::is_class_v<T> || std::is_union_v<T>) { | ||||
|             std::array<u32, WordSize<T>()> buf; | ||||
|             for (std::size_t i = 0; i < WordSize<T>(); ++i) { | ||||
|                 buf[i] = context.GetReg(regi[i]); | ||||
|             } | ||||
|             std::memcpy(&value, &buf, sizeof(T)); | ||||
|         } else if constexpr (WordSize<T>() == 2) { | ||||
|             u64 l = context.GetReg(regi[0]); | ||||
|             u64 h = context.GetReg(regi[1]); | ||||
|             value = static_cast<T>(l | (h << 32)); | ||||
|         } else if constexpr (std::is_same_v<T, bool>) { | ||||
|             // TODO: Is this correct or should only test the lowest byte?
 | ||||
|             value = context.GetReg(regi[0]) != 0; | ||||
|         } else { | ||||
|             value = static_cast<T>(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 <std::size_t param_index, typename T, typename R, typename... Ts> | ||||
|     static void SetParam(Context& context, const T& value) { | ||||
|         static_assert(!std::is_pointer_v<T>, "T should have pointer removed before passing in"); | ||||
|         constexpr auto regi = GetRegIndices<param_index, WordSize<T>(), R, Ts...>(); | ||||
|         if constexpr (std::is_class_v<T> || std::is_union_v<T>) { | ||||
|             std::array<u32, WordSize<T>()> buf; | ||||
|             std::memcpy(&buf, &value, sizeof(T)); | ||||
|             for (std::size_t i = 0; i < WordSize<T>(); ++i) { | ||||
|                 context.SetReg(regi[i], buf[i]); | ||||
|             } | ||||
|         } else if constexpr (WordSize<T>() == 2) { | ||||
|             u64 u = static_cast<u64>(value); | ||||
|             context.SetReg(regi[0], static_cast<u32>(u & 0xFFFFFFFF)); | ||||
|             context.SetReg(regi[1], static_cast<u32>(u >> 32)); | ||||
|         } else { | ||||
|             u32 u = static_cast<u32>(value); | ||||
|             context.SetReg(regi[0], u); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     template <typename SVCT, typename R, typename... Ts> | ||||
|     struct WrapPass; | ||||
| 
 | ||||
|     template <typename SVCT, typename R, typename T, typename... Ts> | ||||
|     struct WrapPass<SVCT, R, T, Ts...> { | ||||
|         // 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 <typename... Us> | ||||
|         static void Call(Context& context, SVCT svc, Us... u) { | ||||
|             static_assert(std::is_same_v<SVCT, R (Context::*)(Us..., T, Ts...)>); | ||||
|             constexpr std::size_t current_param_index = sizeof...(Us); | ||||
|             if constexpr (std::is_pointer_v<T>) { | ||||
|                 using OutputT = std::remove_pointer_t<T>; | ||||
|                 OutputT output; | ||||
|                 WrapPass<SVCT, R, Ts...>::Call(context, svc, u..., &output); | ||||
|                 SetParam<current_param_index, OutputT, R, Us..., T, Ts...>(context, output); | ||||
|             } else { | ||||
|                 T input; | ||||
|                 GetParam<current_param_index, T, R, Us..., T, Ts...>(context, input); | ||||
|                 WrapPass<SVCT, R, Ts...>::Call(context, svc, u..., input); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     template <typename SVCT, typename R> | ||||
|     struct WrapPass<SVCT, R /*empty for T, Ts...*/> { | ||||
|         // Call function R(Context::svc)(Us...) and transfer the return value to registers
 | ||||
|         template <typename... Us> | ||||
|         static void Call(Context& context, SVCT svc, Us... u) { | ||||
|             static_assert(std::is_same_v<SVCT, R (Context::*)(Us...)>); | ||||
|             if constexpr (std::is_void_v<R>) { | ||||
|                 (context.*svc)(u...); | ||||
|             } else { | ||||
|                 R r = (context.*svc)(u...); | ||||
|                 SetParam<INDEX_RETURN, R, R, Us...>(context, r); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     template <typename T> | ||||
|     struct WrapHelper; | ||||
| 
 | ||||
|     template <typename R, typename... T> | ||||
|     struct WrapHelper<R (Context::*)(T...)> { | ||||
|         static void Call(Context& context, R (Context::*svc)(T...)) { | ||||
|             WrapPass<decltype(svc), R, T...>::Call(context, svc /*Empty for Us*/); | ||||
|         } | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue