diff options
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 6406 |
1 files changed, 3856 insertions, 2550 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 788ee2160..1072da8cc 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1,3129 +1,4435 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <algorithm> -#include <cinttypes> -#include <iterator> -#include <mutex> -#include <vector> - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_funcs.h" -#include "common/fiber.h" -#include "common/logging/log.h" -#include "common/scope_exit.h" +// This file is automatically generated using svc_generator.py. + +#include <type_traits> + +#include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/core_timing.h" -#include "core/debugger/debugger.h" -#include "core/hle/kernel/k_client_port.h" -#include "core/hle/kernel/k_client_session.h" -#include "core/hle/kernel/k_code_memory.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_handle_table.h" -#include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/k_memory_layout.h" -#include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/k_session.h" -#include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/k_thread_queue.h" -#include "core/hle/kernel/k_transfer_memory.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/svc.h" -#include "core/hle/kernel/svc_results.h" -#include "core/hle/kernel/svc_types.h" -#include "core/hle/kernel/svc_wrap.h" -#include "core/hle/result.h" -#include "core/memory.h" -#include "core/reporter.h" namespace Kernel::Svc { -namespace { - -// Checks if address + size is greater than the given address -// This can return false if the size causes an overflow of a 64-bit type -// or if the given size is zero. -constexpr bool IsValidAddressRange(VAddr address, u64 size) { - return address + size > address; -} - -// Helper function that performs the common sanity checks for svcMapMemory -// and svcUnmapMemory. This is doable, as both functions perform their sanitizing -// in the same order. -Result MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, VAddr src_addr, - u64 size) { - if (!Common::Is4KBAligned(dst_addr)) { - LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr); - return ResultInvalidAddress; - } - if (!Common::Is4KBAligned(src_addr)) { - LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr); - return ResultInvalidSize; - } +static uint32_t GetReg32(Core::System& system, int n) { + return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n)); +} - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is 0"); - return ResultInvalidSize; - } +static void SetReg32(Core::System& system, int n, uint32_t result) { + system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result)); +} - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size); - return ResultInvalidSize; - } +static uint64_t GetReg64(Core::System& system, int n) { + return system.CurrentArmInterface().GetReg(n); +} - if (!IsValidAddressRange(dst_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}", - dst_addr, size); - return ResultInvalidCurrentMemory; - } +static void SetReg64(Core::System& system, int n, uint64_t result) { + system.CurrentArmInterface().SetReg(n, result); +} - if (!IsValidAddressRange(src_addr, size)) { - LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}", - src_addr, size); - return ResultInvalidCurrentMemory; - } +// Like bit_cast, but handles the case when the source and dest +// are differently-sized. +template <typename To, typename From> + requires(std::is_trivial_v<To> && std::is_trivially_copyable_v<From>) +static To Convert(const From& from) { + To to{}; - if (!manager.IsInsideAddressSpace(src_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", - src_addr, size); - return ResultInvalidCurrentMemory; + if constexpr (sizeof(To) >= sizeof(From)) { + std::memcpy(&to, &from, sizeof(From)); + } else { + std::memcpy(&to, &from, sizeof(To)); } - if (manager.IsOutsideStackRegion(dst_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", - dst_addr, size); - return ResultInvalidMemoryRegion; - } + return to; +} - if (manager.IsInsideHeapRegion(dst_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Destination does not fit within the heap region, addr=0x{:016X}, " - "size=0x{:016X}", - dst_addr, size); - return ResultInvalidMemoryRegion; - } +// clang-format off +static_assert(sizeof(ArbitrationType) == 4); +static_assert(sizeof(BreakReason) == 4); +static_assert(sizeof(CodeMemoryOperation) == 4); +static_assert(sizeof(DebugThreadParam) == 4); +static_assert(sizeof(DeviceName) == 4); +static_assert(sizeof(HardwareBreakPointRegisterName) == 4); +static_assert(sizeof(Handle) == 4); +static_assert(sizeof(InfoType) == 4); +static_assert(sizeof(InterruptType) == 4); +static_assert(sizeof(IoPoolType) == 4); +static_assert(sizeof(KernelDebugType) == 4); +static_assert(sizeof(KernelTraceState) == 4); +static_assert(sizeof(LimitableResource) == 4); +static_assert(sizeof(MemoryMapping) == 4); +static_assert(sizeof(MemoryPermission) == 4); +static_assert(sizeof(PageInfo) == 4); +static_assert(sizeof(ProcessActivity) == 4); +static_assert(sizeof(ProcessInfoType) == 4); +static_assert(sizeof(Result) == 4); +static_assert(sizeof(SignalType) == 4); +static_assert(sizeof(SystemInfoType) == 4); +static_assert(sizeof(ThreadActivity) == 4); +static_assert(sizeof(ilp32::LastThreadContext) == 16); +static_assert(sizeof(ilp32::PhysicalMemoryInfo) == 16); +static_assert(sizeof(ilp32::SecureMonitorArguments) == 32); +static_assert(sizeof(lp64::LastThreadContext) == 32); +static_assert(sizeof(lp64::PhysicalMemoryInfo) == 24); +static_assert(sizeof(lp64::SecureMonitorArguments) == 64); +static_assert(sizeof(bool) == 1); +static_assert(sizeof(int32_t) == 4); +static_assert(sizeof(int64_t) == 8); +static_assert(sizeof(uint32_t) == 4); +static_assert(sizeof(uint64_t) == 8); - if (manager.IsInsideAliasRegion(dst_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Destination does not fit within the map region, addr=0x{:016X}, " - "size=0x{:016X}", - dst_addr, size); - return ResultInvalidMemoryRegion; - } +static void SvcWrap_SetHeapSize64From32(Core::System& system) { + Result ret{}; + + uintptr_t out_address{}; + uint32_t size{}; + + size = Convert<uint32_t>(GetReg32(system, 1)); + + ret = SetHeapSize64From32(system, &out_address, size); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_address)); } -enum class ResourceLimitValueType { - CurrentValue, - LimitValue, - PeakValue, -}; +static void SvcWrap_SetMemoryPermission64From32(Core::System& system) { + Result ret{}; -} // Anonymous namespace + uint32_t address{}; + uint32_t size{}; + MemoryPermission perm{}; + + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); + perm = Convert<MemoryPermission>(GetReg32(system, 2)); + + ret = SetMemoryPermission64From32(system, address, size, perm); + + SetReg32(system, 0, Convert<uint32_t>(ret)); +} -/// Set the process heap to a given Size. It can both extend and shrink the heap. -static Result SetHeapSize(Core::System& system, VAddr* out_address, u64 size) { - LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); +static void SvcWrap_SetMemoryAttribute64From32(Core::System& system) { + Result ret{}; - // Validate size. - R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); - R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); + uint32_t address{}; + uint32_t size{}; + uint32_t mask{}; + uint32_t attr{}; - // Set the heap size. - R_TRY(system.Kernel().CurrentProcess()->PageTable().SetHeapSize(out_address, size)); + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); + mask = Convert<uint32_t>(GetReg32(system, 2)); + attr = Convert<uint32_t>(GetReg32(system, 3)); - return ResultSuccess; + ret = SetMemoryAttribute64From32(system, address, size, mask, attr); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_size) { - VAddr temp_heap_addr{}; - const Result result{SetHeapSize(system, &temp_heap_addr, heap_size)}; - *heap_addr = static_cast<u32>(temp_heap_addr); - return result; +static void SvcWrap_MapMemory64From32(Core::System& system) { + Result ret{}; + + uint32_t dst_address{}; + uint32_t src_address{}; + uint32_t size{}; + + dst_address = Convert<uint32_t>(GetReg32(system, 0)); + src_address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + + ret = MapMemory64From32(system, dst_address, src_address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) { - switch (perm) { - case MemoryPermission::None: - case MemoryPermission::Read: - case MemoryPermission::ReadWrite: - return true; - default: - return false; - } +static void SvcWrap_UnmapMemory64From32(Core::System& system) { + Result ret{}; + + uint32_t dst_address{}; + uint32_t src_address{}; + uint32_t size{}; + + dst_address = Convert<uint32_t>(GetReg32(system, 0)); + src_address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + + ret = UnmapMemory64From32(system, dst_address, src_address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result SetMemoryPermission(Core::System& system, VAddr address, u64 size, - MemoryPermission perm) { - LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size, - perm); +static void SvcWrap_QueryMemory64From32(Core::System& system) { + Result ret{}; - // Validate address / size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + PageInfo out_page_info{}; + uint32_t out_memory_info{}; + uint32_t address{}; - // Validate the permission. - R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission); + out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 2)); - // Validate that the region is in range for the current process. - auto& page_table = system.Kernel().CurrentProcess()->PageTable(); - R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + ret = QueryMemory64From32(system, out_memory_info, &out_page_info, address); - // Set the memory attribute. - return page_table.SetMemoryPermission(address, size, perm); + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_page_info)); } -static Result SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, - u32 attr) { - LOG_DEBUG(Kernel_SVC, - "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, - size, mask, attr); +static void SvcWrap_ExitProcess64From32(Core::System& system) { + ExitProcess64From32(system); +} + +static void SvcWrap_CreateThread64From32(Core::System& system) { + Result ret{}; - // Validate address / size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + Handle out_handle{}; + uint32_t func{}; + uint32_t arg{}; + uint32_t stack_bottom{}; + int32_t priority{}; + int32_t core_id{}; - // Validate the attribute and mask. - constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached); - R_UNLESS((mask | attr) == mask, ResultInvalidCombination); - R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination); + func = Convert<uint32_t>(GetReg32(system, 1)); + arg = Convert<uint32_t>(GetReg32(system, 2)); + stack_bottom = Convert<uint32_t>(GetReg32(system, 3)); + priority = Convert<int32_t>(GetReg32(system, 0)); + core_id = Convert<int32_t>(GetReg32(system, 4)); - // Validate that the region is in range for the current process. - auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; - R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + ret = CreateThread64From32(system, &out_handle, func, arg, stack_bottom, priority, core_id); - // Set the memory attribute. - return page_table.SetMemoryAttribute(address, size, mask, attr); + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static Result SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, - u32 attr) { - return SetMemoryAttribute(system, address, size, mask, attr); +static void SvcWrap_StartThread64From32(Core::System& system) { + Result ret{}; + + Handle thread_handle{}; + + thread_handle = Convert<Handle>(GetReg32(system, 0)); + + ret = StartThread64From32(system, thread_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Maps a memory range into a different range. -static Result MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, - src_addr, size); +static void SvcWrap_ExitThread64From32(Core::System& system) { + ExitThread64From32(system); +} - auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; +static void SvcWrap_SleepThread64From32(Core::System& system) { + int64_t ns{}; - if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; - result.IsError()) { - return result; - } + std::array<uint32_t, 2> ns_gather{}; + ns_gather[0] = GetReg32(system, 0); + ns_gather[1] = GetReg32(system, 1); + ns = Convert<int64_t>(ns_gather); - return page_table.MapMemory(dst_addr, src_addr, size); + SleepThread64From32(system, ns); } -static Result MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { - return MapMemory(system, dst_addr, src_addr, size); +static void SvcWrap_GetThreadPriority64From32(Core::System& system) { + Result ret{}; + + int32_t out_priority{}; + Handle thread_handle{}; + + thread_handle = Convert<Handle>(GetReg32(system, 1)); + + ret = GetThreadPriority64From32(system, &out_priority, thread_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_priority)); } -/// Unmaps a region that was previously mapped with svcMapMemory -static Result UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, - src_addr, size); +static void SvcWrap_SetThreadPriority64From32(Core::System& system) { + Result ret{}; - auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; + Handle thread_handle{}; + int32_t priority{}; - if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; - result.IsError()) { - return result; - } + thread_handle = Convert<Handle>(GetReg32(system, 0)); + priority = Convert<int32_t>(GetReg32(system, 1)); - return page_table.UnmapMemory(dst_addr, src_addr, size); + ret = SetThreadPriority64From32(system, thread_handle, priority); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { - return UnmapMemory(system, dst_addr, src_addr, size); +static void SvcWrap_GetThreadCoreMask64From32(Core::System& system) { + Result ret{}; + + int32_t out_core_id{}; + uint64_t out_affinity_mask{}; + Handle thread_handle{}; + + thread_handle = Convert<Handle>(GetReg32(system, 2)); + + ret = GetThreadCoreMask64From32(system, &out_core_id, &out_affinity_mask, thread_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_core_id)); + auto out_affinity_mask_scatter = Convert<std::array<uint32_t, 2>>(out_affinity_mask); + SetReg32(system, 2, out_affinity_mask_scatter[0]); + SetReg32(system, 3, out_affinity_mask_scatter[1]); } -template <typename T> -Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, u64 name) { - auto& process = *system.CurrentProcess(); - auto& handle_table = process.GetHandleTable(); +static void SvcWrap_SetThreadCoreMask64From32(Core::System& system) { + Result ret{}; - // Declare the session we're going to allocate. - T* session; + Handle thread_handle{}; + int32_t core_id{}; + uint64_t affinity_mask{}; - // Reserve a new session from the process resource limit. - // FIXME: LimitableResource_SessionCountMax - KScopedResourceReservation session_reservation(&process, LimitableResource::SessionCountMax); - if (session_reservation.Succeeded()) { - session = T::Create(system.Kernel()); - } else { - return ResultLimitReached; - - // // We couldn't reserve a session. Check that we support dynamically expanding the - // // resource limit. - // R_UNLESS(process.GetResourceLimit() == - // &system.Kernel().GetSystemResourceLimit(), ResultLimitReached); - // R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached()); - - // // Try to allocate a session from unused slab memory. - // session = T::CreateFromUnusedSlabMemory(); - // R_UNLESS(session != nullptr, ResultLimitReached); - // ON_RESULT_FAILURE { session->Close(); }; - - // // If we're creating a KSession, we want to add two KSessionRequests to the heap, to - // // prevent request exhaustion. - // // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's - // // no reason to not do this statically. - // if constexpr (std::same_as<T, KSession>) { - // for (size_t i = 0; i < 2; i++) { - // KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory(); - // R_UNLESS(request != nullptr, ResultLimitReached); - // request->Close(); - // } - // } - - // We successfully allocated a session, so add the object we allocated to the resource - // limit. - // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1); - } + thread_handle = Convert<Handle>(GetReg32(system, 0)); + core_id = Convert<int32_t>(GetReg32(system, 1)); + std::array<uint32_t, 2> affinity_mask_gather{}; + affinity_mask_gather[0] = GetReg32(system, 2); + affinity_mask_gather[1] = GetReg32(system, 3); + affinity_mask = Convert<uint64_t>(affinity_mask_gather); - // Check that we successfully created a session. - R_UNLESS(session != nullptr, ResultOutOfResource); + ret = SetThreadCoreMask64From32(system, thread_handle, core_id, affinity_mask); - // Initialize the session. - session->Initialize(nullptr, fmt::format("{}", name)); + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // Commit the session reservation. - session_reservation.Commit(); +static void SvcWrap_GetCurrentProcessorNumber64From32(Core::System& system) { + int32_t ret{}; - // Ensure that we clean up the session (and its only references are handle table) on function - // end. - SCOPE_EXIT({ - session->GetClientSession().Close(); - session->GetServerSession().Close(); - }); + ret = GetCurrentProcessorNumber64From32(system); - // Register the session. - T::Register(system.Kernel(), session); + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // Add the server session to the handle table. - R_TRY(handle_table.Add(out_server, &session->GetServerSession())); +static void SvcWrap_SignalEvent64From32(Core::System& system) { + Result ret{}; - // Add the client session to the handle table. - const auto result = handle_table.Add(out_client, &session->GetClientSession()); + Handle event_handle{}; - if (!R_SUCCEEDED(result)) { - // Ensure that we maintaing a clean handle state on exit. - handle_table.Remove(*out_server); - } + event_handle = Convert<Handle>(GetReg32(system, 0)); - return result; + ret = SignalEvent64From32(system, event_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, - u32 is_light, u64 name) { - if (is_light) { - // return CreateSession<KLightSession>(system, out_server, out_client, name); - return ResultUnknown; - } else { - return CreateSession<KSession>(system, out_server, out_client, name); - } +static void SvcWrap_ClearEvent64From32(Core::System& system) { + Result ret{}; + + Handle event_handle{}; + + event_handle = Convert<Handle>(GetReg32(system, 0)); + + ret = ClearEvent64From32(system, event_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Connect to an OS service given the port name, returns the handle to the port to out -static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { - auto& memory = system.Memory(); - if (!memory.IsValidVirtualAddress(port_name_address)) { - LOG_ERROR(Kernel_SVC, - "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", - port_name_address); - return ResultNotFound; - } +static void SvcWrap_MapSharedMemory64From32(Core::System& system) { + Result ret{}; - static constexpr std::size_t PortNameMaxLength = 11; - // Read 1 char beyond the max allowed port name to detect names that are too long. - const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1); - if (port_name.size() > PortNameMaxLength) { - LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength, - port_name.size()); - return ResultOutOfRange; - } + Handle shmem_handle{}; + uint32_t address{}; + uint32_t size{}; + MemoryPermission map_perm{}; - LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); + shmem_handle = Convert<Handle>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + map_perm = Convert<MemoryPermission>(GetReg32(system, 3)); - // Get the current handle table. - auto& kernel = system.Kernel(); - auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + ret = MapSharedMemory64From32(system, shmem_handle, address, size, map_perm); - // Find the client port. - auto port = kernel.CreateNamedServicePort(port_name); - if (!port) { - LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name); - return ResultNotFound; - } + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // Reserve a handle for the port. - // NOTE: Nintendo really does write directly to the output handle here. - R_TRY(handle_table.Reserve(out)); - auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); }); +static void SvcWrap_UnmapSharedMemory64From32(Core::System& system) { + Result ret{}; - // Create a session. - KClientSession* session{}; - R_TRY(port->CreateSession(std::addressof(session))); + Handle shmem_handle{}; + uint32_t address{}; + uint32_t size{}; - kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort()); + shmem_handle = Convert<Handle>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); - // Register the session in the table, close the extra reference. - handle_table.Register(*out, session); - session->Close(); + ret = UnmapSharedMemory64From32(system, shmem_handle, address, size); - // We succeeded. - handle_guard.Cancel(); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result ConnectToNamedPort32(Core::System& system, Handle* out_handle, - u32 port_name_address) { +static void SvcWrap_CreateTransferMemory64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint32_t address{}; + uint32_t size{}; + MemoryPermission map_perm{}; + + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + map_perm = Convert<MemoryPermission>(GetReg32(system, 3)); + + ret = CreateTransferMemory64From32(system, &out_handle, address, size, map_perm); - return ConnectToNamedPort(system, out_handle, port_name_address); + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -/// Makes a blocking IPC call to a service. -static Result SendSyncRequest(Core::System& system, Handle handle) { - auto& kernel = system.Kernel(); +static void SvcWrap_CloseHandle64From32(Core::System& system) { + Result ret{}; - // Create the wait queue. - KThreadQueue wait_queue(kernel); + Handle handle{}; - // Get the client session from its handle. - KScopedAutoObject session = - kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); - R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + handle = Convert<Handle>(GetReg32(system, 0)); - LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + ret = CloseHandle64From32(system, handle); - return session->SendSyncRequest(); + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result SendSyncRequest32(Core::System& system, Handle handle) { - return SendSyncRequest(system, handle); +static void SvcWrap_ResetSignal64From32(Core::System& system) { + Result ret{}; + + Handle handle{}; + + handle = Convert<Handle>(GetReg32(system, 0)); + + ret = ResetSignal64From32(system, handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result ReplyAndReceive(Core::System& system, s32* out_index, Handle* handles, - s32 num_handles, Handle reply_target, s64 timeout_ns) { - auto& kernel = system.Kernel(); - auto& handle_table = GetCurrentThread(kernel).GetOwnerProcess()->GetHandleTable(); - - // Convert handle list to object table. - std::vector<KSynchronizationObject*> objs(num_handles); - R_UNLESS( - handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, num_handles), - ResultInvalidHandle); - - // Ensure handles are closed when we're done. - SCOPE_EXIT({ - for (auto i = 0; i < num_handles; ++i) { - objs[i]->Close(); - } - }); - - // Reply to the target, if one is specified. - if (reply_target != InvalidHandle) { - KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target); - R_UNLESS(session.IsNotNull(), ResultInvalidHandle); - - // If we fail to reply, we want to set the output index to -1. - // ON_RESULT_FAILURE { *out_index = -1; }; - - // Send the reply. - // R_TRY(session->SendReply()); - - Result rc = session->SendReply(); - if (!R_SUCCEEDED(rc)) { - *out_index = -1; - return rc; - } - } +static void SvcWrap_WaitSynchronization64From32(Core::System& system) { + Result ret{}; - // Wait for a message. - while (true) { - // Wait for an object. - s32 index; - Result result = KSynchronizationObject::Wait(kernel, &index, objs.data(), - static_cast<s32>(objs.size()), timeout_ns); - if (result == ResultTimedOut) { - return result; - } - - // Receive the request. - if (R_SUCCEEDED(result)) { - KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); - if (session != nullptr) { - result = session->ReceiveRequest(); - if (result == ResultNotFound) { - continue; - } - } - } - - *out_index = index; - return result; - } + int32_t out_index{}; + uint32_t handles{}; + int32_t num_handles{}; + int64_t timeout_ns{}; + + handles = Convert<uint32_t>(GetReg32(system, 1)); + num_handles = Convert<int32_t>(GetReg32(system, 2)); + std::array<uint32_t, 2> timeout_ns_gather{}; + timeout_ns_gather[0] = GetReg32(system, 0); + timeout_ns_gather[1] = GetReg32(system, 3); + timeout_ns = Convert<int64_t>(timeout_ns_gather); + + ret = WaitSynchronization64From32(system, &out_index, handles, num_handles, timeout_ns); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_index)); } -/// Get the ID for the specified thread. -static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { - // Get the thread from its handle. - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); +static void SvcWrap_CancelSynchronization64From32(Core::System& system) { + Result ret{}; - // Get the thread's id. - *out_thread_id = thread->GetId(); - return ResultSuccess; + Handle handle{}; + + handle = Convert<Handle>(GetReg32(system, 0)); + + ret = CancelSynchronization64From32(system, handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result GetThreadId32(Core::System& system, u32* out_thread_id_low, u32* out_thread_id_high, - Handle thread_handle) { - u64 out_thread_id{}; - const Result result{GetThreadId(system, &out_thread_id, thread_handle)}; +static void SvcWrap_ArbitrateLock64From32(Core::System& system) { + Result ret{}; + + Handle thread_handle{}; + uint32_t address{}; + uint32_t tag{}; - *out_thread_id_low = static_cast<u32>(out_thread_id >> 32); - *out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max()); + thread_handle = Convert<Handle>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 1)); + tag = Convert<uint32_t>(GetReg32(system, 2)); - return result; + ret = ArbitrateLock64From32(system, thread_handle, address, tag); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Gets the ID of the specified process or a specified thread's owning process. -static Result GetProcessId(Core::System& system, u64* out_process_id, Handle handle) { - LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); +static void SvcWrap_ArbitrateUnlock64From32(Core::System& system) { + Result ret{}; - // Get the object from the handle table. - KScopedAutoObject obj = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>( - static_cast<Handle>(handle)); - R_UNLESS(obj.IsNotNull(), ResultInvalidHandle); + uint32_t address{}; - // Get the process from the object. - KProcess* process = nullptr; - if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) { - // The object is a process, so we can use it directly. - process = p; - } else if (KThread* t = obj->DynamicCast<KThread*>(); t != nullptr) { - // The object is a thread, so we want to use its parent. - process = reinterpret_cast<KThread*>(obj.GetPointerUnsafe())->GetOwnerProcess(); - } else { - // TODO(bunnei): This should also handle debug objects before returning. - UNIMPLEMENTED_MSG("Debug objects not implemented"); - } + address = Convert<uint32_t>(GetReg32(system, 0)); - // Make sure the target process exists. - R_UNLESS(process != nullptr, ResultInvalidHandle); + ret = ArbitrateUnlock64From32(system, address); - // Get the process id. - *out_process_id = process->GetId(); + SetReg32(system, 0, Convert<uint32_t>(ret)); +} + +static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system) { + Result ret{}; + + uint32_t address{}; + uint32_t cv_key{}; + uint32_t tag{}; + int64_t timeout_ns{}; + + address = Convert<uint32_t>(GetReg32(system, 0)); + cv_key = Convert<uint32_t>(GetReg32(system, 1)); + tag = Convert<uint32_t>(GetReg32(system, 2)); + std::array<uint32_t, 2> timeout_ns_gather{}; + timeout_ns_gather[0] = GetReg32(system, 3); + timeout_ns_gather[1] = GetReg32(system, 4); + timeout_ns = Convert<int64_t>(timeout_ns_gather); - return ResultSuccess; + ret = WaitProcessWideKeyAtomic64From32(system, address, cv_key, tag, timeout_ns); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result GetProcessId32(Core::System& system, u32* out_process_id_low, - u32* out_process_id_high, Handle handle) { - u64 out_process_id{}; - const auto result = GetProcessId(system, &out_process_id, handle); - *out_process_id_low = static_cast<u32>(out_process_id); - *out_process_id_high = static_cast<u32>(out_process_id >> 32); - return result; +static void SvcWrap_SignalProcessWideKey64From32(Core::System& system) { + uint32_t cv_key{}; + int32_t count{}; + + cv_key = Convert<uint32_t>(GetReg32(system, 0)); + count = Convert<int32_t>(GetReg32(system, 1)); + + SignalProcessWideKey64From32(system, cv_key, count); } -/// Wait for the given handles to synchronize, timeout after the specified nanoseconds -static Result WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, - s32 num_handles, s64 nano_seconds) { - LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}", - handles_address, num_handles, nano_seconds); +static void SvcWrap_GetSystemTick64From32(Core::System& system) { + int64_t ret{}; - // Ensure number of handles is valid. - R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); + ret = GetSystemTick64From32(system); - auto& kernel = system.Kernel(); - std::vector<KSynchronizationObject*> objs(num_handles); - const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - Handle* handles = system.Memory().GetPointer<Handle>(handles_address); - - // Copy user handles. - if (num_handles > 0) { - // Convert the handles to objects. - R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, - num_handles), - ResultInvalidHandle); - for (const auto& obj : objs) { - kernel.RegisterInUseObject(obj); - } - } + auto ret_scatter = Convert<std::array<uint32_t, 2>>(ret); + SetReg32(system, 0, ret_scatter[0]); + SetReg32(system, 1, ret_scatter[1]); +} + +static void SvcWrap_ConnectToNamedPort64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint32_t name{}; - // Ensure handles are closed when we're done. - SCOPE_EXIT({ - for (s32 i = 0; i < num_handles; ++i) { - kernel.UnregisterInUseObject(objs[i]); - objs[i]->Close(); - } - }); + name = Convert<uint32_t>(GetReg32(system, 1)); - return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()), - nano_seconds); + ret = ConnectToNamedPort64From32(system, &out_handle, name); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static Result WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, - s32 num_handles, u32 timeout_high, s32* index) { - const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; - return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds); +static void SvcWrap_SendSyncRequest64From32(Core::System& system) { + Result ret{}; + + Handle session_handle{}; + + session_handle = Convert<Handle>(GetReg32(system, 0)); + + ret = SendSyncRequest64From32(system, session_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Resumes a thread waiting on WaitSynchronization -static Result CancelSynchronization(Core::System& system, Handle handle) { - LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); +static void SvcWrap_SendSyncRequestWithUserBuffer64From32(Core::System& system) { + Result ret{}; + + uint32_t message_buffer{}; + uint32_t message_buffer_size{}; + Handle session_handle{}; + + message_buffer = Convert<uint32_t>(GetReg32(system, 0)); + message_buffer_size = Convert<uint32_t>(GetReg32(system, 1)); + session_handle = Convert<Handle>(GetReg32(system, 2)); - // Get the thread from its handle. - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + ret = SendSyncRequestWithUserBuffer64From32(system, message_buffer, message_buffer_size, session_handle); - // Cancel the thread's wait. - thread->WaitCancel(); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result CancelSynchronization32(Core::System& system, Handle handle) { - return CancelSynchronization(system, handle); +static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system) { + Result ret{}; + + Handle out_event_handle{}; + uint32_t message_buffer{}; + uint32_t message_buffer_size{}; + Handle session_handle{}; + + message_buffer = Convert<uint32_t>(GetReg32(system, 1)); + message_buffer_size = Convert<uint32_t>(GetReg32(system, 2)); + session_handle = Convert<Handle>(GetReg32(system, 3)); + + ret = SendAsyncRequestWithUserBuffer64From32(system, &out_event_handle, message_buffer, message_buffer_size, session_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_event_handle)); } -/// Attempts to locks a mutex -static Result ArbitrateLock(Core::System& system, Handle thread_handle, VAddr address, u32 tag) { - LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address=0x{:X}, tag=0x{:08X}", - thread_handle, address, tag); +static void SvcWrap_GetProcessId64From32(Core::System& system) { + Result ret{}; - // Validate the input address. - if (IsKernelAddress(address)) { - LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})", - address); - return ResultInvalidCurrentMemory; - } - if (!Common::IsAligned(address, sizeof(u32))) { - LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); - return ResultInvalidAddress; - } + uint64_t out_process_id{}; + Handle process_handle{}; + + process_handle = Convert<Handle>(GetReg32(system, 1)); + + ret = GetProcessId64From32(system, &out_process_id, process_handle); - return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_process_id_scatter = Convert<std::array<uint32_t, 2>>(out_process_id); + SetReg32(system, 1, out_process_id_scatter[0]); + SetReg32(system, 2, out_process_id_scatter[1]); } -static Result ArbitrateLock32(Core::System& system, Handle thread_handle, u32 address, u32 tag) { - return ArbitrateLock(system, thread_handle, address, tag); +static void SvcWrap_GetThreadId64From32(Core::System& system) { + Result ret{}; + + uint64_t out_thread_id{}; + Handle thread_handle{}; + + thread_handle = Convert<Handle>(GetReg32(system, 1)); + + ret = GetThreadId64From32(system, &out_thread_id, thread_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id); + SetReg32(system, 1, out_thread_id_scatter[0]); + SetReg32(system, 2, out_thread_id_scatter[1]); } -/// Unlock a mutex -static Result ArbitrateUnlock(Core::System& system, VAddr address) { - LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); +static void SvcWrap_Break64From32(Core::System& system) { + BreakReason break_reason{}; + uint32_t arg{}; + uint32_t size{}; - // Validate the input address. - if (IsKernelAddress(address)) { - LOG_ERROR(Kernel_SVC, - "Attempting to arbitrate an unlock on a kernel address (address={:08X})", - address); - return ResultInvalidCurrentMemory; - } - if (!Common::IsAligned(address, sizeof(u32))) { - LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address); - return ResultInvalidAddress; - } + break_reason = Convert<BreakReason>(GetReg32(system, 0)); + arg = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); - return system.Kernel().CurrentProcess()->SignalToAddress(address); -} - -static Result ArbitrateUnlock32(Core::System& system, u32 address) { - return ArbitrateUnlock(system, address); -} - -/// Break program execution -static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { - BreakReason break_reason = - static_cast<BreakReason>(reason & ~static_cast<u32>(BreakReason::NotificationOnlyFlag)); - bool notification_only = (reason & static_cast<u32>(BreakReason::NotificationOnlyFlag)) != 0; - - bool has_dumped_buffer{}; - std::vector<u8> debug_buffer; - - const auto handle_debug_buffer = [&](VAddr addr, u64 sz) { - if (sz == 0 || addr == 0 || has_dumped_buffer) { - return; - } - - auto& memory = system.Memory(); - - // This typically is an error code so we're going to assume this is the case - if (sz == sizeof(u32)) { - LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr)); - } else { - // We don't know what's in here so we'll hexdump it - debug_buffer.resize(sz); - memory.ReadBlock(addr, debug_buffer.data(), sz); - std::string hexdump; - for (std::size_t i = 0; i < debug_buffer.size(); i++) { - hexdump += fmt::format("{:02X} ", debug_buffer[i]); - if (i != 0 && i % 16 == 0) { - hexdump += '\n'; - } - } - LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump); - } - has_dumped_buffer = true; - }; - switch (break_reason) { - case BreakReason::Panic: - LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1, - info2); - handle_debug_buffer(info1, info2); - break; - case BreakReason::Assert: - LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}", - info1, info2); - handle_debug_buffer(info1, info2); - break; - case BreakReason::User: - LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2); - handle_debug_buffer(info1, info2); - break; - case BreakReason::PreLoadDll: - LOG_INFO(Debug_Emulated, - "Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1, - info2); - break; - case BreakReason::PostLoadDll: - LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1, - info2); - break; - case BreakReason::PreUnloadDll: - LOG_INFO(Debug_Emulated, - "Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1, - info2); - break; - case BreakReason::PostUnloadDll: - LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}", - info1, info2); - break; - case BreakReason::CppException: - LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered."); - break; - default: - LOG_WARNING( - Debug_Emulated, - "Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}", - reason, info1, info2); - handle_debug_buffer(info1, info2); - break; - } + Break64From32(system, break_reason, arg, size); +} - system.GetReporter().SaveSvcBreakReport(reason, notification_only, info1, info2, - has_dumped_buffer ? std::make_optional(debug_buffer) - : std::nullopt); +static void SvcWrap_OutputDebugString64From32(Core::System& system) { + Result ret{}; - if (!notification_only) { - LOG_CRITICAL( - Debug_Emulated, - "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", - reason, info1, info2); + uint32_t debug_str{}; + uint32_t len{}; - handle_debug_buffer(info1, info2); + debug_str = Convert<uint32_t>(GetReg32(system, 0)); + len = Convert<uint32_t>(GetReg32(system, 1)); - auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); - const auto thread_processor_id = current_thread->GetActiveCore(); - system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); - } + ret = OutputDebugString64From32(system, debug_str, len); - if (system.DebuggerEnabled()) { - auto* thread = system.Kernel().GetCurrentEmuThread(); - system.GetDebugger().NotifyThreadStopped(thread); - thread->RequestSuspend(Kernel::SuspendType::Debug); - } + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { - Break(system, reason, info1, info2); +static void SvcWrap_ReturnFromException64From32(Core::System& system) { + Result result{}; + + result = Convert<Result>(GetReg32(system, 0)); + + ReturnFromException64From32(system, result); } -/// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString(Core::System& system, VAddr address, u64 len) { - if (len == 0) { - return; - } +static void SvcWrap_GetInfo64From32(Core::System& system) { + Result ret{}; - std::string str(len, '\0'); - system.Memory().ReadBlock(address, str.data(), str.size()); - LOG_DEBUG(Debug_Emulated, "{}", str); -} - -static void OutputDebugString32(Core::System& system, u32 address, u32 len) { - OutputDebugString(system, address, len); -} - -/// Gets system/memory information for the current process -static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle, - u64 info_sub_id) { - LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, - info_sub_id, handle); - - const auto info_id_type = static_cast<InfoType>(info_id); - - switch (info_id_type) { - case InfoType::CoreMask: - case InfoType::PriorityMask: - case InfoType::AliasRegionAddress: - case InfoType::AliasRegionSize: - case InfoType::HeapRegionAddress: - case InfoType::HeapRegionSize: - case InfoType::AslrRegionAddress: - case InfoType::AslrRegionSize: - case InfoType::StackRegionAddress: - case InfoType::StackRegionSize: - case InfoType::TotalMemorySize: - case InfoType::UsedMemorySize: - case InfoType::SystemResourceSizeTotal: - case InfoType::SystemResourceSizeUsed: - case InfoType::ProgramId: - case InfoType::UserExceptionContextAddress: - case InfoType::TotalNonSystemMemorySize: - case InfoType::UsedNonSystemMemorySize: - case InfoType::IsApplication: - case InfoType::FreeThreadCount: { - if (info_sub_id != 0) { - LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id, - info_sub_id); - return ResultInvalidEnumValue; - } - - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); - if (process.IsNull()) { - LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", - info_id, info_sub_id, handle); - return ResultInvalidHandle; - } - - switch (info_id_type) { - case InfoType::CoreMask: - *result = process->GetCoreMask(); - return ResultSuccess; - - case InfoType::PriorityMask: - *result = process->GetPriorityMask(); - return ResultSuccess; - - case InfoType::AliasRegionAddress: - *result = process->PageTable().GetAliasRegionStart(); - return ResultSuccess; - - case InfoType::AliasRegionSize: - *result = process->PageTable().GetAliasRegionSize(); - return ResultSuccess; - - case InfoType::HeapRegionAddress: - *result = process->PageTable().GetHeapRegionStart(); - return ResultSuccess; - - case InfoType::HeapRegionSize: - *result = process->PageTable().GetHeapRegionSize(); - return ResultSuccess; - - case InfoType::AslrRegionAddress: - *result = process->PageTable().GetAliasCodeRegionStart(); - return ResultSuccess; - - case InfoType::AslrRegionSize: - *result = process->PageTable().GetAliasCodeRegionSize(); - return ResultSuccess; - - case InfoType::StackRegionAddress: - *result = process->PageTable().GetStackRegionStart(); - return ResultSuccess; - - case InfoType::StackRegionSize: - *result = process->PageTable().GetStackRegionSize(); - return ResultSuccess; - - case InfoType::TotalMemorySize: - *result = process->GetTotalPhysicalMemoryAvailable(); - return ResultSuccess; - - case InfoType::UsedMemorySize: - *result = process->GetTotalPhysicalMemoryUsed(); - return ResultSuccess; - - case InfoType::SystemResourceSizeTotal: - *result = process->GetSystemResourceSize(); - return ResultSuccess; - - case InfoType::SystemResourceSizeUsed: - LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage"); - *result = process->GetSystemResourceUsage(); - return ResultSuccess; - - case InfoType::ProgramId: - *result = process->GetProgramID(); - return ResultSuccess; - - case InfoType::UserExceptionContextAddress: - *result = process->GetProcessLocalRegionAddress(); - return ResultSuccess; - - case InfoType::TotalNonSystemMemorySize: - *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource(); - return ResultSuccess; - - case InfoType::UsedNonSystemMemorySize: - *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource(); - return ResultSuccess; - - case InfoType::FreeThreadCount: - *result = process->GetFreeThreadCount(); - return ResultSuccess; - - default: - break; - } - - LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id); - return ResultInvalidEnumValue; - } + uint64_t out{}; + InfoType info_type{}; + Handle handle{}; + uint64_t info_subtype{}; - case InfoType::DebuggerAttached: - *result = 0; - return ResultSuccess; - - case InfoType::ResourceLimit: { - if (handle != 0) { - LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle); - return ResultInvalidHandle; - } - - if (info_sub_id != 0) { - LOG_ERROR(Kernel, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id, - info_sub_id); - return ResultInvalidCombination; - } - - KProcess* const current_process = system.Kernel().CurrentProcess(); - KHandleTable& handle_table = current_process->GetHandleTable(); - const auto resource_limit = current_process->GetResourceLimit(); - if (!resource_limit) { - *result = Svc::InvalidHandle; - // Yes, the kernel considers this a successful operation. - return ResultSuccess; - } - - Handle resource_handle{}; - R_TRY(handle_table.Add(&resource_handle, resource_limit)); - - *result = resource_handle; - return ResultSuccess; - } + info_type = Convert<InfoType>(GetReg32(system, 1)); + handle = Convert<Handle>(GetReg32(system, 2)); + std::array<uint32_t, 2> info_subtype_gather{}; + info_subtype_gather[0] = GetReg32(system, 0); + info_subtype_gather[1] = GetReg32(system, 3); + info_subtype = Convert<uint64_t>(info_subtype_gather); - case InfoType::RandomEntropy: - if (handle != 0) { - LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", - handle); - return ResultInvalidHandle; - } - - if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) { - LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", - KProcess::RANDOM_ENTROPY_SIZE, info_sub_id); - return ResultInvalidCombination; - } - - *result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id); - return ResultSuccess; - - case InfoType::InitialProcessIdRange: - LOG_WARNING(Kernel_SVC, - "(STUBBED) Attempted to query privileged process id bounds, returned 0"); - *result = 0; - return ResultSuccess; - - case InfoType::ThreadTickCount: { - constexpr u64 num_cpus = 4; - if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { - LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, - info_sub_id); - return ResultInvalidCombination; - } - - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>( - static_cast<Handle>(handle)); - if (thread.IsNull()) { - LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", - static_cast<Handle>(handle)); - return ResultInvalidHandle; - } - - const auto& core_timing = system.CoreTiming(); - const auto& scheduler = *system.Kernel().CurrentScheduler(); - const auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); - const bool same_thread = current_thread == thread.GetPointerUnsafe(); - - const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTime(); - u64 out_ticks = 0; - if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { - const u64 thread_ticks = current_thread->GetCpuTime(); - - out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); - } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { - out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; - } - - *result = out_ticks; - return ResultSuccess; - } - case InfoType::IdleTickCount: { - // Verify the input handle is invalid. - R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); - - // Verify the requested core is valid. - const bool core_valid = - (info_sub_id == 0xFFFFFFFFFFFFFFFF) || - (info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex())); - R_UNLESS(core_valid, ResultInvalidCombination); - - // Get the idle tick count. - *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime(); - return ResultSuccess; - } - case InfoType::MesosphereCurrentProcess: { - // Verify the input handle is invalid. - R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); + ret = GetInfo64From32(system, &out, info_type, handle, info_subtype); - // Verify the sub-type is valid. - R_UNLESS(info_sub_id == 0, ResultInvalidCombination); + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_scatter = Convert<std::array<uint32_t, 2>>(out); + SetReg32(system, 1, out_scatter[0]); + SetReg32(system, 2, out_scatter[1]); +} - // Get the handle table. - KProcess* current_process = system.Kernel().CurrentProcess(); - KHandleTable& handle_table = current_process->GetHandleTable(); +static void SvcWrap_FlushEntireDataCache64From32(Core::System& system) { + FlushEntireDataCache64From32(system); +} - // Get a new handle for the current process. - Handle tmp; - R_TRY(handle_table.Add(&tmp, current_process)); +static void SvcWrap_FlushDataCache64From32(Core::System& system) { + Result ret{}; - // Set the output. - *result = tmp; + uint32_t address{}; + uint32_t size{}; - // We succeeded. - return ResultSuccess; - } - default: - LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id); - return ResultInvalidEnumValue; - } + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); + + ret = FlushDataCache64From32(system, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low, - u32 info_id, u32 handle, u32 sub_id_high) { - const u64 sub_id{u64{sub_id_low} | (u64{sub_id_high} << 32)}; - u64 res_value{}; +static void SvcWrap_MapPhysicalMemory64From32(Core::System& system) { + Result ret{}; + + uint32_t address{}; + uint32_t size{}; - const Result result{GetInfo(system, &res_value, info_id, handle, sub_id)}; - *result_high = static_cast<u32>(res_value >> 32); - *result_low = static_cast<u32>(res_value & std::numeric_limits<u32>::max()); + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); - return result; + ret = MapPhysicalMemory64From32(system, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Maps memory at a desired address -static Result MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { - LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); +static void SvcWrap_UnmapPhysicalMemory64From32(Core::System& system) { + Result ret{}; - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); - return ResultInvalidAddress; - } + uint32_t address{}; + uint32_t size{}; - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); - return ResultInvalidSize; - } + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is zero"); - return ResultInvalidSize; - } + ret = UnmapPhysicalMemory64From32(system, address, size); - if (!(addr < addr + size)) { - LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); - return ResultInvalidMemoryRegion; - } + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - KProcess* const current_process{system.Kernel().CurrentProcess()}; - auto& page_table{current_process->PageTable()}; +static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system) { + Result ret{}; - if (current_process->GetSystemResourceSize() == 0) { - LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); - return ResultInvalidState; - } + ilp32::LastThreadContext out_context{}; + uint64_t out_thread_id{}; + Handle debug_handle{}; + int64_t ns{}; - if (!page_table.IsInsideAddressSpace(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, - size); - return ResultInvalidMemoryRegion; - } + debug_handle = Convert<Handle>(GetReg32(system, 2)); + std::array<uint32_t, 2> ns_gather{}; + ns_gather[0] = GetReg32(system, 0); + ns_gather[1] = GetReg32(system, 1); + ns = Convert<int64_t>(ns_gather); - if (page_table.IsOutsideAliasRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, - size); - return ResultInvalidMemoryRegion; - } + ret = GetDebugFutureThreadInfo64From32(system, &out_context, &out_thread_id, debug_handle, ns); - return page_table.MapPhysicalMemory(addr, size); + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context); + SetReg32(system, 1, out_context_scatter[0]); + SetReg32(system, 2, out_context_scatter[1]); + SetReg32(system, 3, out_context_scatter[2]); + SetReg32(system, 4, out_context_scatter[3]); + auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id); + SetReg32(system, 5, out_thread_id_scatter[0]); + SetReg32(system, 6, out_thread_id_scatter[1]); } -static Result MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { - return MapPhysicalMemory(system, addr, size); +static void SvcWrap_GetLastThreadInfo64From32(Core::System& system) { + Result ret{}; + + ilp32::LastThreadContext out_context{}; + uintptr_t out_tls_address{}; + uint32_t out_flags{}; + + ret = GetLastThreadInfo64From32(system, &out_context, &out_tls_address, &out_flags); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context); + SetReg32(system, 1, out_context_scatter[0]); + SetReg32(system, 2, out_context_scatter[1]); + SetReg32(system, 3, out_context_scatter[2]); + SetReg32(system, 4, out_context_scatter[3]); + SetReg32(system, 5, Convert<uint32_t>(out_tls_address)); + SetReg32(system, 6, Convert<uint32_t>(out_flags)); } -/// Unmaps memory previously mapped via MapPhysicalMemory -static Result UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { - LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); +static void SvcWrap_GetResourceLimitLimitValue64From32(Core::System& system) { + Result ret{}; - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); - return ResultInvalidAddress; - } + int64_t out_limit_value{}; + Handle resource_limit_handle{}; + LimitableResource which{}; - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); - return ResultInvalidSize; - } + resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); + which = Convert<LimitableResource>(GetReg32(system, 2)); - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is zero"); - return ResultInvalidSize; - } + ret = GetResourceLimitLimitValue64From32(system, &out_limit_value, resource_limit_handle, which); - if (!(addr < addr + size)) { - LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); - return ResultInvalidMemoryRegion; - } + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_limit_value_scatter = Convert<std::array<uint32_t, 2>>(out_limit_value); + SetReg32(system, 1, out_limit_value_scatter[0]); + SetReg32(system, 2, out_limit_value_scatter[1]); +} - KProcess* const current_process{system.Kernel().CurrentProcess()}; - auto& page_table{current_process->PageTable()}; +static void SvcWrap_GetResourceLimitCurrentValue64From32(Core::System& system) { + Result ret{}; - if (current_process->GetSystemResourceSize() == 0) { - LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); - return ResultInvalidState; - } + int64_t out_current_value{}; + Handle resource_limit_handle{}; + LimitableResource which{}; - if (!page_table.IsInsideAddressSpace(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, - size); - return ResultInvalidMemoryRegion; - } + resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); + which = Convert<LimitableResource>(GetReg32(system, 2)); - if (page_table.IsOutsideAliasRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, - size); - return ResultInvalidMemoryRegion; - } + ret = GetResourceLimitCurrentValue64From32(system, &out_current_value, resource_limit_handle, which); - return page_table.UnmapPhysicalMemory(addr, size); + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_current_value_scatter = Convert<std::array<uint32_t, 2>>(out_current_value); + SetReg32(system, 1, out_current_value_scatter[0]); + SetReg32(system, 2, out_current_value_scatter[1]); } -static Result UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { - return UnmapPhysicalMemory(system, addr, size); +static void SvcWrap_SetThreadActivity64From32(Core::System& system) { + Result ret{}; + + Handle thread_handle{}; + ThreadActivity thread_activity{}; + + thread_handle = Convert<Handle>(GetReg32(system, 0)); + thread_activity = Convert<ThreadActivity>(GetReg32(system, 1)); + + ret = SetThreadActivity64From32(system, thread_handle, thread_activity); + + SetReg32(system, 0, Convert<uint32_t>(ret)); +} + +static void SvcWrap_GetThreadContext364From32(Core::System& system) { + Result ret{}; + + uint32_t out_context{}; + Handle thread_handle{}; + + out_context = Convert<uint32_t>(GetReg32(system, 0)); + thread_handle = Convert<Handle>(GetReg32(system, 1)); + + ret = GetThreadContext364From32(system, out_context, thread_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Sets the thread activity -static Result SetThreadActivity(Core::System& system, Handle thread_handle, - ThreadActivity thread_activity) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, - thread_activity); +static void SvcWrap_WaitForAddress64From32(Core::System& system) { + Result ret{}; + + uint32_t address{}; + ArbitrationType arb_type{}; + int32_t value{}; + int64_t timeout_ns{}; + + address = Convert<uint32_t>(GetReg32(system, 0)); + arb_type = Convert<ArbitrationType>(GetReg32(system, 1)); + value = Convert<int32_t>(GetReg32(system, 2)); + std::array<uint32_t, 2> timeout_ns_gather{}; + timeout_ns_gather[0] = GetReg32(system, 3); + timeout_ns_gather[1] = GetReg32(system, 4); + timeout_ns = Convert<int64_t>(timeout_ns_gather); - // Validate the activity. - constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { - return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; - }; - R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue); + ret = WaitForAddress64From32(system, address, arb_type, value, timeout_ns); - // Get the thread from its handle. - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + SetReg32(system, 0, Convert<uint32_t>(ret)); +} + +static void SvcWrap_SignalToAddress64From32(Core::System& system) { + Result ret{}; - // Check that the activity is being set on a non-current thread for the current process. - R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle); - R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy); + uint32_t address{}; + SignalType signal_type{}; + int32_t value{}; + int32_t count{}; - // Set the activity. - R_TRY(thread->SetActivity(thread_activity)); + address = Convert<uint32_t>(GetReg32(system, 0)); + signal_type = Convert<SignalType>(GetReg32(system, 1)); + value = Convert<int32_t>(GetReg32(system, 2)); + count = Convert<int32_t>(GetReg32(system, 3)); - return ResultSuccess; + ret = SignalToAddress64From32(system, address, signal_type, value, count); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result SetThreadActivity32(Core::System& system, Handle thread_handle, - Svc::ThreadActivity thread_activity) { - return SetThreadActivity(system, thread_handle, thread_activity); +static void SvcWrap_SynchronizePreemptionState64From32(Core::System& system) { + SynchronizePreemptionState64From32(system); } -/// Gets the thread context -static Result GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) { - LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, - thread_handle); +static void SvcWrap_GetResourceLimitPeakValue64From32(Core::System& system) { + Result ret{}; - auto& kernel = system.Kernel(); + int64_t out_peak_value{}; + Handle resource_limit_handle{}; + LimitableResource which{}; - // Get the thread from its handle. - KScopedAutoObject thread = - kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); + which = Convert<LimitableResource>(GetReg32(system, 2)); - // Require the handle be to a non-current thread in the current process. - const auto* current_process = kernel.CurrentProcess(); - R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId); + ret = GetResourceLimitPeakValue64From32(system, &out_peak_value, resource_limit_handle, which); - // Verify that the thread isn't terminated. - R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested); + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_peak_value_scatter = Convert<std::array<uint32_t, 2>>(out_peak_value); + SetReg32(system, 1, out_peak_value_scatter[0]); + SetReg32(system, 2, out_peak_value_scatter[1]); +} + +static void SvcWrap_CreateIoPool64From32(Core::System& system) { + Result ret{}; - /// Check that the thread is not the current one. - /// NOTE: Nintendo does not check this, and thus the following loop will deadlock. - R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId); + Handle out_handle{}; + IoPoolType which{}; - // Try to get the thread context until the thread isn't current on any core. - while (true) { - KScopedSchedulerLock sl{kernel}; + which = Convert<IoPoolType>(GetReg32(system, 1)); - // TODO(bunnei): Enforce that thread is suspended for debug here. + ret = CreateIoPool64From32(system, &out_handle, which); - // If the thread's raw state isn't runnable, check if it's current on some core. - if (thread->GetRawState() != ThreadState::Runnable) { - bool current = false; - for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { - if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetSchedulerCurrentThread()) { - current = true; - break; - } - } + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); +} - // If the thread is current, retry until it isn't. - if (current) { - continue; - } - } +static void SvcWrap_CreateIoRegion64From32(Core::System& system) { + Result ret{}; - // Get the thread context. - std::vector<u8> context; - R_TRY(thread->GetThreadContext3(context)); + Handle out_handle{}; + Handle io_pool{}; + uint64_t physical_address{}; + uint32_t size{}; + MemoryMapping mapping{}; + MemoryPermission perm{}; - // Copy the thread context to user space. - system.Memory().WriteBlock(out_context, context.data(), context.size()); + io_pool = Convert<Handle>(GetReg32(system, 1)); + std::array<uint32_t, 2> physical_address_gather{}; + physical_address_gather[0] = GetReg32(system, 2); + physical_address_gather[1] = GetReg32(system, 3); + physical_address = Convert<uint64_t>(physical_address_gather); + size = Convert<uint32_t>(GetReg32(system, 0)); + mapping = Convert<MemoryMapping>(GetReg32(system, 4)); + perm = Convert<MemoryPermission>(GetReg32(system, 5)); - return ResultSuccess; - } + ret = CreateIoRegion64From32(system, &out_handle, io_pool, physical_address, size, mapping, perm); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static Result GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) { - return GetThreadContext(system, out_context, thread_handle); +static void SvcWrap_KernelDebug64From32(Core::System& system) { + KernelDebugType kern_debug_type{}; + uint64_t arg0{}; + uint64_t arg1{}; + uint64_t arg2{}; + + kern_debug_type = Convert<KernelDebugType>(GetReg32(system, 0)); + std::array<uint32_t, 2> arg0_gather{}; + arg0_gather[0] = GetReg32(system, 2); + arg0_gather[1] = GetReg32(system, 3); + arg0 = Convert<uint64_t>(arg0_gather); + std::array<uint32_t, 2> arg1_gather{}; + arg1_gather[0] = GetReg32(system, 1); + arg1_gather[1] = GetReg32(system, 4); + arg1 = Convert<uint64_t>(arg1_gather); + std::array<uint32_t, 2> arg2_gather{}; + arg2_gather[0] = GetReg32(system, 5); + arg2_gather[1] = GetReg32(system, 6); + arg2 = Convert<uint64_t>(arg2_gather); + + KernelDebug64From32(system, kern_debug_type, arg0, arg1, arg2); } -/// Gets the priority for the specified thread -static Result GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) { - LOG_TRACE(Kernel_SVC, "called"); +static void SvcWrap_ChangeKernelTraceState64From32(Core::System& system) { + KernelTraceState kern_trace_state{}; - // Get the thread from its handle. - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + kern_trace_state = Convert<KernelTraceState>(GetReg32(system, 0)); - // Get the thread's priority. - *out_priority = thread->GetPriority(); - return ResultSuccess; + ChangeKernelTraceState64From32(system, kern_trace_state); } -static Result GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) { - return GetThreadPriority(system, out_priority, handle); +static void SvcWrap_CreateSession64From32(Core::System& system) { + Result ret{}; + + Handle out_server_session_handle{}; + Handle out_client_session_handle{}; + bool is_light{}; + uint32_t name{}; + + is_light = Convert<bool>(GetReg32(system, 2)); + name = Convert<uint32_t>(GetReg32(system, 3)); + + ret = CreateSession64From32(system, &out_server_session_handle, &out_client_session_handle, is_light, name); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_server_session_handle)); + SetReg32(system, 2, Convert<uint32_t>(out_client_session_handle)); } -/// Sets the priority for the specified thread -static Result SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) { - // Get the current process. - KProcess& process = *system.Kernel().CurrentProcess(); +static void SvcWrap_AcceptSession64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + Handle port{}; - // Validate the priority. - R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority, - ResultInvalidPriority); - R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority); + port = Convert<Handle>(GetReg32(system, 1)); - // Get the thread from its handle. - KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + ret = AcceptSession64From32(system, &out_handle, port); - // Set the thread priority. - thread->SetBasePriority(priority); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static Result SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) { - return SetThreadPriority(system, thread_handle, priority); +static void SvcWrap_ReplyAndReceive64From32(Core::System& system) { + Result ret{}; + + int32_t out_index{}; + uint32_t handles{}; + int32_t num_handles{}; + Handle reply_target{}; + int64_t timeout_ns{}; + + handles = Convert<uint32_t>(GetReg32(system, 1)); + num_handles = Convert<int32_t>(GetReg32(system, 2)); + reply_target = Convert<Handle>(GetReg32(system, 3)); + std::array<uint32_t, 2> timeout_ns_gather{}; + timeout_ns_gather[0] = GetReg32(system, 0); + timeout_ns_gather[1] = GetReg32(system, 4); + timeout_ns = Convert<int64_t>(timeout_ns_gather); + + ret = ReplyAndReceive64From32(system, &out_index, handles, num_handles, reply_target, timeout_ns); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_index)); } -/// Get which CPU core is executing the current thread -static u32 GetCurrentProcessorNumber(Core::System& system) { - LOG_TRACE(Kernel_SVC, "called"); - return static_cast<u32>(system.CurrentPhysicalCore().CoreIndex()); +static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system) { + Result ret{}; + + int32_t out_index{}; + uint32_t message_buffer{}; + uint32_t message_buffer_size{}; + uint32_t handles{}; + int32_t num_handles{}; + Handle reply_target{}; + int64_t timeout_ns{}; + + message_buffer = Convert<uint32_t>(GetReg32(system, 1)); + message_buffer_size = Convert<uint32_t>(GetReg32(system, 2)); + handles = Convert<uint32_t>(GetReg32(system, 3)); + num_handles = Convert<int32_t>(GetReg32(system, 0)); + reply_target = Convert<Handle>(GetReg32(system, 4)); + std::array<uint32_t, 2> timeout_ns_gather{}; + timeout_ns_gather[0] = GetReg32(system, 5); + timeout_ns_gather[1] = GetReg32(system, 6); + timeout_ns = Convert<int64_t>(timeout_ns_gather); + + ret = ReplyAndReceiveWithUserBuffer64From32(system, &out_index, message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_index)); } -static u32 GetCurrentProcessorNumber32(Core::System& system) { - return GetCurrentProcessorNumber(system); +static void SvcWrap_CreateEvent64From32(Core::System& system) { + Result ret{}; + + Handle out_write_handle{}; + Handle out_read_handle{}; + + ret = CreateEvent64From32(system, &out_write_handle, &out_read_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_write_handle)); + SetReg32(system, 2, Convert<uint32_t>(out_read_handle)); } -namespace { +static void SvcWrap_MapIoRegion64From32(Core::System& system) { + Result ret{}; -constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { - switch (perm) { - case Svc::MemoryPermission::Read: - case Svc::MemoryPermission::ReadWrite: - return true; - default: - return false; - } + Handle io_region{}; + uint32_t address{}; + uint32_t size{}; + MemoryPermission perm{}; + + io_region = Convert<Handle>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + perm = Convert<MemoryPermission>(GetReg32(system, 3)); + + ret = MapIoRegion64From32(system, io_region, address, size, perm); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { - return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; +static void SvcWrap_UnmapIoRegion64From32(Core::System& system) { + Result ret{}; + + Handle io_region{}; + uint32_t address{}; + uint32_t size{}; + + io_region = Convert<Handle>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + + ret = UnmapIoRegion64From32(system, io_region, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { - switch (perm) { - case Svc::MemoryPermission::None: - case Svc::MemoryPermission::Read: - case Svc::MemoryPermission::ReadWrite: - case Svc::MemoryPermission::ReadExecute: - return true; - default: - return false; - } +static void SvcWrap_MapPhysicalMemoryUnsafe64From32(Core::System& system) { + Result ret{}; + + uint32_t address{}; + uint32_t size{}; + + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); + + ret = MapPhysicalMemoryUnsafe64From32(system, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) { - return perm == Svc::MemoryPermission::ReadWrite; +static void SvcWrap_UnmapPhysicalMemoryUnsafe64From32(Core::System& system) { + Result ret{}; + + uint32_t address{}; + uint32_t size{}; + + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); + + ret = UnmapPhysicalMemoryUnsafe64From32(system, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { - return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute; +static void SvcWrap_SetUnsafeLimit64From32(Core::System& system) { + Result ret{}; + + uint32_t limit{}; + + limit = Convert<uint32_t>(GetReg32(system, 0)); + + ret = SetUnsafeLimit64From32(system, limit); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) { - return perm == Svc::MemoryPermission::None; +static void SvcWrap_CreateCodeMemory64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint32_t address{}; + uint32_t size{}; + + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + + ret = CreateCodeMemory64From32(system, &out_handle, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { - return perm == Svc::MemoryPermission::None; +static void SvcWrap_ControlCodeMemory64From32(Core::System& system) { + Result ret{}; + + Handle code_memory_handle{}; + CodeMemoryOperation operation{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission perm{}; + + code_memory_handle = Convert<Handle>(GetReg32(system, 0)); + operation = Convert<CodeMemoryOperation>(GetReg32(system, 1)); + std::array<uint32_t, 2> address_gather{}; + address_gather[0] = GetReg32(system, 2); + address_gather[1] = GetReg32(system, 3); + address = Convert<uint64_t>(address_gather); + std::array<uint32_t, 2> size_gather{}; + size_gather[0] = GetReg32(system, 4); + size_gather[1] = GetReg32(system, 5); + size = Convert<uint64_t>(size_gather); + perm = Convert<MemoryPermission>(GetReg32(system, 6)); + + ret = ControlCodeMemory64From32(system, code_memory_handle, operation, address, size, perm); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -} // Anonymous namespace +static void SvcWrap_SleepSystem64From32(Core::System& system) { + SleepSystem64From32(system); +} -static Result MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, u64 size, - Svc::MemoryPermission map_perm) { - LOG_TRACE(Kernel_SVC, - "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", - shmem_handle, address, size, map_perm); +static void SvcWrap_ReadWriteRegister64From32(Core::System& system) { + Result ret{}; - // Validate the address/size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + uint32_t out_value{}; + uint64_t address{}; + uint32_t mask{}; + uint32_t value{}; - // Validate the permission. - R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); + std::array<uint32_t, 2> address_gather{}; + address_gather[0] = GetReg32(system, 2); + address_gather[1] = GetReg32(system, 3); + address = Convert<uint64_t>(address_gather); + mask = Convert<uint32_t>(GetReg32(system, 0)); + value = Convert<uint32_t>(GetReg32(system, 1)); - // Get the current process. - auto& process = *system.Kernel().CurrentProcess(); - auto& page_table = process.PageTable(); + ret = ReadWriteRegister64From32(system, &out_value, address, mask, value); - // Get the shared memory. - KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); - R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_value)); +} - // Verify that the mapping is in range. - R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); +static void SvcWrap_SetProcessActivity64From32(Core::System& system) { + Result ret{}; - // Add the shared memory to the process. - R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size)); + Handle process_handle{}; + ProcessActivity process_activity{}; - // Ensure that we clean up the shared memory if we fail to map it. - auto guard = - SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); }); + process_handle = Convert<Handle>(GetReg32(system, 0)); + process_activity = Convert<ProcessActivity>(GetReg32(system, 1)); - // Map the shared memory. - R_TRY(shmem->Map(process, address, size, map_perm)); + ret = SetProcessActivity64From32(system, process_handle, process_activity); - // We succeeded. - guard.Cancel(); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, u32 size, - Svc::MemoryPermission map_perm) { - return MapSharedMemory(system, shmem_handle, address, size, map_perm); +static void SvcWrap_CreateSharedMemory64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint32_t size{}; + MemoryPermission owner_perm{}; + MemoryPermission remote_perm{}; + + size = Convert<uint32_t>(GetReg32(system, 1)); + owner_perm = Convert<MemoryPermission>(GetReg32(system, 2)); + remote_perm = Convert<MemoryPermission>(GetReg32(system, 3)); + + ret = CreateSharedMemory64From32(system, &out_handle, size, owner_perm, remote_perm); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, - u64 size) { - // Validate the address/size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); +static void SvcWrap_MapTransferMemory64From32(Core::System& system) { + Result ret{}; + + Handle trmem_handle{}; + uint32_t address{}; + uint32_t size{}; + MemoryPermission owner_perm{}; - // Get the current process. - auto& process = *system.Kernel().CurrentProcess(); - auto& page_table = process.PageTable(); + trmem_handle = Convert<Handle>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); + owner_perm = Convert<MemoryPermission>(GetReg32(system, 3)); - // Get the shared memory. - KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); - R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); + ret = MapTransferMemory64From32(system, trmem_handle, address, size, owner_perm); - // Verify that the mapping is in range. - R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); + SetReg32(system, 0, Convert<uint32_t>(ret)); +} + +static void SvcWrap_UnmapTransferMemory64From32(Core::System& system) { + Result ret{}; - // Unmap the shared memory. - R_TRY(shmem->Unmap(process, address, size)); + Handle trmem_handle{}; + uint32_t address{}; + uint32_t size{}; - // Remove the shared memory from the process. - process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); + trmem_handle = Convert<Handle>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetReg32(system, 2)); - return ResultSuccess; + ret = UnmapTransferMemory64From32(system, trmem_handle, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, - u32 size) { - return UnmapSharedMemory(system, shmem_handle, address, size); +static void SvcWrap_CreateInterruptEvent64From32(Core::System& system) { + Result ret{}; + + Handle out_read_handle{}; + int32_t interrupt_id{}; + InterruptType interrupt_type{}; + + interrupt_id = Convert<int32_t>(GetReg32(system, 1)); + interrupt_type = Convert<InterruptType>(GetReg32(system, 2)); + + ret = CreateInterruptEvent64From32(system, &out_read_handle, interrupt_id, interrupt_type); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_read_handle)); } -static Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, VAddr address, - u64 size, Svc::MemoryPermission perm) { - LOG_TRACE(Kernel_SVC, - "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", - process_handle, address, size, perm); +static void SvcWrap_QueryPhysicalAddress64From32(Core::System& system) { + Result ret{}; - // Validate the address/size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); - R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory); - R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory); + ilp32::PhysicalMemoryInfo out_info{}; + uint32_t address{}; - // Validate the memory permission. - R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); + address = Convert<uint32_t>(GetReg32(system, 1)); - // Get the process from its handle. - KScopedAutoObject process = - system.CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle); - R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + ret = QueryPhysicalAddress64From32(system, &out_info, address); - // Validate that the address is in range. - auto& page_table = process->PageTable(); - R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_info_scatter = Convert<std::array<uint32_t, 4>>(out_info); + SetReg32(system, 1, out_info_scatter[0]); + SetReg32(system, 2, out_info_scatter[1]); + SetReg32(system, 3, out_info_scatter[2]); + SetReg32(system, 4, out_info_scatter[3]); +} - // Set the memory permission. - return page_table.SetProcessMemoryPermission(address, size, perm); +static void SvcWrap_QueryIoMapping64From32(Core::System& system) { + Result ret{}; + + uintptr_t out_address{}; + uintptr_t out_size{}; + uint64_t physical_address{}; + uint32_t size{}; + + std::array<uint32_t, 2> physical_address_gather{}; + physical_address_gather[0] = GetReg32(system, 2); + physical_address_gather[1] = GetReg32(system, 3); + physical_address = Convert<uint64_t>(physical_address_gather); + size = Convert<uint32_t>(GetReg32(system, 0)); + + ret = QueryIoMapping64From32(system, &out_address, &out_size, physical_address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_address)); + SetReg32(system, 2, Convert<uint32_t>(out_size)); } -static Result MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, - VAddr src_address, u64 size) { - LOG_TRACE(Kernel_SVC, - "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", - dst_address, process_handle, src_address, size); +static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system) { + Result ret{}; - // Validate the address/size. - R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory); - R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory); + Handle out_handle{}; + uint64_t das_address{}; + uint64_t das_size{}; - // Get the processes. - KProcess* dst_process = system.CurrentProcess(); - KScopedAutoObject src_process = - dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); - R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); + std::array<uint32_t, 2> das_address_gather{}; + das_address_gather[0] = GetReg32(system, 2); + das_address_gather[1] = GetReg32(system, 3); + das_address = Convert<uint64_t>(das_address_gather); + std::array<uint32_t, 2> das_size_gather{}; + das_size_gather[0] = GetReg32(system, 0); + das_size_gather[1] = GetReg32(system, 1); + das_size = Convert<uint64_t>(das_size_gather); - // Get the page tables. - auto& dst_pt = dst_process->PageTable(); - auto& src_pt = src_process->PageTable(); + ret = CreateDeviceAddressSpace64From32(system, &out_handle, das_address, das_size); - // Validate that the mapping is in range. - R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); - R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode), - ResultInvalidMemoryRegion); + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); +} + +static void SvcWrap_AttachDeviceAddressSpace64From32(Core::System& system) { + Result ret{}; - // Create a new page group. - KPageGroup pg; - R_TRY(src_pt.MakeAndOpenPageGroup( - std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess, - KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::All, KMemoryAttribute::None)); + DeviceName device_name{}; + Handle das_handle{}; - // Map the group. - R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode, - KMemoryPermission::UserReadWrite)); + device_name = Convert<DeviceName>(GetReg32(system, 0)); + das_handle = Convert<Handle>(GetReg32(system, 1)); - return ResultSuccess; + ret = AttachDeviceAddressSpace64From32(system, device_name, das_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, - VAddr src_address, u64 size) { - LOG_TRACE(Kernel_SVC, - "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", - dst_address, process_handle, src_address, size); +static void SvcWrap_DetachDeviceAddressSpace64From32(Core::System& system) { + Result ret{}; - // Validate the address/size. - R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory); - R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory); + DeviceName device_name{}; + Handle das_handle{}; - // Get the processes. - KProcess* dst_process = system.CurrentProcess(); - KScopedAutoObject src_process = - dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); - R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); - - // Get the page tables. - auto& dst_pt = dst_process->PageTable(); - auto& src_pt = src_process->PageTable(); - - // Validate that the mapping is in range. - R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); - R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode), - ResultInvalidMemoryRegion); - - // Unmap the memory. - R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address)); - - return ResultSuccess; -} - -static Result CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size); - - // Get kernel instance. - auto& kernel = system.Kernel(); + device_name = Convert<DeviceName>(GetReg32(system, 0)); + das_handle = Convert<Handle>(GetReg32(system, 1)); - // Validate address / size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + ret = DetachDeviceAddressSpace64From32(system, device_name, das_handle); - // Create the code memory. + SetReg32(system, 0, Convert<uint32_t>(ret)); +} + +static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system) { + Result ret{}; - KCodeMemory* code_mem = KCodeMemory::Create(kernel); - R_UNLESS(code_mem != nullptr, ResultOutOfResource); + Handle das_handle{}; + Handle process_handle{}; + uint64_t process_address{}; + uint32_t size{}; + uint64_t device_address{}; + uint32_t option{}; - // Verify that the region is in range. - R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size), - ResultInvalidCurrentMemory); + das_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetReg32(system, 1)); + std::array<uint32_t, 2> process_address_gather{}; + process_address_gather[0] = GetReg32(system, 2); + process_address_gather[1] = GetReg32(system, 3); + process_address = Convert<uint64_t>(process_address_gather); + size = Convert<uint32_t>(GetReg32(system, 4)); + std::array<uint32_t, 2> device_address_gather{}; + device_address_gather[0] = GetReg32(system, 5); + device_address_gather[1] = GetReg32(system, 6); + device_address = Convert<uint64_t>(device_address_gather); + option = Convert<uint32_t>(GetReg32(system, 7)); - // Initialize the code memory. - R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size)); + ret = MapDeviceAddressSpaceByForce64From32(system, das_handle, process_handle, process_address, size, device_address, option); + + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // Register the code memory. - KCodeMemory::Register(kernel, code_mem); +static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system) { + Result ret{}; - // Add the code memory to the handle table. - R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem)); + Handle das_handle{}; + Handle process_handle{}; + uint64_t process_address{}; + uint32_t size{}; + uint64_t device_address{}; + uint32_t option{}; - code_mem->Close(); + das_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetReg32(system, 1)); + std::array<uint32_t, 2> process_address_gather{}; + process_address_gather[0] = GetReg32(system, 2); + process_address_gather[1] = GetReg32(system, 3); + process_address = Convert<uint64_t>(process_address_gather); + size = Convert<uint32_t>(GetReg32(system, 4)); + std::array<uint32_t, 2> device_address_gather{}; + device_address_gather[0] = GetReg32(system, 5); + device_address_gather[1] = GetReg32(system, 6); + device_address = Convert<uint64_t>(device_address_gather); + option = Convert<uint32_t>(GetReg32(system, 7)); - return ResultSuccess; + ret = MapDeviceAddressSpaceAligned64From32(system, das_handle, process_handle, process_address, size, device_address, option); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result CreateCodeMemory32(Core::System& system, Handle* out, u32 address, u32 size) { - return CreateCodeMemory(system, out, address, size); +static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system) { + Result ret{}; + + Handle das_handle{}; + Handle process_handle{}; + uint64_t process_address{}; + uint32_t size{}; + uint64_t device_address{}; + + das_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetReg32(system, 1)); + std::array<uint32_t, 2> process_address_gather{}; + process_address_gather[0] = GetReg32(system, 2); + process_address_gather[1] = GetReg32(system, 3); + process_address = Convert<uint64_t>(process_address_gather); + size = Convert<uint32_t>(GetReg32(system, 4)); + std::array<uint32_t, 2> device_address_gather{}; + device_address_gather[0] = GetReg32(system, 5); + device_address_gather[1] = GetReg32(system, 6); + device_address = Convert<uint64_t>(device_address_gather); + + ret = UnmapDeviceAddressSpace64From32(system, das_handle, process_handle, process_address, size, device_address); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation, - VAddr address, size_t size, Svc::MemoryPermission perm) { +static void SvcWrap_InvalidateProcessDataCache64From32(Core::System& system) { + Result ret{}; - LOG_TRACE(Kernel_SVC, - "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, " - "permission=0x{:X}", - code_memory_handle, operation, address, size, perm); + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; - // Validate the address / size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + process_handle = Convert<Handle>(GetReg32(system, 0)); + std::array<uint32_t, 2> address_gather{}; + address_gather[0] = GetReg32(system, 2); + address_gather[1] = GetReg32(system, 3); + address = Convert<uint64_t>(address_gather); + std::array<uint32_t, 2> size_gather{}; + size_gather[0] = GetReg32(system, 1); + size_gather[1] = GetReg32(system, 4); + size = Convert<uint64_t>(size_gather); - // Get the code memory from its handle. - KScopedAutoObject code_mem = - system.CurrentProcess()->GetHandleTable().GetObject<KCodeMemory>(code_memory_handle); - R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle); + ret = InvalidateProcessDataCache64From32(system, process_handle, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process. - // This enables homebrew usage of these SVCs for JIT. +static void SvcWrap_StoreProcessDataCache64From32(Core::System& system) { + Result ret{}; - // Perform the operation. - switch (static_cast<CodeMemoryOperation>(operation)) { - case CodeMemoryOperation::Map: { - // Check that the region is in range. - R_UNLESS( - system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut), - ResultInvalidMemoryRegion); + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; - // Check the memory permission. - R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + process_handle = Convert<Handle>(GetReg32(system, 0)); + std::array<uint32_t, 2> address_gather{}; + address_gather[0] = GetReg32(system, 2); + address_gather[1] = GetReg32(system, 3); + address = Convert<uint64_t>(address_gather); + std::array<uint32_t, 2> size_gather{}; + size_gather[0] = GetReg32(system, 1); + size_gather[1] = GetReg32(system, 4); + size = Convert<uint64_t>(size_gather); - // Map the memory. - R_TRY(code_mem->Map(address, size)); - } break; - case CodeMemoryOperation::Unmap: { - // Check that the region is in range. - R_UNLESS( - system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut), - ResultInvalidMemoryRegion); + ret = StoreProcessDataCache64From32(system, process_handle, address, size); - // Check the memory permission. - R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // Unmap the memory. - R_TRY(code_mem->Unmap(address, size)); - } break; - case CodeMemoryOperation::MapToOwner: { - // Check that the region is in range. - R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, - KMemoryState::GeneratedCode), - ResultInvalidMemoryRegion); +static void SvcWrap_FlushProcessDataCache64From32(Core::System& system) { + Result ret{}; - // Check the memory permission. - R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; - // Map the memory to its owner. - R_TRY(code_mem->MapToOwner(address, size, perm)); - } break; - case CodeMemoryOperation::UnmapFromOwner: { - // Check that the region is in range. - R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, - KMemoryState::GeneratedCode), - ResultInvalidMemoryRegion); + process_handle = Convert<Handle>(GetReg32(system, 0)); + std::array<uint32_t, 2> address_gather{}; + address_gather[0] = GetReg32(system, 2); + address_gather[1] = GetReg32(system, 3); + address = Convert<uint64_t>(address_gather); + std::array<uint32_t, 2> size_gather{}; + size_gather[0] = GetReg32(system, 1); + size_gather[1] = GetReg32(system, 4); + size = Convert<uint64_t>(size_gather); - // Check the memory permission. - R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); - - // Unmap the memory from its owner. - R_TRY(code_mem->UnmapFromOwner(address, size)); - } break; - default: - return ResultInvalidEnumValue; - } + ret = FlushProcessDataCache64From32(system, process_handle, address, size); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result ControlCodeMemory32(Core::System& system, Handle code_memory_handle, u32 operation, - u64 address, u64 size, Svc::MemoryPermission perm) { - return ControlCodeMemory(system, code_memory_handle, operation, address, size, perm); +static void SvcWrap_DebugActiveProcess64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint64_t process_id{}; + + std::array<uint32_t, 2> process_id_gather{}; + process_id_gather[0] = GetReg32(system, 2); + process_id_gather[1] = GetReg32(system, 3); + process_id = Convert<uint64_t>(process_id_gather); + + ret = DebugActiveProcess64From32(system, &out_handle, process_id); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static Result QueryProcessMemory(Core::System& system, VAddr memory_info_address, - VAddr page_info_address, Handle process_handle, VAddr address) { - LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); - if (process.IsNull()) { - LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", - process_handle); - return ResultInvalidHandle; - } +static void SvcWrap_BreakDebugProcess64From32(Core::System& system) { + Result ret{}; - auto& memory{system.Memory()}; - const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()}; + Handle debug_handle{}; - memory.Write64(memory_info_address + 0x00, memory_info.base_address); - memory.Write64(memory_info_address + 0x08, memory_info.size); - memory.Write32(memory_info_address + 0x10, static_cast<u32>(memory_info.state) & 0xff); - memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attribute)); - memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.permission)); - memory.Write32(memory_info_address + 0x1c, memory_info.ipc_count); - memory.Write32(memory_info_address + 0x20, memory_info.device_count); - memory.Write32(memory_info_address + 0x24, 0); + debug_handle = Convert<Handle>(GetReg32(system, 0)); - // Page info appears to be currently unused by the kernel and is always set to zero. - memory.Write32(page_info_address, 0); + ret = BreakDebugProcess64From32(system, debug_handle); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result QueryMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, - VAddr query_address) { - LOG_TRACE(Kernel_SVC, - "called, memory_info_address=0x{:016X}, page_info_address=0x{:016X}, " - "query_address=0x{:016X}", - memory_info_address, page_info_address, query_address); +static void SvcWrap_TerminateDebugProcess64From32(Core::System& system) { + Result ret{}; + + Handle debug_handle{}; + + debug_handle = Convert<Handle>(GetReg32(system, 0)); + + ret = TerminateDebugProcess64From32(system, debug_handle); - return QueryProcessMemory(system, memory_info_address, page_info_address, CurrentProcess, - query_address); + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result QueryMemory32(Core::System& system, u32 memory_info_address, u32 page_info_address, - u32 query_address) { - return QueryMemory(system, memory_info_address, page_info_address, query_address); +static void SvcWrap_GetDebugEvent64From32(Core::System& system) { + Result ret{}; + + uint32_t out_info{}; + Handle debug_handle{}; + + out_info = Convert<uint32_t>(GetReg32(system, 0)); + debug_handle = Convert<Handle>(GetReg32(system, 1)); + + ret = GetDebugEvent64From32(system, out_info, debug_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address, - u64 src_address, u64 size) { - LOG_DEBUG(Kernel_SVC, - "called. process_handle=0x{:08X}, dst_address=0x{:016X}, " - "src_address=0x{:016X}, size=0x{:016X}", - process_handle, dst_address, src_address, size); +static void SvcWrap_ContinueDebugEvent64From32(Core::System& system) { + Result ret{}; - if (!Common::Is4KBAligned(src_address)) { - LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", - src_address); - return ResultInvalidAddress; - } + Handle debug_handle{}; + uint32_t flags{}; + uint32_t thread_ids{}; + int32_t num_thread_ids{}; - if (!Common::Is4KBAligned(dst_address)) { - LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", - dst_address); - return ResultInvalidAddress; - } + debug_handle = Convert<Handle>(GetReg32(system, 0)); + flags = Convert<uint32_t>(GetReg32(system, 1)); + thread_ids = Convert<uint32_t>(GetReg32(system, 2)); + num_thread_ids = Convert<int32_t>(GetReg32(system, 3)); - if (size == 0 || !Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size); - return ResultInvalidSize; - } + ret = ContinueDebugEvent64From32(system, debug_handle, flags, thread_ids, num_thread_ids); - if (!IsValidAddressRange(dst_address, size)) { - LOG_ERROR(Kernel_SVC, - "Destination address range overflows the address space (dst_address=0x{:016X}, " - "size=0x{:016X}).", - dst_address, size); - return ResultInvalidCurrentMemory; - } + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - if (!IsValidAddressRange(src_address, size)) { - LOG_ERROR(Kernel_SVC, - "Source address range overflows the address space (src_address=0x{:016X}, " - "size=0x{:016X}).", - src_address, size); - return ResultInvalidCurrentMemory; - } +static void SvcWrap_GetProcessList64From32(Core::System& system) { + Result ret{}; - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); - if (process.IsNull()) { - LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", - process_handle); - return ResultInvalidHandle; - } + int32_t out_num_processes{}; + uint32_t out_process_ids{}; + int32_t max_out_count{}; - auto& page_table = process->PageTable(); - if (!page_table.IsInsideAddressSpace(src_address, size)) { - LOG_ERROR(Kernel_SVC, - "Source address range is not within the address space (src_address=0x{:016X}, " - "size=0x{:016X}).", - src_address, size); - return ResultInvalidCurrentMemory; - } + out_process_ids = Convert<uint32_t>(GetReg32(system, 1)); + max_out_count = Convert<int32_t>(GetReg32(system, 2)); - if (!page_table.IsInsideASLRRegion(dst_address, size)) { - LOG_ERROR(Kernel_SVC, - "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " - "size=0x{:016X}).", - dst_address, size); - return ResultInvalidMemoryRegion; - } + ret = GetProcessList64From32(system, &out_num_processes, out_process_ids, max_out_count); - return page_table.MapCodeMemory(dst_address, src_address, size); + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_num_processes)); } -static Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address, - u64 src_address, u64 size) { - LOG_DEBUG(Kernel_SVC, - "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, " - "size=0x{:016X}", - process_handle, dst_address, src_address, size); +static void SvcWrap_GetThreadList64From32(Core::System& system) { + Result ret{}; - if (!Common::Is4KBAligned(dst_address)) { - LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", - dst_address); - return ResultInvalidAddress; - } + int32_t out_num_threads{}; + uint32_t out_thread_ids{}; + int32_t max_out_count{}; + Handle debug_handle{}; - if (!Common::Is4KBAligned(src_address)) { - LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", - src_address); - return ResultInvalidAddress; - } + out_thread_ids = Convert<uint32_t>(GetReg32(system, 1)); + max_out_count = Convert<int32_t>(GetReg32(system, 2)); + debug_handle = Convert<Handle>(GetReg32(system, 3)); - if (size == 0 || !Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size); - return ResultInvalidSize; - } + ret = GetThreadList64From32(system, &out_num_threads, out_thread_ids, max_out_count, debug_handle); - if (!IsValidAddressRange(dst_address, size)) { - LOG_ERROR(Kernel_SVC, - "Destination address range overflows the address space (dst_address=0x{:016X}, " - "size=0x{:016X}).", - dst_address, size); - return ResultInvalidCurrentMemory; - } + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_num_threads)); +} - if (!IsValidAddressRange(src_address, size)) { - LOG_ERROR(Kernel_SVC, - "Source address range overflows the address space (src_address=0x{:016X}, " - "size=0x{:016X}).", - src_address, size); - return ResultInvalidCurrentMemory; - } +static void SvcWrap_GetDebugThreadContext64From32(Core::System& system) { + Result ret{}; - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); - if (process.IsNull()) { - LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", - process_handle); - return ResultInvalidHandle; - } + uint32_t out_context{}; + Handle debug_handle{}; + uint64_t thread_id{}; + uint32_t context_flags{}; - auto& page_table = process->PageTable(); - if (!page_table.IsInsideAddressSpace(src_address, size)) { - LOG_ERROR(Kernel_SVC, - "Source address range is not within the address space (src_address=0x{:016X}, " - "size=0x{:016X}).", - src_address, size); - return ResultInvalidCurrentMemory; - } + out_context = Convert<uint32_t>(GetReg32(system, 0)); + debug_handle = Convert<Handle>(GetReg32(system, 1)); + std::array<uint32_t, 2> thread_id_gather{}; + thread_id_gather[0] = GetReg32(system, 2); + thread_id_gather[1] = GetReg32(system, 3); + thread_id = Convert<uint64_t>(thread_id_gather); + context_flags = Convert<uint32_t>(GetReg32(system, 4)); - if (!page_table.IsInsideASLRRegion(dst_address, size)) { - LOG_ERROR(Kernel_SVC, - "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " - "size=0x{:016X}).", - dst_address, size); - return ResultInvalidMemoryRegion; - } + ret = GetDebugThreadContext64From32(system, out_context, debug_handle, thread_id, context_flags); - return page_table.UnmapCodeMemory(dst_address, src_address, size, - KPageTable::ICacheInvalidationStrategy::InvalidateAll); + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Exits the current process -static void ExitProcess(Core::System& system) { - auto* current_process = system.Kernel().CurrentProcess(); +static void SvcWrap_SetDebugThreadContext64From32(Core::System& system) { + Result ret{}; + + Handle debug_handle{}; + uint64_t thread_id{}; + uint32_t context{}; + uint32_t context_flags{}; - LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); - ASSERT_MSG(current_process->GetState() == KProcess::State::Running, - "Process has already exited"); + debug_handle = Convert<Handle>(GetReg32(system, 0)); + std::array<uint32_t, 2> thread_id_gather{}; + thread_id_gather[0] = GetReg32(system, 2); + thread_id_gather[1] = GetReg32(system, 3); + thread_id = Convert<uint64_t>(thread_id_gather); + context = Convert<uint32_t>(GetReg32(system, 1)); + context_flags = Convert<uint32_t>(GetReg32(system, 4)); - system.Exit(); + ret = SetDebugThreadContext64From32(system, debug_handle, thread_id, context, context_flags); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static void ExitProcess32(Core::System& system) { - ExitProcess(system); +static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system) { + Result ret{}; + + PageInfo out_page_info{}; + uint32_t out_memory_info{}; + Handle process_handle{}; + uint32_t address{}; + + out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetReg32(system, 2)); + address = Convert<uint32_t>(GetReg32(system, 3)); + + ret = QueryDebugProcessMemory64From32(system, out_memory_info, &out_page_info, process_handle, address); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_page_info)); } -namespace { +static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system) { + Result ret{}; + + uint32_t buffer{}; + Handle debug_handle{}; + uint32_t address{}; + uint32_t size{}; + + buffer = Convert<uint32_t>(GetReg32(system, 0)); + debug_handle = Convert<Handle>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetReg32(system, 2)); + size = Convert<uint32_t>(GetReg32(system, 3)); -constexpr bool IsValidVirtualCoreId(int32_t core_id) { - return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); + ret = ReadDebugProcessMemory64From32(system, buffer, debug_handle, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -} // Anonymous namespace +static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system) { + Result ret{}; -/// Creates a new thread -static Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, - VAddr stack_bottom, u32 priority, s32 core_id) { - LOG_DEBUG(Kernel_SVC, - "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, " - "priority=0x{:08X}, core_id=0x{:08X}", - entry_point, arg, stack_bottom, priority, core_id); + Handle debug_handle{}; + uint32_t buffer{}; + uint32_t address{}; + uint32_t size{}; - // Adjust core id, if it's the default magic. - auto& kernel = system.Kernel(); - auto& process = *kernel.CurrentProcess(); - if (core_id == IdealCoreUseProcessValue) { - core_id = process.GetIdealCoreId(); - } + debug_handle = Convert<Handle>(GetReg32(system, 0)); + buffer = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetReg32(system, 2)); + size = Convert<uint32_t>(GetReg32(system, 3)); - // Validate arguments. - if (!IsValidVirtualCoreId(core_id)) { - LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); - return ResultInvalidCoreId; - } - if (((1ULL << core_id) & process.GetCoreMask()) == 0) { - LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id); - return ResultInvalidCoreId; - } + ret = WriteDebugProcessMemory64From32(system, debug_handle, buffer, address, size); - if (HighestThreadPriority > priority || priority > LowestThreadPriority) { - LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority); - return ResultInvalidPriority; - } - if (!process.CheckThreadPriority(priority)) { - LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority); - return ResultInvalidPriority; - } + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // Reserve a new thread from the process resource limit (waiting up to 100ms). - KScopedResourceReservation thread_reservation( - kernel.CurrentProcess(), LimitableResource::ThreadCountMax, 1, - system.CoreTiming().GetGlobalTimeNs().count() + 100000000); - if (!thread_reservation.Succeeded()) { - LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); - return ResultLimitReached; - } +static void SvcWrap_SetHardwareBreakPoint64From32(Core::System& system) { + Result ret{}; - // Create the thread. - KThread* thread = KThread::Create(kernel); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached."); - return ResultOutOfResource; - } - SCOPE_EXIT({ thread->Close(); }); + HardwareBreakPointRegisterName name{}; + uint64_t flags{}; + uint64_t value{}; - // Initialize the thread. - { - KScopedLightLock lk{process.GetStateLock()}; - R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom, - priority, core_id, &process)); - } + name = Convert<HardwareBreakPointRegisterName>(GetReg32(system, 0)); + std::array<uint32_t, 2> flags_gather{}; + flags_gather[0] = GetReg32(system, 2); + flags_gather[1] = GetReg32(system, 3); + flags = Convert<uint64_t>(flags_gather); + std::array<uint32_t, 2> value_gather{}; + value_gather[0] = GetReg32(system, 1); + value_gather[1] = GetReg32(system, 4); + value = Convert<uint64_t>(value_gather); - // Set the thread name for debugging purposes. - thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle)); + ret = SetHardwareBreakPoint64From32(system, name, flags, value); - // Commit the thread reservation. - thread_reservation.Commit(); + SetReg32(system, 0, Convert<uint32_t>(ret)); +} - // Register the new thread. - KThread::Register(kernel, thread); +static void SvcWrap_GetDebugThreadParam64From32(Core::System& system) { + Result ret{}; - // Add the thread to the handle table. - R_TRY(process.GetHandleTable().Add(out_handle, thread)); + uint64_t out_64{}; + uint32_t out_32{}; + Handle debug_handle{}; + uint64_t thread_id{}; + DebugThreadParam param{}; - return ResultSuccess; + debug_handle = Convert<Handle>(GetReg32(system, 2)); + std::array<uint32_t, 2> thread_id_gather{}; + thread_id_gather[0] = GetReg32(system, 0); + thread_id_gather[1] = GetReg32(system, 1); + thread_id = Convert<uint64_t>(thread_id_gather); + param = Convert<DebugThreadParam>(GetReg32(system, 3)); + + ret = GetDebugThreadParam64From32(system, &out_64, &out_32, debug_handle, thread_id, param); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_64_scatter = Convert<std::array<uint32_t, 2>>(out_64); + SetReg32(system, 1, out_64_scatter[0]); + SetReg32(system, 2, out_64_scatter[1]); + SetReg32(system, 3, Convert<uint32_t>(out_32)); } -static Result CreateThread32(Core::System& system, Handle* out_handle, u32 priority, - u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { - return CreateThread(system, out_handle, entry_point, arg, stack_top, priority, processor_id); +static void SvcWrap_GetSystemInfo64From32(Core::System& system) { + Result ret{}; + + uint64_t out{}; + SystemInfoType info_type{}; + Handle handle{}; + uint64_t info_subtype{}; + + info_type = Convert<SystemInfoType>(GetReg32(system, 1)); + handle = Convert<Handle>(GetReg32(system, 2)); + std::array<uint32_t, 2> info_subtype_gather{}; + info_subtype_gather[0] = GetReg32(system, 0); + info_subtype_gather[1] = GetReg32(system, 3); + info_subtype = Convert<uint64_t>(info_subtype_gather); + + ret = GetSystemInfo64From32(system, &out, info_type, handle, info_subtype); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_scatter = Convert<std::array<uint32_t, 2>>(out); + SetReg32(system, 1, out_scatter[0]); + SetReg32(system, 2, out_scatter[1]); } -/// Starts the thread for the provided handle -static Result StartThread(Core::System& system, Handle thread_handle) { - LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); +static void SvcWrap_CreatePort64From32(Core::System& system) { + Result ret{}; - // Get the thread from its handle. - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + Handle out_server_handle{}; + Handle out_client_handle{}; + int32_t max_sessions{}; + bool is_light{}; + uint32_t name{}; - // Try to start the thread. - R_TRY(thread->Run()); + max_sessions = Convert<int32_t>(GetReg32(system, 2)); + is_light = Convert<bool>(GetReg32(system, 3)); + name = Convert<uint32_t>(GetReg32(system, 0)); - // If we succeeded, persist a reference to the thread. - thread->Open(); - system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe()); + ret = CreatePort64From32(system, &out_server_handle, &out_client_handle, max_sessions, is_light, name); - return ResultSuccess; + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_server_handle)); + SetReg32(system, 2, Convert<uint32_t>(out_client_handle)); } -static Result StartThread32(Core::System& system, Handle thread_handle) { - return StartThread(system, thread_handle); +static void SvcWrap_ManageNamedPort64From32(Core::System& system) { + Result ret{}; + + Handle out_server_handle{}; + uint32_t name{}; + int32_t max_sessions{}; + + name = Convert<uint32_t>(GetReg32(system, 1)); + max_sessions = Convert<int32_t>(GetReg32(system, 2)); + + ret = ManageNamedPort64From32(system, &out_server_handle, name, max_sessions); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_server_handle)); } -/// Called when a thread exits -static void ExitThread(Core::System& system) { - LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); +static void SvcWrap_ConnectToPort64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + Handle port{}; - auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); - system.GlobalSchedulerContext().RemoveThread(current_thread); - current_thread->Exit(); - system.Kernel().UnregisterInUseObject(current_thread); + port = Convert<Handle>(GetReg32(system, 1)); + + ret = ConnectToPort64From32(system, &out_handle, port); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static void ExitThread32(Core::System& system) { - ExitThread(system); +static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission perm{}; + + process_handle = Convert<Handle>(GetReg32(system, 0)); + std::array<uint32_t, 2> address_gather{}; + address_gather[0] = GetReg32(system, 2); + address_gather[1] = GetReg32(system, 3); + address = Convert<uint64_t>(address_gather); + std::array<uint32_t, 2> size_gather{}; + size_gather[0] = GetReg32(system, 1); + size_gather[1] = GetReg32(system, 4); + size = Convert<uint64_t>(size_gather); + perm = Convert<MemoryPermission>(GetReg32(system, 5)); + + ret = SetProcessMemoryPermission64From32(system, process_handle, address, size, perm); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Sleep the current thread -static void SleepThread(Core::System& system, s64 nanoseconds) { - auto& kernel = system.Kernel(); - const auto yield_type = static_cast<Svc::YieldType>(nanoseconds); - - LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); - - // When the input tick is positive, sleep. - if (nanoseconds > 0) { - // Convert the timeout from nanoseconds to ticks. - // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... - - // Sleep. - // NOTE: Nintendo does not check the result of this sleep. - static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds)); - } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { - KScheduler::YieldWithoutCoreMigration(kernel); - } else if (yield_type == Svc::YieldType::WithCoreMigration) { - KScheduler::YieldWithCoreMigration(kernel); - } else if (yield_type == Svc::YieldType::ToAnyThread) { - KScheduler::YieldToAnyThread(kernel); - } else { - // Nintendo does nothing at all if an otherwise invalid value is passed. - ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds); - } +static void SvcWrap_MapProcessMemory64From32(Core::System& system) { + Result ret{}; + + uint32_t dst_address{}; + Handle process_handle{}; + uint64_t src_address{}; + uint32_t size{}; + + dst_address = Convert<uint32_t>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetReg32(system, 1)); + std::array<uint32_t, 2> src_address_gather{}; + src_address_gather[0] = GetReg32(system, 2); + src_address_gather[1] = GetReg32(system, 3); + src_address = Convert<uint64_t>(src_address_gather); + size = Convert<uint32_t>(GetReg32(system, 4)); + + ret = MapProcessMemory64From32(system, dst_address, process_handle, src_address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) { - const auto nanoseconds = static_cast<s64>(u64{nanoseconds_low} | (u64{nanoseconds_high} << 32)); - SleepThread(system, nanoseconds); +static void SvcWrap_UnmapProcessMemory64From32(Core::System& system) { + Result ret{}; + + uint32_t dst_address{}; + Handle process_handle{}; + uint64_t src_address{}; + uint32_t size{}; + + dst_address = Convert<uint32_t>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetReg32(system, 1)); + std::array<uint32_t, 2> src_address_gather{}; + src_address_gather[0] = GetReg32(system, 2); + src_address_gather[1] = GetReg32(system, 3); + src_address = Convert<uint64_t>(src_address_gather); + size = Convert<uint32_t>(GetReg32(system, 4)); + + ret = UnmapProcessMemory64From32(system, dst_address, process_handle, src_address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Wait process wide key atomic -static Result WaitProcessWideKeyAtomic(Core::System& system, VAddr address, VAddr cv_key, u32 tag, - s64 timeout_ns) { - LOG_TRACE(Kernel_SVC, "called address={:X}, cv_key={:X}, tag=0x{:08X}, timeout_ns={}", address, - cv_key, tag, timeout_ns); +static void SvcWrap_QueryProcessMemory64From32(Core::System& system) { + Result ret{}; - // Validate input. - if (IsKernelAddress(address)) { - LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address); - return ResultInvalidCurrentMemory; - } - if (!Common::IsAligned(address, sizeof(s32))) { - LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address); - return ResultInvalidAddress; - } + PageInfo out_page_info{}; + uint32_t out_memory_info{}; + Handle process_handle{}; + uint64_t address{}; - // Convert timeout from nanoseconds to ticks. - s64 timeout{}; - if (timeout_ns > 0) { - const s64 offset_tick(timeout_ns); - if (offset_tick > 0) { - timeout = offset_tick + 2; - if (timeout <= 0) { - timeout = std::numeric_limits<s64>::max(); - } - } else { - timeout = std::numeric_limits<s64>::max(); - } - } else { - timeout = timeout_ns; - } + out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetReg32(system, 2)); + std::array<uint32_t, 2> address_gather{}; + address_gather[0] = GetReg32(system, 1); + address_gather[1] = GetReg32(system, 3); + address = Convert<uint64_t>(address_gather); + + ret = QueryProcessMemory64From32(system, out_memory_info, &out_page_info, process_handle, address); - // Wait on the condition variable. - return system.Kernel().CurrentProcess()->WaitConditionVariable( - address, Common::AlignDown(cv_key, sizeof(u32)), tag, timeout); + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_page_info)); } -static Result WaitProcessWideKeyAtomic32(Core::System& system, u32 address, u32 cv_key, u32 tag, - u32 timeout_ns_low, u32 timeout_ns_high) { - const auto timeout_ns = static_cast<s64>(timeout_ns_low | (u64{timeout_ns_high} << 32)); - return WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns); +static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t dst_address{}; + uint64_t src_address{}; + uint64_t size{}; + + process_handle = Convert<Handle>(GetReg32(system, 0)); + std::array<uint32_t, 2> dst_address_gather{}; + dst_address_gather[0] = GetReg32(system, 2); + dst_address_gather[1] = GetReg32(system, 3); + dst_address = Convert<uint64_t>(dst_address_gather); + std::array<uint32_t, 2> src_address_gather{}; + src_address_gather[0] = GetReg32(system, 1); + src_address_gather[1] = GetReg32(system, 4); + src_address = Convert<uint64_t>(src_address_gather); + std::array<uint32_t, 2> size_gather{}; + size_gather[0] = GetReg32(system, 5); + size_gather[1] = GetReg32(system, 6); + size = Convert<uint64_t>(size_gather); + + ret = MapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -/// Signal process wide key -static void SignalProcessWideKey(Core::System& system, VAddr cv_key, s32 count) { - LOG_TRACE(Kernel_SVC, "called, cv_key=0x{:X}, count=0x{:08X}", cv_key, count); +static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system) { + Result ret{}; - // Signal the condition variable. - return system.Kernel().CurrentProcess()->SignalConditionVariable( - Common::AlignDown(cv_key, sizeof(u32)), count); + Handle process_handle{}; + uint64_t dst_address{}; + uint64_t src_address{}; + uint64_t size{}; + + process_handle = Convert<Handle>(GetReg32(system, 0)); + std::array<uint32_t, 2> dst_address_gather{}; + dst_address_gather[0] = GetReg32(system, 2); + dst_address_gather[1] = GetReg32(system, 3); + dst_address = Convert<uint64_t>(dst_address_gather); + std::array<uint32_t, 2> src_address_gather{}; + src_address_gather[0] = GetReg32(system, 1); + src_address_gather[1] = GetReg32(system, 4); + src_address = Convert<uint64_t>(src_address_gather); + std::array<uint32_t, 2> size_gather{}; + size_gather[0] = GetReg32(system, 5); + size_gather[1] = GetReg32(system, 6); + size = Convert<uint64_t>(size_gather); + + ret = UnmapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static void SignalProcessWideKey32(Core::System& system, u32 cv_key, s32 count) { - SignalProcessWideKey(system, cv_key, count); +static void SvcWrap_CreateProcess64From32(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint32_t parameters{}; + uint32_t caps{}; + int32_t num_caps{}; + + parameters = Convert<uint32_t>(GetReg32(system, 1)); + caps = Convert<uint32_t>(GetReg32(system, 2)); + num_caps = Convert<int32_t>(GetReg32(system, 3)); + + ret = CreateProcess64From32(system, &out_handle, parameters, caps, num_caps); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -namespace { +static void SvcWrap_StartProcess64From32(Core::System& system) { + Result ret{}; -constexpr bool IsValidSignalType(Svc::SignalType type) { - switch (type) { - case Svc::SignalType::Signal: - case Svc::SignalType::SignalAndIncrementIfEqual: - case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual: - return true; - default: - return false; - } + Handle process_handle{}; + int32_t priority{}; + int32_t core_id{}; + uint64_t main_thread_stack_size{}; + + process_handle = Convert<Handle>(GetReg32(system, 0)); + priority = Convert<int32_t>(GetReg32(system, 1)); + core_id = Convert<int32_t>(GetReg32(system, 2)); + std::array<uint32_t, 2> main_thread_stack_size_gather{}; + main_thread_stack_size_gather[0] = GetReg32(system, 3); + main_thread_stack_size_gather[1] = GetReg32(system, 4); + main_thread_stack_size = Convert<uint64_t>(main_thread_stack_size_gather); + + ret = StartProcess64From32(system, process_handle, priority, core_id, main_thread_stack_size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -constexpr bool IsValidArbitrationType(Svc::ArbitrationType type) { - switch (type) { - case Svc::ArbitrationType::WaitIfLessThan: - case Svc::ArbitrationType::DecrementAndWaitIfLessThan: - case Svc::ArbitrationType::WaitIfEqual: - return true; - default: - return false; - } +static void SvcWrap_TerminateProcess64From32(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + + process_handle = Convert<Handle>(GetReg32(system, 0)); + + ret = TerminateProcess64From32(system, process_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -} // namespace +static void SvcWrap_GetProcessInfo64From32(Core::System& system) { + Result ret{}; -// Wait for an address (via Address Arbiter) -static Result WaitForAddress(Core::System& system, VAddr address, Svc::ArbitrationType arb_type, - s32 value, s64 timeout_ns) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}", - address, arb_type, value, timeout_ns); + int64_t out_info{}; + Handle process_handle{}; + ProcessInfoType info_type{}; - // Validate input. - if (IsKernelAddress(address)) { - LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address); - return ResultInvalidCurrentMemory; - } - if (!Common::IsAligned(address, sizeof(s32))) { - LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address); - return ResultInvalidAddress; - } - if (!IsValidArbitrationType(arb_type)) { - LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type); - return ResultInvalidEnumValue; - } + process_handle = Convert<Handle>(GetReg32(system, 1)); + info_type = Convert<ProcessInfoType>(GetReg32(system, 2)); - // Convert timeout from nanoseconds to ticks. - s64 timeout{}; - if (timeout_ns > 0) { - const s64 offset_tick(timeout_ns); - if (offset_tick > 0) { - timeout = offset_tick + 2; - if (timeout <= 0) { - timeout = std::numeric_limits<s64>::max(); - } - } else { - timeout = std::numeric_limits<s64>::max(); - } - } else { - timeout = timeout_ns; - } + ret = GetProcessInfo64From32(system, &out_info, process_handle, info_type); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + auto out_info_scatter = Convert<std::array<uint32_t, 2>>(out_info); + SetReg32(system, 1, out_info_scatter[0]); + SetReg32(system, 2, out_info_scatter[1]); +} + +static void SvcWrap_CreateResourceLimit64From32(Core::System& system) { + Result ret{}; - return system.Kernel().CurrentProcess()->WaitAddressArbiter(address, arb_type, value, timeout); + Handle out_handle{}; + + ret = CreateResourceLimit64From32(system, &out_handle); + + SetReg32(system, 0, Convert<uint32_t>(ret)); + SetReg32(system, 1, Convert<uint32_t>(out_handle)); } -static Result WaitForAddress32(Core::System& system, u32 address, Svc::ArbitrationType arb_type, - s32 value, u32 timeout_ns_low, u32 timeout_ns_high) { - const auto timeout = static_cast<s64>(timeout_ns_low | (u64{timeout_ns_high} << 32)); - return WaitForAddress(system, address, arb_type, value, timeout); +static void SvcWrap_SetResourceLimitLimitValue64From32(Core::System& system) { + Result ret{}; + + Handle resource_limit_handle{}; + LimitableResource which{}; + int64_t limit_value{}; + + resource_limit_handle = Convert<Handle>(GetReg32(system, 0)); + which = Convert<LimitableResource>(GetReg32(system, 1)); + std::array<uint32_t, 2> limit_value_gather{}; + limit_value_gather[0] = GetReg32(system, 2); + limit_value_gather[1] = GetReg32(system, 3); + limit_value = Convert<int64_t>(limit_value_gather); + + ret = SetResourceLimitLimitValue64From32(system, resource_limit_handle, which, limit_value); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -// Signals to an address (via Address Arbiter) -static Result SignalToAddress(Core::System& system, VAddr address, Svc::SignalType signal_type, - s32 value, s32 count) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}", - address, signal_type, value, count); +static void SvcWrap_MapInsecureMemory64From32(Core::System& system) { + Result ret{}; - // Validate input. - if (IsKernelAddress(address)) { - LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address); - return ResultInvalidCurrentMemory; - } - if (!Common::IsAligned(address, sizeof(s32))) { - LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address); - return ResultInvalidAddress; - } - if (!IsValidSignalType(signal_type)) { - LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type); - return ResultInvalidEnumValue; - } + uint32_t address{}; + uint32_t size{}; + + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); - return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, - count); + ret = MapInsecureMemory64From32(system, address, size); + + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static void SynchronizePreemptionState(Core::System& system) { - auto& kernel = system.Kernel(); +static void SvcWrap_UnmapInsecureMemory64From32(Core::System& system) { + Result ret{}; - // Lock the scheduler. - KScopedSchedulerLock sl{kernel}; + uint32_t address{}; + uint32_t size{}; - // If the current thread is pinned, unpin it. - KProcess* cur_process = system.Kernel().CurrentProcess(); - const auto core_id = GetCurrentCoreId(kernel); + address = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetReg32(system, 1)); - if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) { - // Clear the current thread's interrupt flag. - GetCurrentThread(kernel).ClearInterruptFlag(); + ret = UnmapInsecureMemory64From32(system, address, size); - // Unpin the current thread. - cur_process->UnpinCurrentThread(core_id); - } + SetReg32(system, 0, Convert<uint32_t>(ret)); } -static Result SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type, - s32 value, s32 count) { - return SignalToAddress(system, address, signal_type, value, count); +static void SvcWrap_SetHeapSize64(Core::System& system) { + Result ret{}; + + uintptr_t out_address{}; + uint64_t size{}; + + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = SetHeapSize64(system, &out_address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_address)); } -static void KernelDebug([[maybe_unused]] Core::System& system, - [[maybe_unused]] u32 kernel_debug_type, [[maybe_unused]] u64 param1, - [[maybe_unused]] u64 param2, [[maybe_unused]] u64 param3) { - // Intentionally do nothing, as this does nothing in released kernel binaries. +static void SvcWrap_SetMemoryPermission64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + MemoryPermission perm{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + perm = Convert<MemoryPermission>(GetReg64(system, 2)); + + ret = SetMemoryPermission64(system, address, size, perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static void ChangeKernelTraceState([[maybe_unused]] Core::System& system, - [[maybe_unused]] u32 trace_state) { - // Intentionally do nothing, as this does nothing in released kernel binaries. +static void SvcWrap_SetMemoryAttribute64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + uint32_t mask{}; + uint32_t attr{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + mask = Convert<uint32_t>(GetReg64(system, 2)); + attr = Convert<uint32_t>(GetReg64(system, 3)); + + ret = SetMemoryAttribute64(system, address, size, mask, attr); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -/// This returns the total CPU ticks elapsed since the CPU was powered-on -static u64 GetSystemTick(Core::System& system) { - LOG_TRACE(Kernel_SVC, "called"); +static void SvcWrap_MapMemory64(Core::System& system) { + Result ret{}; - auto& core_timing = system.CoreTiming(); + uint64_t dst_address{}; + uint64_t src_address{}; + uint64_t size{}; - // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) - const u64 result{core_timing.GetClockTicks()}; + dst_address = Convert<uint64_t>(GetReg64(system, 0)); + src_address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); - if (!system.Kernel().IsMulticore()) { - core_timing.AddTicks(400U); - } + ret = MapMemory64(system, dst_address, src_address, size); - return result; + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { - const auto time = GetSystemTick(system); - *time_low = static_cast<u32>(time); - *time_high = static_cast<u32>(time >> 32); +static void SvcWrap_UnmapMemory64(Core::System& system) { + Result ret{}; + + uint64_t dst_address{}; + uint64_t src_address{}; + uint64_t size{}; + + dst_address = Convert<uint64_t>(GetReg64(system, 0)); + src_address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = UnmapMemory64(system, dst_address, src_address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -/// Close a handle -static Result CloseHandle(Core::System& system, Handle handle) { - LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); +static void SvcWrap_QueryMemory64(Core::System& system) { + Result ret{}; - // Remove the handle. - R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle), - ResultInvalidHandle); + PageInfo out_page_info{}; + uint64_t out_memory_info{}; + uint64_t address{}; - return ResultSuccess; + out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 2)); + + ret = QueryMemory64(system, out_memory_info, &out_page_info, address); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_page_info)); } -static Result CloseHandle32(Core::System& system, Handle handle) { - return CloseHandle(system, handle); +static void SvcWrap_ExitProcess64(Core::System& system) { + ExitProcess64(system); } -/// Clears the signaled state of an event or process. -static Result ResetSignal(Core::System& system, Handle handle) { - LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); +static void SvcWrap_CreateThread64(Core::System& system) { + Result ret{}; - // Get the current handle table. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + Handle out_handle{}; + uint64_t func{}; + uint64_t arg{}; + uint64_t stack_bottom{}; + int32_t priority{}; + int32_t core_id{}; - // Try to reset as readable event. - { - KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle); - if (readable_event.IsNotNull()) { - return readable_event->Reset(); - } - } + func = Convert<uint64_t>(GetReg64(system, 1)); + arg = Convert<uint64_t>(GetReg64(system, 2)); + stack_bottom = Convert<uint64_t>(GetReg64(system, 3)); + priority = Convert<int32_t>(GetReg64(system, 4)); + core_id = Convert<int32_t>(GetReg64(system, 5)); - // Try to reset as process. - { - KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); - if (process.IsNotNull()) { - return process->Reset(); - } - } + ret = CreateThread64(system, &out_handle, func, arg, stack_bottom, priority, core_id); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_StartThread64(Core::System& system) { + Result ret{}; + + Handle thread_handle{}; - LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle); + thread_handle = Convert<Handle>(GetReg64(system, 0)); - return ResultInvalidHandle; + ret = StartThread64(system, thread_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result ResetSignal32(Core::System& system, Handle handle) { - return ResetSignal(system, handle); +static void SvcWrap_ExitThread64(Core::System& system) { + ExitThread64(system); } -namespace { +static void SvcWrap_SleepThread64(Core::System& system) { + int64_t ns{}; -constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { - switch (perm) { - case MemoryPermission::None: - case MemoryPermission::Read: - case MemoryPermission::ReadWrite: - return true; - default: - return false; - } + ns = Convert<int64_t>(GetReg64(system, 0)); + + SleepThread64(system, ns); } -} // Anonymous namespace +static void SvcWrap_GetThreadPriority64(Core::System& system) { + Result ret{}; -/// Creates a TransferMemory object -static Result CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, - MemoryPermission map_perm) { - auto& kernel = system.Kernel(); + int32_t out_priority{}; + Handle thread_handle{}; + + thread_handle = Convert<Handle>(GetReg64(system, 1)); + + ret = GetThreadPriority64(system, &out_priority, thread_handle); - // Validate the size. - R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); - R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_priority)); +} + +static void SvcWrap_SetThreadPriority64(Core::System& system) { + Result ret{}; + + Handle thread_handle{}; + int32_t priority{}; + + thread_handle = Convert<Handle>(GetReg64(system, 0)); + priority = Convert<int32_t>(GetReg64(system, 1)); - // Validate the permissions. - R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); + ret = SetThreadPriority64(system, thread_handle, priority); - // Get the current process and handle table. - auto& process = *kernel.CurrentProcess(); - auto& handle_table = process.GetHandleTable(); + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_GetThreadCoreMask64(Core::System& system) { + Result ret{}; - // Reserve a new transfer memory from the process resource limit. - KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), - LimitableResource::TransferMemoryCountMax); - R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached); + int32_t out_core_id{}; + uint64_t out_affinity_mask{}; + Handle thread_handle{}; - // Create the transfer memory. - KTransferMemory* trmem = KTransferMemory::Create(kernel); - R_UNLESS(trmem != nullptr, ResultOutOfResource); + thread_handle = Convert<Handle>(GetReg64(system, 2)); - // Ensure the only reference is in the handle table when we're done. - SCOPE_EXIT({ trmem->Close(); }); + ret = GetThreadCoreMask64(system, &out_core_id, &out_affinity_mask, thread_handle); - // Ensure that the region is in range. - R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory); + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_core_id)); + SetReg64(system, 2, Convert<uint64_t>(out_affinity_mask)); +} - // Initialize the transfer memory. - R_TRY(trmem->Initialize(address, size, map_perm)); +static void SvcWrap_SetThreadCoreMask64(Core::System& system) { + Result ret{}; - // Commit the reservation. - trmem_reservation.Commit(); + Handle thread_handle{}; + int32_t core_id{}; + uint64_t affinity_mask{}; - // Register the transfer memory. - KTransferMemory::Register(kernel, trmem); + thread_handle = Convert<Handle>(GetReg64(system, 0)); + core_id = Convert<int32_t>(GetReg64(system, 1)); + affinity_mask = Convert<uint64_t>(GetReg64(system, 2)); - // Add the transfer memory to the handle table. - R_TRY(handle_table.Add(out, trmem)); + ret = SetThreadCoreMask64(system, thread_handle, core_id, affinity_mask); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size, - MemoryPermission map_perm) { - return CreateTransferMemory(system, out, address, size, map_perm); +static void SvcWrap_GetCurrentProcessorNumber64(Core::System& system) { + int32_t ret{}; + + ret = GetCurrentProcessorNumber64(system); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, - u64* out_affinity_mask) { - LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); +static void SvcWrap_SignalEvent64(Core::System& system) { + Result ret{}; + + Handle event_handle{}; - // Get the thread from its handle. - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + event_handle = Convert<Handle>(GetReg64(system, 0)); - // Get the core mask. - R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); + ret = SignalEvent64(system, event_handle); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id, - u32* out_affinity_mask_low, u32* out_affinity_mask_high) { - u64 out_affinity_mask{}; - const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask); - *out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32); - *out_affinity_mask_low = static_cast<u32>(out_affinity_mask); - return result; +static void SvcWrap_ClearEvent64(Core::System& system) { + Result ret{}; + + Handle event_handle{}; + + event_handle = Convert<Handle>(GetReg64(system, 0)); + + ret = ClearEvent64(system, event_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, - u64 affinity_mask) { - // Determine the core id/affinity mask. - if (core_id == IdealCoreUseProcessValue) { - core_id = system.Kernel().CurrentProcess()->GetIdealCoreId(); - affinity_mask = (1ULL << core_id); - } else { - // Validate the affinity mask. - const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask(); - R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId); - R_UNLESS(affinity_mask != 0, ResultInvalidCombination); - - // Validate the core id. - if (IsValidVirtualCoreId(core_id)) { - R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination); - } else { - R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare, - ResultInvalidCoreId); - } - } +static void SvcWrap_MapSharedMemory64(Core::System& system) { + Result ret{}; + + Handle shmem_handle{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission map_perm{}; - // Get the thread from its handle. - KScopedAutoObject thread = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle); - R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + shmem_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + map_perm = Convert<MemoryPermission>(GetReg64(system, 3)); - // Set the core mask. - R_TRY(thread->SetCoreMask(core_id, affinity_mask)); + ret = MapSharedMemory64(system, shmem_handle, address, size, map_perm); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id, - u32 affinity_mask_low, u32 affinity_mask_high) { - const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); - return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask); +static void SvcWrap_UnmapSharedMemory64(Core::System& system) { + Result ret{}; + + Handle shmem_handle{}; + uint64_t address{}; + uint64_t size{}; + + shmem_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = UnmapSharedMemory64(system, shmem_handle, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result SignalEvent(Core::System& system, Handle event_handle) { - LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); +static void SvcWrap_CreateTransferMemory64(Core::System& system) { + Result ret{}; - // Get the current handle table. - const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + Handle out_handle{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission map_perm{}; - // Get the event. - KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle); - R_UNLESS(event.IsNotNull(), ResultInvalidHandle); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + map_perm = Convert<MemoryPermission>(GetReg64(system, 3)); - return event->Signal(); + ret = CreateTransferMemory64(system, &out_handle, address, size, map_perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); } -static Result SignalEvent32(Core::System& system, Handle event_handle) { - return SignalEvent(system, event_handle); +static void SvcWrap_CloseHandle64(Core::System& system) { + Result ret{}; + + Handle handle{}; + + handle = Convert<Handle>(GetReg64(system, 0)); + + ret = CloseHandle64(system, handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result ClearEvent(Core::System& system, Handle event_handle) { - LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); +static void SvcWrap_ResetSignal64(Core::System& system) { + Result ret{}; - // Get the current handle table. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + Handle handle{}; - // Try to clear the writable event. - { - KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle); - if (event.IsNotNull()) { - return event->Clear(); - } - } + handle = Convert<Handle>(GetReg64(system, 0)); - // Try to clear the readable event. - { - KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle); - if (readable_event.IsNotNull()) { - return readable_event->Clear(); - } - } + ret = ResetSignal64(system, handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} - LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle); +static void SvcWrap_WaitSynchronization64(Core::System& system) { + Result ret{}; - return ResultInvalidHandle; + int32_t out_index{}; + uint64_t handles{}; + int32_t num_handles{}; + int64_t timeout_ns{}; + + handles = Convert<uint64_t>(GetReg64(system, 1)); + num_handles = Convert<int32_t>(GetReg64(system, 2)); + timeout_ns = Convert<int64_t>(GetReg64(system, 3)); + + ret = WaitSynchronization64(system, &out_index, handles, num_handles, timeout_ns); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_index)); } -static Result ClearEvent32(Core::System& system, Handle event_handle) { - return ClearEvent(system, event_handle); +static void SvcWrap_CancelSynchronization64(Core::System& system) { + Result ret{}; + + Handle handle{}; + + handle = Convert<Handle>(GetReg64(system, 0)); + + ret = CancelSynchronization64(system, handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) { - LOG_DEBUG(Kernel_SVC, "called"); +static void SvcWrap_ArbitrateLock64(Core::System& system) { + Result ret{}; - // Get the kernel reference and handle table. - auto& kernel = system.Kernel(); - auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + Handle thread_handle{}; + uint64_t address{}; + uint32_t tag{}; - // Reserve a new event from the process resource limit - KScopedResourceReservation event_reservation(kernel.CurrentProcess(), - LimitableResource::EventCountMax); - R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); + thread_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + tag = Convert<uint32_t>(GetReg64(system, 2)); - // Create a new event. - KEvent* event = KEvent::Create(kernel); - R_UNLESS(event != nullptr, ResultOutOfResource); + ret = ArbitrateLock64(system, thread_handle, address, tag); - // Initialize the event. - event->Initialize(kernel.CurrentProcess()); + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_ArbitrateUnlock64(Core::System& system) { + Result ret{}; - // Commit the thread reservation. - event_reservation.Commit(); + uint64_t address{}; - // Ensure that we clean up the event (and its only references are handle table) on function end. - SCOPE_EXIT({ - event->GetReadableEvent().Close(); - event->Close(); - }); + address = Convert<uint64_t>(GetReg64(system, 0)); - // Register the event. - KEvent::Register(kernel, event); + ret = ArbitrateUnlock64(system, address); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} - // Add the event to the handle table. - R_TRY(handle_table.Add(out_write, event)); +static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system) { + Result ret{}; - // Ensure that we maintaing a clean handle state on exit. - auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); }); + uint64_t address{}; + uint64_t cv_key{}; + uint32_t tag{}; + int64_t timeout_ns{}; - // Add the readable event to the handle table. - R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); + address = Convert<uint64_t>(GetReg64(system, 0)); + cv_key = Convert<uint64_t>(GetReg64(system, 1)); + tag = Convert<uint32_t>(GetReg64(system, 2)); + timeout_ns = Convert<int64_t>(GetReg64(system, 3)); - // We succeeded. - handle_guard.Cancel(); - return ResultSuccess; + ret = WaitProcessWideKeyAtomic64(system, address, cv_key, tag, timeout_ns); + + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result CreateEvent32(Core::System& system, Handle* out_write, Handle* out_read) { - return CreateEvent(system, out_write, out_read); +static void SvcWrap_SignalProcessWideKey64(Core::System& system) { + uint64_t cv_key{}; + int32_t count{}; + + cv_key = Convert<uint64_t>(GetReg64(system, 0)); + count = Convert<int32_t>(GetReg64(system, 1)); + + SignalProcessWideKey64(system, cv_key, count); } -static Result GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); +static void SvcWrap_GetSystemTick64(Core::System& system) { + int64_t ret{}; - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); - if (process.IsNull()) { - LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", - process_handle); - return ResultInvalidHandle; - } + ret = GetSystemTick64(system); - const auto info_type = static_cast<ProcessInfoType>(type); - if (info_type != ProcessInfoType::ProcessState) { - LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead", type); - return ResultInvalidEnumValue; - } + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_ConnectToNamedPort64(Core::System& system) { + Result ret{}; - *out = static_cast<u64>(process->GetState()); - return ResultSuccess; + Handle out_handle{}; + uint64_t name{}; + + name = Convert<uint64_t>(GetReg64(system, 1)); + + ret = ConnectToNamedPort64(system, &out_handle, name); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); } -static Result CreateResourceLimit(Core::System& system, Handle* out_handle) { - LOG_DEBUG(Kernel_SVC, "called"); +static void SvcWrap_SendSyncRequest64(Core::System& system) { + Result ret{}; - // Create a new resource limit. - auto& kernel = system.Kernel(); - KResourceLimit* resource_limit = KResourceLimit::Create(kernel); - R_UNLESS(resource_limit != nullptr, ResultOutOfResource); + Handle session_handle{}; - // Ensure we don't leak a reference to the limit. - SCOPE_EXIT({ resource_limit->Close(); }); + session_handle = Convert<Handle>(GetReg64(system, 0)); - // Initialize the resource limit. - resource_limit->Initialize(&system.CoreTiming()); + ret = SendSyncRequest64(system, session_handle); - // Register the limit. - KResourceLimit::Register(kernel, resource_limit); + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_SendSyncRequestWithUserBuffer64(Core::System& system) { + Result ret{}; + + uint64_t message_buffer{}; + uint64_t message_buffer_size{}; + Handle session_handle{}; + + message_buffer = Convert<uint64_t>(GetReg64(system, 0)); + message_buffer_size = Convert<uint64_t>(GetReg64(system, 1)); + session_handle = Convert<Handle>(GetReg64(system, 2)); - // Add the limit to the handle table. - R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit)); + ret = SendSyncRequestWithUserBuffer64(system, message_buffer, message_buffer_size, session_handle); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value, - Handle resource_limit_handle, LimitableResource which) { - LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, - which); +static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system) { + Result ret{}; - // Validate the resource. - R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + Handle out_event_handle{}; + uint64_t message_buffer{}; + uint64_t message_buffer_size{}; + Handle session_handle{}; - // Get the resource limit. - auto& kernel = system.Kernel(); - KScopedAutoObject resource_limit = - kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); - R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + message_buffer = Convert<uint64_t>(GetReg64(system, 1)); + message_buffer_size = Convert<uint64_t>(GetReg64(system, 2)); + session_handle = Convert<Handle>(GetReg64(system, 3)); - // Get the limit value. - *out_limit_value = resource_limit->GetLimitValue(which); + ret = SendAsyncRequestWithUserBuffer64(system, &out_event_handle, message_buffer, message_buffer_size, session_handle); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_event_handle)); } -static Result GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value, - Handle resource_limit_handle, LimitableResource which) { - LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, - which); +static void SvcWrap_GetProcessId64(Core::System& system) { + Result ret{}; - // Validate the resource. - R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + uint64_t out_process_id{}; + Handle process_handle{}; - // Get the resource limit. - auto& kernel = system.Kernel(); - KScopedAutoObject resource_limit = - kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); - R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + process_handle = Convert<Handle>(GetReg64(system, 1)); - // Get the current value. - *out_current_value = resource_limit->GetCurrentValue(which); + ret = GetProcessId64(system, &out_process_id, process_handle); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_process_id)); } -static Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, - LimitableResource which, u64 limit_value) { - LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}", - resource_limit_handle, which, limit_value); +static void SvcWrap_GetThreadId64(Core::System& system) { + Result ret{}; - // Validate the resource. - R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + uint64_t out_thread_id{}; + Handle thread_handle{}; - // Get the resource limit. - auto& kernel = system.Kernel(); - KScopedAutoObject resource_limit = - kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); - R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + thread_handle = Convert<Handle>(GetReg64(system, 1)); - // Set the limit value. - R_TRY(resource_limit->SetLimitValue(which, limit_value)); + ret = GetThreadId64(system, &out_thread_id, thread_handle); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_thread_id)); } -static Result GetProcessList(Core::System& system, u32* out_num_processes, VAddr out_process_ids, - u32 out_process_ids_size) { - LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}", - out_process_ids, out_process_ids_size); +static void SvcWrap_Break64(Core::System& system) { + BreakReason break_reason{}; + uint64_t arg{}; + uint64_t size{}; - // If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail. - if ((out_process_ids_size & 0xF0000000) != 0) { - LOG_ERROR(Kernel_SVC, - "Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}", - out_process_ids_size); - return ResultOutOfRange; - } + break_reason = Convert<BreakReason>(GetReg64(system, 0)); + arg = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); - const auto& kernel = system.Kernel(); - const auto total_copy_size = out_process_ids_size * sizeof(u64); + Break64(system, break_reason, arg, size); +} - if (out_process_ids_size > 0 && !kernel.CurrentProcess()->PageTable().IsInsideAddressSpace( - out_process_ids, total_copy_size)) { - LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", - out_process_ids, out_process_ids + total_copy_size); - return ResultInvalidCurrentMemory; - } +static void SvcWrap_OutputDebugString64(Core::System& system) { + Result ret{}; - auto& memory = system.Memory(); - const auto& process_list = kernel.GetProcessList(); - const auto num_processes = process_list.size(); - const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); + uint64_t debug_str{}; + uint64_t len{}; - for (std::size_t i = 0; i < copy_amount; ++i) { - memory.Write64(out_process_ids, process_list[i]->GetProcessID()); - out_process_ids += sizeof(u64); - } + debug_str = Convert<uint64_t>(GetReg64(system, 0)); + len = Convert<uint64_t>(GetReg64(system, 1)); + + ret = OutputDebugString64(system, debug_str, len); - *out_num_processes = static_cast<u32>(num_processes); - return ResultSuccess; + SetReg64(system, 0, Convert<uint64_t>(ret)); } -static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids, - u32 out_thread_ids_size, Handle debug_handle) { - // TODO: Handle this case when debug events are supported. - UNIMPLEMENTED_IF(debug_handle != InvalidHandle); +static void SvcWrap_ReturnFromException64(Core::System& system) { + Result result{}; - LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}", - out_thread_ids, out_thread_ids_size); + result = Convert<Result>(GetReg64(system, 0)); - // If the size is negative or larger than INT32_MAX / sizeof(u64) - if ((out_thread_ids_size & 0xF0000000) != 0) { - LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}", - out_thread_ids_size); - return ResultOutOfRange; - } + ReturnFromException64(system, result); +} - auto* const current_process = system.Kernel().CurrentProcess(); - const auto total_copy_size = out_thread_ids_size * sizeof(u64); +static void SvcWrap_GetInfo64(Core::System& system) { + Result ret{}; - if (out_thread_ids_size > 0 && - !current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) { - LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", - out_thread_ids, out_thread_ids + total_copy_size); - return ResultInvalidCurrentMemory; - } + uint64_t out{}; + InfoType info_type{}; + Handle handle{}; + uint64_t info_subtype{}; - auto& memory = system.Memory(); - const auto& thread_list = current_process->GetThreadList(); - const auto num_threads = thread_list.size(); - const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); + info_type = Convert<InfoType>(GetReg64(system, 1)); + handle = Convert<Handle>(GetReg64(system, 2)); + info_subtype = Convert<uint64_t>(GetReg64(system, 3)); - auto list_iter = thread_list.cbegin(); - for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { - memory.Write64(out_thread_ids, (*list_iter)->GetThreadID()); - out_thread_ids += sizeof(u64); - } + ret = GetInfo64(system, &out, info_type, handle, info_subtype); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out)); +} + +static void SvcWrap_FlushEntireDataCache64(Core::System& system) { + FlushEntireDataCache64(system); +} + +static void SvcWrap_FlushDataCache64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = FlushDataCache64(system, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_MapPhysicalMemory64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = MapPhysicalMemory64(system, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapPhysicalMemory64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = UnmapPhysicalMemory64(system, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system) { + Result ret{}; + + lp64::LastThreadContext out_context{}; + uint64_t out_thread_id{}; + Handle debug_handle{}; + int64_t ns{}; + + debug_handle = Convert<Handle>(GetReg64(system, 2)); + ns = Convert<int64_t>(GetReg64(system, 3)); + + ret = GetDebugFutureThreadInfo64(system, &out_context, &out_thread_id, debug_handle, ns); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context); + SetReg64(system, 1, out_context_scatter[0]); + SetReg64(system, 2, out_context_scatter[1]); + SetReg64(system, 3, out_context_scatter[2]); + SetReg64(system, 4, out_context_scatter[3]); + SetReg64(system, 5, Convert<uint64_t>(out_thread_id)); +} + +static void SvcWrap_GetLastThreadInfo64(Core::System& system) { + Result ret{}; + + lp64::LastThreadContext out_context{}; + uintptr_t out_tls_address{}; + uint32_t out_flags{}; + + ret = GetLastThreadInfo64(system, &out_context, &out_tls_address, &out_flags); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context); + SetReg64(system, 1, out_context_scatter[0]); + SetReg64(system, 2, out_context_scatter[1]); + SetReg64(system, 3, out_context_scatter[2]); + SetReg64(system, 4, out_context_scatter[3]); + SetReg64(system, 5, Convert<uint64_t>(out_tls_address)); + SetReg64(system, 6, Convert<uint64_t>(out_flags)); +} + +static void SvcWrap_GetResourceLimitLimitValue64(Core::System& system) { + Result ret{}; + + int64_t out_limit_value{}; + Handle resource_limit_handle{}; + LimitableResource which{}; + + resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); + which = Convert<LimitableResource>(GetReg64(system, 2)); + + ret = GetResourceLimitLimitValue64(system, &out_limit_value, resource_limit_handle, which); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_limit_value)); +} + +static void SvcWrap_GetResourceLimitCurrentValue64(Core::System& system) { + Result ret{}; + + int64_t out_current_value{}; + Handle resource_limit_handle{}; + LimitableResource which{}; + + resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); + which = Convert<LimitableResource>(GetReg64(system, 2)); + + ret = GetResourceLimitCurrentValue64(system, &out_current_value, resource_limit_handle, which); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_current_value)); +} + +static void SvcWrap_SetThreadActivity64(Core::System& system) { + Result ret{}; + + Handle thread_handle{}; + ThreadActivity thread_activity{}; + + thread_handle = Convert<Handle>(GetReg64(system, 0)); + thread_activity = Convert<ThreadActivity>(GetReg64(system, 1)); + + ret = SetThreadActivity64(system, thread_handle, thread_activity); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_GetThreadContext364(Core::System& system) { + Result ret{}; + + uint64_t out_context{}; + Handle thread_handle{}; + + out_context = Convert<uint64_t>(GetReg64(system, 0)); + thread_handle = Convert<Handle>(GetReg64(system, 1)); + + ret = GetThreadContext364(system, out_context, thread_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_WaitForAddress64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + ArbitrationType arb_type{}; + int32_t value{}; + int64_t timeout_ns{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + arb_type = Convert<ArbitrationType>(GetReg64(system, 1)); + value = Convert<int32_t>(GetReg64(system, 2)); + timeout_ns = Convert<int64_t>(GetReg64(system, 3)); + + ret = WaitForAddress64(system, address, arb_type, value, timeout_ns); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_SignalToAddress64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + SignalType signal_type{}; + int32_t value{}; + int32_t count{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + signal_type = Convert<SignalType>(GetReg64(system, 1)); + value = Convert<int32_t>(GetReg64(system, 2)); + count = Convert<int32_t>(GetReg64(system, 3)); + + ret = SignalToAddress64(system, address, signal_type, value, count); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_SynchronizePreemptionState64(Core::System& system) { + SynchronizePreemptionState64(system); +} + +static void SvcWrap_GetResourceLimitPeakValue64(Core::System& system) { + Result ret{}; + + int64_t out_peak_value{}; + Handle resource_limit_handle{}; + LimitableResource which{}; + + resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); + which = Convert<LimitableResource>(GetReg64(system, 2)); + + ret = GetResourceLimitPeakValue64(system, &out_peak_value, resource_limit_handle, which); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_peak_value)); +} + +static void SvcWrap_CreateIoPool64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + IoPoolType which{}; + + which = Convert<IoPoolType>(GetReg64(system, 1)); + + ret = CreateIoPool64(system, &out_handle, which); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_CreateIoRegion64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + Handle io_pool{}; + uint64_t physical_address{}; + uint64_t size{}; + MemoryMapping mapping{}; + MemoryPermission perm{}; + + io_pool = Convert<Handle>(GetReg64(system, 1)); + physical_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + mapping = Convert<MemoryMapping>(GetReg64(system, 4)); + perm = Convert<MemoryPermission>(GetReg64(system, 5)); + + ret = CreateIoRegion64(system, &out_handle, io_pool, physical_address, size, mapping, perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_KernelDebug64(Core::System& system) { + KernelDebugType kern_debug_type{}; + uint64_t arg0{}; + uint64_t arg1{}; + uint64_t arg2{}; + + kern_debug_type = Convert<KernelDebugType>(GetReg64(system, 0)); + arg0 = Convert<uint64_t>(GetReg64(system, 1)); + arg1 = Convert<uint64_t>(GetReg64(system, 2)); + arg2 = Convert<uint64_t>(GetReg64(system, 3)); + + KernelDebug64(system, kern_debug_type, arg0, arg1, arg2); +} + +static void SvcWrap_ChangeKernelTraceState64(Core::System& system) { + KernelTraceState kern_trace_state{}; + + kern_trace_state = Convert<KernelTraceState>(GetReg64(system, 0)); + + ChangeKernelTraceState64(system, kern_trace_state); +} - *out_num_threads = static_cast<u32>(num_threads); - return ResultSuccess; -} - -static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address, - u64 size) { - // Validate address/size. - R_UNLESS(size > 0, ResultInvalidSize); - R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory); - R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory); - - // Get the process from its handle. - KScopedAutoObject process = - system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle); - R_UNLESS(process.IsNotNull(), ResultInvalidHandle); - - // Verify the region is within range. - auto& page_table = process->PageTable(); - R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); - - // Perform the operation. - R_RETURN(system.Memory().FlushDataCache(*process, address, size)); -} - -namespace { -struct FunctionDef { - using Func = void(Core::System&); - - u32 id; - Func* func; - const char* name; -}; -} // namespace - -static const FunctionDef SVC_Table_32[] = { - {0x00, nullptr, "Unknown0"}, - {0x01, SvcWrap32<SetHeapSize32>, "SetHeapSize32"}, - {0x02, nullptr, "SetMemoryPermission32"}, - {0x03, SvcWrap32<SetMemoryAttribute32>, "SetMemoryAttribute32"}, - {0x04, SvcWrap32<MapMemory32>, "MapMemory32"}, - {0x05, SvcWrap32<UnmapMemory32>, "UnmapMemory32"}, - {0x06, SvcWrap32<QueryMemory32>, "QueryMemory32"}, - {0x07, SvcWrap32<ExitProcess32>, "ExitProcess32"}, - {0x08, SvcWrap32<CreateThread32>, "CreateThread32"}, - {0x09, SvcWrap32<StartThread32>, "StartThread32"}, - {0x0a, SvcWrap32<ExitThread32>, "ExitThread32"}, - {0x0b, SvcWrap32<SleepThread32>, "SleepThread32"}, - {0x0c, SvcWrap32<GetThreadPriority32>, "GetThreadPriority32"}, - {0x0d, SvcWrap32<SetThreadPriority32>, "SetThreadPriority32"}, - {0x0e, SvcWrap32<GetThreadCoreMask32>, "GetThreadCoreMask32"}, - {0x0f, SvcWrap32<SetThreadCoreMask32>, "SetThreadCoreMask32"}, - {0x10, SvcWrap32<GetCurrentProcessorNumber32>, "GetCurrentProcessorNumber32"}, - {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, - {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, - {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, - {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"}, - {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, - {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, - {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, - {0x18, SvcWrap32<WaitSynchronization32>, "WaitSynchronization32"}, - {0x19, SvcWrap32<CancelSynchronization32>, "CancelSynchronization32"}, - {0x1a, SvcWrap32<ArbitrateLock32>, "ArbitrateLock32"}, - {0x1b, SvcWrap32<ArbitrateUnlock32>, "ArbitrateUnlock32"}, - {0x1c, SvcWrap32<WaitProcessWideKeyAtomic32>, "WaitProcessWideKeyAtomic32"}, - {0x1d, SvcWrap32<SignalProcessWideKey32>, "SignalProcessWideKey32"}, - {0x1e, SvcWrap32<GetSystemTick32>, "GetSystemTick32"}, - {0x1f, SvcWrap32<ConnectToNamedPort32>, "ConnectToNamedPort32"}, - {0x20, nullptr, "SendSyncRequestLight32"}, - {0x21, SvcWrap32<SendSyncRequest32>, "SendSyncRequest32"}, - {0x22, nullptr, "SendSyncRequestWithUserBuffer32"}, - {0x23, nullptr, "SendAsyncRequestWithUserBuffer32"}, - {0x24, SvcWrap32<GetProcessId32>, "GetProcessId32"}, - {0x25, SvcWrap32<GetThreadId32>, "GetThreadId32"}, - {0x26, SvcWrap32<Break32>, "Break32"}, - {0x27, SvcWrap32<OutputDebugString32>, "OutputDebugString32"}, - {0x28, nullptr, "ReturnFromException32"}, - {0x29, SvcWrap32<GetInfo32>, "GetInfo32"}, - {0x2a, nullptr, "FlushEntireDataCache32"}, - {0x2b, nullptr, "FlushDataCache32"}, - {0x2c, SvcWrap32<MapPhysicalMemory32>, "MapPhysicalMemory32"}, - {0x2d, SvcWrap32<UnmapPhysicalMemory32>, "UnmapPhysicalMemory32"}, - {0x2e, nullptr, "GetDebugFutureThreadInfo32"}, - {0x2f, nullptr, "GetLastThreadInfo32"}, - {0x30, nullptr, "GetResourceLimitLimitValue32"}, - {0x31, nullptr, "GetResourceLimitCurrentValue32"}, - {0x32, SvcWrap32<SetThreadActivity32>, "SetThreadActivity32"}, - {0x33, SvcWrap32<GetThreadContext32>, "GetThreadContext32"}, - {0x34, SvcWrap32<WaitForAddress32>, "WaitForAddress32"}, - {0x35, SvcWrap32<SignalToAddress32>, "SignalToAddress32"}, - {0x36, SvcWrap32<SynchronizePreemptionState>, "SynchronizePreemptionState32"}, - {0x37, nullptr, "GetResourceLimitPeakValue32"}, - {0x38, nullptr, "Unknown38"}, - {0x39, nullptr, "CreateIoPool32"}, - {0x3a, nullptr, "CreateIoRegion32"}, - {0x3b, nullptr, "Unknown3b"}, - {0x3c, nullptr, "KernelDebug32"}, - {0x3d, nullptr, "ChangeKernelTraceState32"}, - {0x3e, nullptr, "Unknown3e"}, - {0x3f, nullptr, "Unknown3f"}, - {0x40, nullptr, "CreateSession32"}, - {0x41, nullptr, "AcceptSession32"}, - {0x42, nullptr, "ReplyAndReceiveLight32"}, - {0x43, nullptr, "ReplyAndReceive32"}, - {0x44, nullptr, "ReplyAndReceiveWithUserBuffer32"}, - {0x45, SvcWrap32<CreateEvent32>, "CreateEvent32"}, - {0x46, nullptr, "MapIoRegion32"}, - {0x47, nullptr, "UnmapIoRegion32"}, - {0x48, nullptr, "MapPhysicalMemoryUnsafe32"}, - {0x49, nullptr, "UnmapPhysicalMemoryUnsafe32"}, - {0x4a, nullptr, "SetUnsafeLimit32"}, - {0x4b, SvcWrap32<CreateCodeMemory32>, "CreateCodeMemory32"}, - {0x4c, SvcWrap32<ControlCodeMemory32>, "ControlCodeMemory32"}, - {0x4d, nullptr, "SleepSystem32"}, - {0x4e, nullptr, "ReadWriteRegister32"}, - {0x4f, nullptr, "SetProcessActivity32"}, - {0x50, nullptr, "CreateSharedMemory32"}, - {0x51, nullptr, "MapTransferMemory32"}, - {0x52, nullptr, "UnmapTransferMemory32"}, - {0x53, nullptr, "CreateInterruptEvent32"}, - {0x54, nullptr, "QueryPhysicalAddress32"}, - {0x55, nullptr, "QueryIoMapping32"}, - {0x56, nullptr, "CreateDeviceAddressSpace32"}, - {0x57, nullptr, "AttachDeviceAddressSpace32"}, - {0x58, nullptr, "DetachDeviceAddressSpace32"}, - {0x59, nullptr, "MapDeviceAddressSpaceByForce32"}, - {0x5a, nullptr, "MapDeviceAddressSpaceAligned32"}, - {0x5b, nullptr, "MapDeviceAddressSpace32"}, - {0x5c, nullptr, "UnmapDeviceAddressSpace32"}, - {0x5d, nullptr, "InvalidateProcessDataCache32"}, - {0x5e, nullptr, "StoreProcessDataCache32"}, - {0x5F, SvcWrap32<FlushProcessDataCache32>, "FlushProcessDataCache32"}, - {0x60, nullptr, "StoreProcessDataCache32"}, - {0x61, nullptr, "BreakDebugProcess32"}, - {0x62, nullptr, "TerminateDebugProcess32"}, - {0x63, nullptr, "GetDebugEvent32"}, - {0x64, nullptr, "ContinueDebugEvent32"}, - {0x65, nullptr, "GetProcessList32"}, - {0x66, nullptr, "GetThreadList"}, - {0x67, nullptr, "GetDebugThreadContext32"}, - {0x68, nullptr, "SetDebugThreadContext32"}, - {0x69, nullptr, "QueryDebugProcessMemory32"}, - {0x6A, nullptr, "ReadDebugProcessMemory32"}, - {0x6B, nullptr, "WriteDebugProcessMemory32"}, - {0x6C, nullptr, "SetHardwareBreakPoint32"}, - {0x6D, nullptr, "GetDebugThreadParam32"}, - {0x6E, nullptr, "Unknown6E"}, - {0x6f, nullptr, "GetSystemInfo32"}, - {0x70, nullptr, "CreatePort32"}, - {0x71, nullptr, "ManageNamedPort32"}, - {0x72, nullptr, "ConnectToPort32"}, - {0x73, nullptr, "SetProcessMemoryPermission32"}, - {0x74, nullptr, "MapProcessMemory32"}, - {0x75, nullptr, "UnmapProcessMemory32"}, - {0x76, nullptr, "QueryProcessMemory32"}, - {0x77, nullptr, "MapProcessCodeMemory32"}, - {0x78, nullptr, "UnmapProcessCodeMemory32"}, - {0x79, nullptr, "CreateProcess32"}, - {0x7A, nullptr, "StartProcess32"}, - {0x7B, nullptr, "TerminateProcess32"}, - {0x7C, nullptr, "GetProcessInfo32"}, - {0x7D, nullptr, "CreateResourceLimit32"}, - {0x7E, nullptr, "SetResourceLimitLimitValue32"}, - {0x7F, nullptr, "CallSecureMonitor32"}, - {0x80, nullptr, "Unknown"}, - {0x81, nullptr, "Unknown"}, - {0x82, nullptr, "Unknown"}, - {0x83, nullptr, "Unknown"}, - {0x84, nullptr, "Unknown"}, - {0x85, nullptr, "Unknown"}, - {0x86, nullptr, "Unknown"}, - {0x87, nullptr, "Unknown"}, - {0x88, nullptr, "Unknown"}, - {0x89, nullptr, "Unknown"}, - {0x8A, nullptr, "Unknown"}, - {0x8B, nullptr, "Unknown"}, - {0x8C, nullptr, "Unknown"}, - {0x8D, nullptr, "Unknown"}, - {0x8E, nullptr, "Unknown"}, - {0x8F, nullptr, "Unknown"}, - {0x90, nullptr, "Unknown"}, - {0x91, nullptr, "Unknown"}, - {0x92, nullptr, "Unknown"}, - {0x93, nullptr, "Unknown"}, - {0x94, nullptr, "Unknown"}, - {0x95, nullptr, "Unknown"}, - {0x96, nullptr, "Unknown"}, - {0x97, nullptr, "Unknown"}, - {0x98, nullptr, "Unknown"}, - {0x99, nullptr, "Unknown"}, - {0x9A, nullptr, "Unknown"}, - {0x9B, nullptr, "Unknown"}, - {0x9C, nullptr, "Unknown"}, - {0x9D, nullptr, "Unknown"}, - {0x9E, nullptr, "Unknown"}, - {0x9F, nullptr, "Unknown"}, - {0xA0, nullptr, "Unknown"}, - {0xA1, nullptr, "Unknown"}, - {0xA2, nullptr, "Unknown"}, - {0xA3, nullptr, "Unknown"}, - {0xA4, nullptr, "Unknown"}, - {0xA5, nullptr, "Unknown"}, - {0xA6, nullptr, "Unknown"}, - {0xA7, nullptr, "Unknown"}, - {0xA8, nullptr, "Unknown"}, - {0xA9, nullptr, "Unknown"}, - {0xAA, nullptr, "Unknown"}, - {0xAB, nullptr, "Unknown"}, - {0xAC, nullptr, "Unknown"}, - {0xAD, nullptr, "Unknown"}, - {0xAE, nullptr, "Unknown"}, - {0xAF, nullptr, "Unknown"}, - {0xB0, nullptr, "Unknown"}, - {0xB1, nullptr, "Unknown"}, - {0xB2, nullptr, "Unknown"}, - {0xB3, nullptr, "Unknown"}, - {0xB4, nullptr, "Unknown"}, - {0xB5, nullptr, "Unknown"}, - {0xB6, nullptr, "Unknown"}, - {0xB7, nullptr, "Unknown"}, - {0xB8, nullptr, "Unknown"}, - {0xB9, nullptr, "Unknown"}, - {0xBA, nullptr, "Unknown"}, - {0xBB, nullptr, "Unknown"}, - {0xBC, nullptr, "Unknown"}, - {0xBD, nullptr, "Unknown"}, - {0xBE, nullptr, "Unknown"}, - {0xBF, nullptr, "Unknown"}, -}; - -static const FunctionDef SVC_Table_64[] = { - {0x00, nullptr, "Unknown0"}, - {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"}, - {0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"}, - {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"}, - {0x04, SvcWrap64<MapMemory>, "MapMemory"}, - {0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"}, - {0x06, SvcWrap64<QueryMemory>, "QueryMemory"}, - {0x07, SvcWrap64<ExitProcess>, "ExitProcess"}, - {0x08, SvcWrap64<CreateThread>, "CreateThread"}, - {0x09, SvcWrap64<StartThread>, "StartThread"}, - {0x0A, SvcWrap64<ExitThread>, "ExitThread"}, - {0x0B, SvcWrap64<SleepThread>, "SleepThread"}, - {0x0C, SvcWrap64<GetThreadPriority>, "GetThreadPriority"}, - {0x0D, SvcWrap64<SetThreadPriority>, "SetThreadPriority"}, - {0x0E, SvcWrap64<GetThreadCoreMask>, "GetThreadCoreMask"}, - {0x0F, SvcWrap64<SetThreadCoreMask>, "SetThreadCoreMask"}, - {0x10, SvcWrap64<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, - {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, - {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, - {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, - {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"}, - {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, - {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, - {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, - {0x18, SvcWrap64<WaitSynchronization>, "WaitSynchronization"}, - {0x19, SvcWrap64<CancelSynchronization>, "CancelSynchronization"}, - {0x1A, SvcWrap64<ArbitrateLock>, "ArbitrateLock"}, - {0x1B, SvcWrap64<ArbitrateUnlock>, "ArbitrateUnlock"}, - {0x1C, SvcWrap64<WaitProcessWideKeyAtomic>, "WaitProcessWideKeyAtomic"}, - {0x1D, SvcWrap64<SignalProcessWideKey>, "SignalProcessWideKey"}, - {0x1E, SvcWrap64<GetSystemTick>, "GetSystemTick"}, - {0x1F, SvcWrap64<ConnectToNamedPort>, "ConnectToNamedPort"}, - {0x20, nullptr, "SendSyncRequestLight"}, - {0x21, SvcWrap64<SendSyncRequest>, "SendSyncRequest"}, - {0x22, nullptr, "SendSyncRequestWithUserBuffer"}, - {0x23, nullptr, "SendAsyncRequestWithUserBuffer"}, - {0x24, SvcWrap64<GetProcessId>, "GetProcessId"}, - {0x25, SvcWrap64<GetThreadId>, "GetThreadId"}, - {0x26, SvcWrap64<Break>, "Break"}, - {0x27, SvcWrap64<OutputDebugString>, "OutputDebugString"}, - {0x28, nullptr, "ReturnFromException"}, - {0x29, SvcWrap64<GetInfo>, "GetInfo"}, - {0x2A, nullptr, "FlushEntireDataCache"}, - {0x2B, nullptr, "FlushDataCache"}, - {0x2C, SvcWrap64<MapPhysicalMemory>, "MapPhysicalMemory"}, - {0x2D, SvcWrap64<UnmapPhysicalMemory>, "UnmapPhysicalMemory"}, - {0x2E, nullptr, "GetFutureThreadInfo"}, - {0x2F, nullptr, "GetLastThreadInfo"}, - {0x30, SvcWrap64<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"}, - {0x31, SvcWrap64<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"}, - {0x32, SvcWrap64<SetThreadActivity>, "SetThreadActivity"}, - {0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"}, - {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"}, - {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"}, - {0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"}, - {0x37, nullptr, "GetResourceLimitPeakValue"}, - {0x38, nullptr, "Unknown38"}, - {0x39, nullptr, "CreateIoPool"}, - {0x3A, nullptr, "CreateIoRegion"}, - {0x3B, nullptr, "Unknown3B"}, - {0x3C, SvcWrap64<KernelDebug>, "KernelDebug"}, - {0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"}, - {0x3E, nullptr, "Unknown3e"}, - {0x3F, nullptr, "Unknown3f"}, - {0x40, SvcWrap64<CreateSession>, "CreateSession"}, - {0x41, nullptr, "AcceptSession"}, - {0x42, nullptr, "ReplyAndReceiveLight"}, - {0x43, SvcWrap64<ReplyAndReceive>, "ReplyAndReceive"}, - {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, - {0x45, SvcWrap64<CreateEvent>, "CreateEvent"}, - {0x46, nullptr, "MapIoRegion"}, - {0x47, nullptr, "UnmapIoRegion"}, - {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, - {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"}, - {0x4A, nullptr, "SetUnsafeLimit"}, - {0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"}, - {0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"}, - {0x4D, nullptr, "SleepSystem"}, - {0x4E, nullptr, "ReadWriteRegister"}, - {0x4F, nullptr, "SetProcessActivity"}, - {0x50, nullptr, "CreateSharedMemory"}, - {0x51, nullptr, "MapTransferMemory"}, - {0x52, nullptr, "UnmapTransferMemory"}, - {0x53, nullptr, "CreateInterruptEvent"}, - {0x54, nullptr, "QueryPhysicalAddress"}, - {0x55, nullptr, "QueryIoMapping"}, - {0x56, nullptr, "CreateDeviceAddressSpace"}, - {0x57, nullptr, "AttachDeviceAddressSpace"}, - {0x58, nullptr, "DetachDeviceAddressSpace"}, - {0x59, nullptr, "MapDeviceAddressSpaceByForce"}, - {0x5A, nullptr, "MapDeviceAddressSpaceAligned"}, - {0x5B, nullptr, "MapDeviceAddressSpace"}, - {0x5C, nullptr, "UnmapDeviceAddressSpace"}, - {0x5D, nullptr, "InvalidateProcessDataCache"}, - {0x5E, nullptr, "StoreProcessDataCache"}, - {0x5F, nullptr, "FlushProcessDataCache"}, - {0x60, nullptr, "DebugActiveProcess"}, - {0x61, nullptr, "BreakDebugProcess"}, - {0x62, nullptr, "TerminateDebugProcess"}, - {0x63, nullptr, "GetDebugEvent"}, - {0x64, nullptr, "ContinueDebugEvent"}, - {0x65, SvcWrap64<GetProcessList>, "GetProcessList"}, - {0x66, SvcWrap64<GetThreadList>, "GetThreadList"}, - {0x67, nullptr, "GetDebugThreadContext"}, - {0x68, nullptr, "SetDebugThreadContext"}, - {0x69, nullptr, "QueryDebugProcessMemory"}, - {0x6A, nullptr, "ReadDebugProcessMemory"}, - {0x6B, nullptr, "WriteDebugProcessMemory"}, - {0x6C, nullptr, "SetHardwareBreakPoint"}, - {0x6D, nullptr, "GetDebugThreadParam"}, - {0x6E, nullptr, "Unknown6E"}, - {0x6F, nullptr, "GetSystemInfo"}, - {0x70, nullptr, "CreatePort"}, - {0x71, nullptr, "ManageNamedPort"}, - {0x72, nullptr, "ConnectToPort"}, - {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"}, - {0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"}, - {0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"}, - {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"}, - {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"}, - {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"}, - {0x79, nullptr, "CreateProcess"}, - {0x7A, nullptr, "StartProcess"}, - {0x7B, nullptr, "TerminateProcess"}, - {0x7C, SvcWrap64<GetProcessInfo>, "GetProcessInfo"}, - {0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"}, - {0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"}, - {0x7F, nullptr, "CallSecureMonitor"}, - {0x80, nullptr, "Unknown"}, - {0x81, nullptr, "Unknown"}, - {0x82, nullptr, "Unknown"}, - {0x83, nullptr, "Unknown"}, - {0x84, nullptr, "Unknown"}, - {0x85, nullptr, "Unknown"}, - {0x86, nullptr, "Unknown"}, - {0x87, nullptr, "Unknown"}, - {0x88, nullptr, "Unknown"}, - {0x89, nullptr, "Unknown"}, - {0x8A, nullptr, "Unknown"}, - {0x8B, nullptr, "Unknown"}, - {0x8C, nullptr, "Unknown"}, - {0x8D, nullptr, "Unknown"}, - {0x8E, nullptr, "Unknown"}, - {0x8F, nullptr, "Unknown"}, - {0x90, nullptr, "Unknown"}, - {0x91, nullptr, "Unknown"}, - {0x92, nullptr, "Unknown"}, - {0x93, nullptr, "Unknown"}, - {0x94, nullptr, "Unknown"}, - {0x95, nullptr, "Unknown"}, - {0x96, nullptr, "Unknown"}, - {0x97, nullptr, "Unknown"}, - {0x98, nullptr, "Unknown"}, - {0x99, nullptr, "Unknown"}, - {0x9A, nullptr, "Unknown"}, - {0x9B, nullptr, "Unknown"}, - {0x9C, nullptr, "Unknown"}, - {0x9D, nullptr, "Unknown"}, - {0x9E, nullptr, "Unknown"}, - {0x9F, nullptr, "Unknown"}, - {0xA0, nullptr, "Unknown"}, - {0xA1, nullptr, "Unknown"}, - {0xA2, nullptr, "Unknown"}, - {0xA3, nullptr, "Unknown"}, - {0xA4, nullptr, "Unknown"}, - {0xA5, nullptr, "Unknown"}, - {0xA6, nullptr, "Unknown"}, - {0xA7, nullptr, "Unknown"}, - {0xA8, nullptr, "Unknown"}, - {0xA9, nullptr, "Unknown"}, - {0xAA, nullptr, "Unknown"}, - {0xAB, nullptr, "Unknown"}, - {0xAC, nullptr, "Unknown"}, - {0xAD, nullptr, "Unknown"}, - {0xAE, nullptr, "Unknown"}, - {0xAF, nullptr, "Unknown"}, - {0xB0, nullptr, "Unknown"}, - {0xB1, nullptr, "Unknown"}, - {0xB2, nullptr, "Unknown"}, - {0xB3, nullptr, "Unknown"}, - {0xB4, nullptr, "Unknown"}, - {0xB5, nullptr, "Unknown"}, - {0xB6, nullptr, "Unknown"}, - {0xB7, nullptr, "Unknown"}, - {0xB8, nullptr, "Unknown"}, - {0xB9, nullptr, "Unknown"}, - {0xBA, nullptr, "Unknown"}, - {0xBB, nullptr, "Unknown"}, - {0xBC, nullptr, "Unknown"}, - {0xBD, nullptr, "Unknown"}, - {0xBE, nullptr, "Unknown"}, - {0xBF, nullptr, "Unknown"}, -}; - -static const FunctionDef* GetSVCInfo32(u32 func_num) { - if (func_num >= std::size(SVC_Table_32)) { - LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num); - return nullptr; +static void SvcWrap_CreateSession64(Core::System& system) { + Result ret{}; + + Handle out_server_session_handle{}; + Handle out_client_session_handle{}; + bool is_light{}; + uint64_t name{}; + + is_light = Convert<bool>(GetReg64(system, 2)); + name = Convert<uint64_t>(GetReg64(system, 3)); + + ret = CreateSession64(system, &out_server_session_handle, &out_client_session_handle, is_light, name); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_server_session_handle)); + SetReg64(system, 2, Convert<uint64_t>(out_client_session_handle)); +} + +static void SvcWrap_AcceptSession64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + Handle port{}; + + port = Convert<Handle>(GetReg64(system, 1)); + + ret = AcceptSession64(system, &out_handle, port); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_ReplyAndReceive64(Core::System& system) { + Result ret{}; + + int32_t out_index{}; + uint64_t handles{}; + int32_t num_handles{}; + Handle reply_target{}; + int64_t timeout_ns{}; + + handles = Convert<uint64_t>(GetReg64(system, 1)); + num_handles = Convert<int32_t>(GetReg64(system, 2)); + reply_target = Convert<Handle>(GetReg64(system, 3)); + timeout_ns = Convert<int64_t>(GetReg64(system, 4)); + + ret = ReplyAndReceive64(system, &out_index, handles, num_handles, reply_target, timeout_ns); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_index)); +} + +static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system) { + Result ret{}; + + int32_t out_index{}; + uint64_t message_buffer{}; + uint64_t message_buffer_size{}; + uint64_t handles{}; + int32_t num_handles{}; + Handle reply_target{}; + int64_t timeout_ns{}; + + message_buffer = Convert<uint64_t>(GetReg64(system, 1)); + message_buffer_size = Convert<uint64_t>(GetReg64(system, 2)); + handles = Convert<uint64_t>(GetReg64(system, 3)); + num_handles = Convert<int32_t>(GetReg64(system, 4)); + reply_target = Convert<Handle>(GetReg64(system, 5)); + timeout_ns = Convert<int64_t>(GetReg64(system, 6)); + + ret = ReplyAndReceiveWithUserBuffer64(system, &out_index, message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_index)); +} + +static void SvcWrap_CreateEvent64(Core::System& system) { + Result ret{}; + + Handle out_write_handle{}; + Handle out_read_handle{}; + + ret = CreateEvent64(system, &out_write_handle, &out_read_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_write_handle)); + SetReg64(system, 2, Convert<uint64_t>(out_read_handle)); +} + +static void SvcWrap_MapIoRegion64(Core::System& system) { + Result ret{}; + + Handle io_region{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission perm{}; + + io_region = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + perm = Convert<MemoryPermission>(GetReg64(system, 3)); + + ret = MapIoRegion64(system, io_region, address, size, perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapIoRegion64(Core::System& system) { + Result ret{}; + + Handle io_region{}; + uint64_t address{}; + uint64_t size{}; + + io_region = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = UnmapIoRegion64(system, io_region, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_MapPhysicalMemoryUnsafe64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = MapPhysicalMemoryUnsafe64(system, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapPhysicalMemoryUnsafe64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = UnmapPhysicalMemoryUnsafe64(system, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_SetUnsafeLimit64(Core::System& system) { + Result ret{}; + + uint64_t limit{}; + + limit = Convert<uint64_t>(GetReg64(system, 0)); + + ret = SetUnsafeLimit64(system, limit); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_CreateCodeMemory64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = CreateCodeMemory64(system, &out_handle, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_ControlCodeMemory64(Core::System& system) { + Result ret{}; + + Handle code_memory_handle{}; + CodeMemoryOperation operation{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission perm{}; + + code_memory_handle = Convert<Handle>(GetReg64(system, 0)); + operation = Convert<CodeMemoryOperation>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + perm = Convert<MemoryPermission>(GetReg64(system, 4)); + + ret = ControlCodeMemory64(system, code_memory_handle, operation, address, size, perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_SleepSystem64(Core::System& system) { + SleepSystem64(system); +} + +static void SvcWrap_ReadWriteRegister64(Core::System& system) { + Result ret{}; + + uint32_t out_value{}; + uint64_t address{}; + uint32_t mask{}; + uint32_t value{}; + + address = Convert<uint64_t>(GetReg64(system, 1)); + mask = Convert<uint32_t>(GetReg64(system, 2)); + value = Convert<uint32_t>(GetReg64(system, 3)); + + ret = ReadWriteRegister64(system, &out_value, address, mask, value); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_value)); +} + +static void SvcWrap_SetProcessActivity64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + ProcessActivity process_activity{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + process_activity = Convert<ProcessActivity>(GetReg64(system, 1)); + + ret = SetProcessActivity64(system, process_handle, process_activity); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_CreateSharedMemory64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint64_t size{}; + MemoryPermission owner_perm{}; + MemoryPermission remote_perm{}; + + size = Convert<uint64_t>(GetReg64(system, 1)); + owner_perm = Convert<MemoryPermission>(GetReg64(system, 2)); + remote_perm = Convert<MemoryPermission>(GetReg64(system, 3)); + + ret = CreateSharedMemory64(system, &out_handle, size, owner_perm, remote_perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_MapTransferMemory64(Core::System& system) { + Result ret{}; + + Handle trmem_handle{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission owner_perm{}; + + trmem_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + owner_perm = Convert<MemoryPermission>(GetReg64(system, 3)); + + ret = MapTransferMemory64(system, trmem_handle, address, size, owner_perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapTransferMemory64(Core::System& system) { + Result ret{}; + + Handle trmem_handle{}; + uint64_t address{}; + uint64_t size{}; + + trmem_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = UnmapTransferMemory64(system, trmem_handle, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_CreateInterruptEvent64(Core::System& system) { + Result ret{}; + + Handle out_read_handle{}; + int32_t interrupt_id{}; + InterruptType interrupt_type{}; + + interrupt_id = Convert<int32_t>(GetReg64(system, 1)); + interrupt_type = Convert<InterruptType>(GetReg64(system, 2)); + + ret = CreateInterruptEvent64(system, &out_read_handle, interrupt_id, interrupt_type); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_read_handle)); +} + +static void SvcWrap_QueryPhysicalAddress64(Core::System& system) { + Result ret{}; + + lp64::PhysicalMemoryInfo out_info{}; + uint64_t address{}; + + address = Convert<uint64_t>(GetReg64(system, 1)); + + ret = QueryPhysicalAddress64(system, &out_info, address); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + auto out_info_scatter = Convert<std::array<uint64_t, 3>>(out_info); + SetReg64(system, 1, out_info_scatter[0]); + SetReg64(system, 2, out_info_scatter[1]); + SetReg64(system, 3, out_info_scatter[2]); +} + +static void SvcWrap_QueryIoMapping64(Core::System& system) { + Result ret{}; + + uintptr_t out_address{}; + uintptr_t out_size{}; + uint64_t physical_address{}; + uint64_t size{}; + + physical_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = QueryIoMapping64(system, &out_address, &out_size, physical_address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_address)); + SetReg64(system, 2, Convert<uint64_t>(out_size)); +} + +static void SvcWrap_CreateDeviceAddressSpace64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint64_t das_address{}; + uint64_t das_size{}; + + das_address = Convert<uint64_t>(GetReg64(system, 1)); + das_size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = CreateDeviceAddressSpace64(system, &out_handle, das_address, das_size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_AttachDeviceAddressSpace64(Core::System& system) { + Result ret{}; + + DeviceName device_name{}; + Handle das_handle{}; + + device_name = Convert<DeviceName>(GetReg64(system, 0)); + das_handle = Convert<Handle>(GetReg64(system, 1)); + + ret = AttachDeviceAddressSpace64(system, device_name, das_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_DetachDeviceAddressSpace64(Core::System& system) { + Result ret{}; + + DeviceName device_name{}; + Handle das_handle{}; + + device_name = Convert<DeviceName>(GetReg64(system, 0)); + das_handle = Convert<Handle>(GetReg64(system, 1)); + + ret = DetachDeviceAddressSpace64(system, device_name, das_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system) { + Result ret{}; + + Handle das_handle{}; + Handle process_handle{}; + uint64_t process_address{}; + uint64_t size{}; + uint64_t device_address{}; + uint32_t option{}; + + das_handle = Convert<Handle>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetReg64(system, 1)); + process_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + device_address = Convert<uint64_t>(GetReg64(system, 4)); + option = Convert<uint32_t>(GetReg64(system, 5)); + + ret = MapDeviceAddressSpaceByForce64(system, das_handle, process_handle, process_address, size, device_address, option); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system) { + Result ret{}; + + Handle das_handle{}; + Handle process_handle{}; + uint64_t process_address{}; + uint64_t size{}; + uint64_t device_address{}; + uint32_t option{}; + + das_handle = Convert<Handle>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetReg64(system, 1)); + process_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + device_address = Convert<uint64_t>(GetReg64(system, 4)); + option = Convert<uint32_t>(GetReg64(system, 5)); + + ret = MapDeviceAddressSpaceAligned64(system, das_handle, process_handle, process_address, size, device_address, option); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system) { + Result ret{}; + + Handle das_handle{}; + Handle process_handle{}; + uint64_t process_address{}; + uint64_t size{}; + uint64_t device_address{}; + + das_handle = Convert<Handle>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetReg64(system, 1)); + process_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + device_address = Convert<uint64_t>(GetReg64(system, 4)); + + ret = UnmapDeviceAddressSpace64(system, das_handle, process_handle, process_address, size, device_address); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_InvalidateProcessDataCache64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = InvalidateProcessDataCache64(system, process_handle, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_StoreProcessDataCache64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = StoreProcessDataCache64(system, process_handle, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_FlushProcessDataCache64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + + ret = FlushProcessDataCache64(system, process_handle, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_DebugActiveProcess64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint64_t process_id{}; + + process_id = Convert<uint64_t>(GetReg64(system, 1)); + + ret = DebugActiveProcess64(system, &out_handle, process_id); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_BreakDebugProcess64(Core::System& system) { + Result ret{}; + + Handle debug_handle{}; + + debug_handle = Convert<Handle>(GetReg64(system, 0)); + + ret = BreakDebugProcess64(system, debug_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_TerminateDebugProcess64(Core::System& system) { + Result ret{}; + + Handle debug_handle{}; + + debug_handle = Convert<Handle>(GetReg64(system, 0)); + + ret = TerminateDebugProcess64(system, debug_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_GetDebugEvent64(Core::System& system) { + Result ret{}; + + uint64_t out_info{}; + Handle debug_handle{}; + + out_info = Convert<uint64_t>(GetReg64(system, 0)); + debug_handle = Convert<Handle>(GetReg64(system, 1)); + + ret = GetDebugEvent64(system, out_info, debug_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_ContinueDebugEvent64(Core::System& system) { + Result ret{}; + + Handle debug_handle{}; + uint32_t flags{}; + uint64_t thread_ids{}; + int32_t num_thread_ids{}; + + debug_handle = Convert<Handle>(GetReg64(system, 0)); + flags = Convert<uint32_t>(GetReg64(system, 1)); + thread_ids = Convert<uint64_t>(GetReg64(system, 2)); + num_thread_ids = Convert<int32_t>(GetReg64(system, 3)); + + ret = ContinueDebugEvent64(system, debug_handle, flags, thread_ids, num_thread_ids); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_GetProcessList64(Core::System& system) { + Result ret{}; + + int32_t out_num_processes{}; + uint64_t out_process_ids{}; + int32_t max_out_count{}; + + out_process_ids = Convert<uint64_t>(GetReg64(system, 1)); + max_out_count = Convert<int32_t>(GetReg64(system, 2)); + + ret = GetProcessList64(system, &out_num_processes, out_process_ids, max_out_count); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_num_processes)); +} + +static void SvcWrap_GetThreadList64(Core::System& system) { + Result ret{}; + + int32_t out_num_threads{}; + uint64_t out_thread_ids{}; + int32_t max_out_count{}; + Handle debug_handle{}; + + out_thread_ids = Convert<uint64_t>(GetReg64(system, 1)); + max_out_count = Convert<int32_t>(GetReg64(system, 2)); + debug_handle = Convert<Handle>(GetReg64(system, 3)); + + ret = GetThreadList64(system, &out_num_threads, out_thread_ids, max_out_count, debug_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_num_threads)); +} + +static void SvcWrap_GetDebugThreadContext64(Core::System& system) { + Result ret{}; + + uint64_t out_context{}; + Handle debug_handle{}; + uint64_t thread_id{}; + uint32_t context_flags{}; + + out_context = Convert<uint64_t>(GetReg64(system, 0)); + debug_handle = Convert<Handle>(GetReg64(system, 1)); + thread_id = Convert<uint64_t>(GetReg64(system, 2)); + context_flags = Convert<uint32_t>(GetReg64(system, 3)); + + ret = GetDebugThreadContext64(system, out_context, debug_handle, thread_id, context_flags); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_SetDebugThreadContext64(Core::System& system) { + Result ret{}; + + Handle debug_handle{}; + uint64_t thread_id{}; + uint64_t context{}; + uint32_t context_flags{}; + + debug_handle = Convert<Handle>(GetReg64(system, 0)); + thread_id = Convert<uint64_t>(GetReg64(system, 1)); + context = Convert<uint64_t>(GetReg64(system, 2)); + context_flags = Convert<uint32_t>(GetReg64(system, 3)); + + ret = SetDebugThreadContext64(system, debug_handle, thread_id, context, context_flags); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_QueryDebugProcessMemory64(Core::System& system) { + Result ret{}; + + PageInfo out_page_info{}; + uint64_t out_memory_info{}; + Handle process_handle{}; + uint64_t address{}; + + out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetReg64(system, 2)); + address = Convert<uint64_t>(GetReg64(system, 3)); + + ret = QueryDebugProcessMemory64(system, out_memory_info, &out_page_info, process_handle, address); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_page_info)); +} + +static void SvcWrap_ReadDebugProcessMemory64(Core::System& system) { + Result ret{}; + + uint64_t buffer{}; + Handle debug_handle{}; + uint64_t address{}; + uint64_t size{}; + + buffer = Convert<uint64_t>(GetReg64(system, 0)); + debug_handle = Convert<Handle>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = ReadDebugProcessMemory64(system, buffer, debug_handle, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_WriteDebugProcessMemory64(Core::System& system) { + Result ret{}; + + Handle debug_handle{}; + uint64_t buffer{}; + uint64_t address{}; + uint64_t size{}; + + debug_handle = Convert<Handle>(GetReg64(system, 0)); + buffer = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = WriteDebugProcessMemory64(system, debug_handle, buffer, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_SetHardwareBreakPoint64(Core::System& system) { + Result ret{}; + + HardwareBreakPointRegisterName name{}; + uint64_t flags{}; + uint64_t value{}; + + name = Convert<HardwareBreakPointRegisterName>(GetReg64(system, 0)); + flags = Convert<uint64_t>(GetReg64(system, 1)); + value = Convert<uint64_t>(GetReg64(system, 2)); + + ret = SetHardwareBreakPoint64(system, name, flags, value); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_GetDebugThreadParam64(Core::System& system) { + Result ret{}; + + uint64_t out_64{}; + uint32_t out_32{}; + Handle debug_handle{}; + uint64_t thread_id{}; + DebugThreadParam param{}; + + debug_handle = Convert<Handle>(GetReg64(system, 2)); + thread_id = Convert<uint64_t>(GetReg64(system, 3)); + param = Convert<DebugThreadParam>(GetReg64(system, 4)); + + ret = GetDebugThreadParam64(system, &out_64, &out_32, debug_handle, thread_id, param); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_64)); + SetReg64(system, 2, Convert<uint64_t>(out_32)); +} + +static void SvcWrap_GetSystemInfo64(Core::System& system) { + Result ret{}; + + uint64_t out{}; + SystemInfoType info_type{}; + Handle handle{}; + uint64_t info_subtype{}; + + info_type = Convert<SystemInfoType>(GetReg64(system, 1)); + handle = Convert<Handle>(GetReg64(system, 2)); + info_subtype = Convert<uint64_t>(GetReg64(system, 3)); + + ret = GetSystemInfo64(system, &out, info_type, handle, info_subtype); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out)); +} + +static void SvcWrap_CreatePort64(Core::System& system) { + Result ret{}; + + Handle out_server_handle{}; + Handle out_client_handle{}; + int32_t max_sessions{}; + bool is_light{}; + uint64_t name{}; + + max_sessions = Convert<int32_t>(GetReg64(system, 2)); + is_light = Convert<bool>(GetReg64(system, 3)); + name = Convert<uint64_t>(GetReg64(system, 4)); + + ret = CreatePort64(system, &out_server_handle, &out_client_handle, max_sessions, is_light, name); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_server_handle)); + SetReg64(system, 2, Convert<uint64_t>(out_client_handle)); +} + +static void SvcWrap_ManageNamedPort64(Core::System& system) { + Result ret{}; + + Handle out_server_handle{}; + uint64_t name{}; + int32_t max_sessions{}; + + name = Convert<uint64_t>(GetReg64(system, 1)); + max_sessions = Convert<int32_t>(GetReg64(system, 2)); + + ret = ManageNamedPort64(system, &out_server_handle, name, max_sessions); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_server_handle)); +} + +static void SvcWrap_ConnectToPort64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + Handle port{}; + + port = Convert<Handle>(GetReg64(system, 1)); + + ret = ConnectToPort64(system, &out_handle, port); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_SetProcessMemoryPermission64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t address{}; + uint64_t size{}; + MemoryPermission perm{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetReg64(system, 2)); + perm = Convert<MemoryPermission>(GetReg64(system, 3)); + + ret = SetProcessMemoryPermission64(system, process_handle, address, size, perm); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_MapProcessMemory64(Core::System& system) { + Result ret{}; + + uint64_t dst_address{}; + Handle process_handle{}; + uint64_t src_address{}; + uint64_t size{}; + + dst_address = Convert<uint64_t>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetReg64(system, 1)); + src_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = MapProcessMemory64(system, dst_address, process_handle, src_address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapProcessMemory64(Core::System& system) { + Result ret{}; + + uint64_t dst_address{}; + Handle process_handle{}; + uint64_t src_address{}; + uint64_t size{}; + + dst_address = Convert<uint64_t>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetReg64(system, 1)); + src_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = UnmapProcessMemory64(system, dst_address, process_handle, src_address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_QueryProcessMemory64(Core::System& system) { + Result ret{}; + + PageInfo out_page_info{}; + uint64_t out_memory_info{}; + Handle process_handle{}; + uint64_t address{}; + + out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetReg64(system, 2)); + address = Convert<uint64_t>(GetReg64(system, 3)); + + ret = QueryProcessMemory64(system, out_memory_info, &out_page_info, process_handle, address); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_page_info)); +} + +static void SvcWrap_MapProcessCodeMemory64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t dst_address{}; + uint64_t src_address{}; + uint64_t size{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + dst_address = Convert<uint64_t>(GetReg64(system, 1)); + src_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = MapProcessCodeMemory64(system, process_handle, dst_address, src_address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + uint64_t dst_address{}; + uint64_t src_address{}; + uint64_t size{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + dst_address = Convert<uint64_t>(GetReg64(system, 1)); + src_address = Convert<uint64_t>(GetReg64(system, 2)); + size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = UnmapProcessCodeMemory64(system, process_handle, dst_address, src_address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_CreateProcess64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + uint64_t parameters{}; + uint64_t caps{}; + int32_t num_caps{}; + + parameters = Convert<uint64_t>(GetReg64(system, 1)); + caps = Convert<uint64_t>(GetReg64(system, 2)); + num_caps = Convert<int32_t>(GetReg64(system, 3)); + + ret = CreateProcess64(system, &out_handle, parameters, caps, num_caps); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_StartProcess64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + int32_t priority{}; + int32_t core_id{}; + uint64_t main_thread_stack_size{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + priority = Convert<int32_t>(GetReg64(system, 1)); + core_id = Convert<int32_t>(GetReg64(system, 2)); + main_thread_stack_size = Convert<uint64_t>(GetReg64(system, 3)); + + ret = StartProcess64(system, process_handle, priority, core_id, main_thread_stack_size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_TerminateProcess64(Core::System& system) { + Result ret{}; + + Handle process_handle{}; + + process_handle = Convert<Handle>(GetReg64(system, 0)); + + ret = TerminateProcess64(system, process_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_GetProcessInfo64(Core::System& system) { + Result ret{}; + + int64_t out_info{}; + Handle process_handle{}; + ProcessInfoType info_type{}; + + process_handle = Convert<Handle>(GetReg64(system, 1)); + info_type = Convert<ProcessInfoType>(GetReg64(system, 2)); + + ret = GetProcessInfo64(system, &out_info, process_handle, info_type); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_info)); +} + +static void SvcWrap_CreateResourceLimit64(Core::System& system) { + Result ret{}; + + Handle out_handle{}; + + ret = CreateResourceLimit64(system, &out_handle); + + SetReg64(system, 0, Convert<uint64_t>(ret)); + SetReg64(system, 1, Convert<uint64_t>(out_handle)); +} + +static void SvcWrap_SetResourceLimitLimitValue64(Core::System& system) { + Result ret{}; + + Handle resource_limit_handle{}; + LimitableResource which{}; + int64_t limit_value{}; + + resource_limit_handle = Convert<Handle>(GetReg64(system, 0)); + which = Convert<LimitableResource>(GetReg64(system, 1)); + limit_value = Convert<int64_t>(GetReg64(system, 2)); + + ret = SetResourceLimitLimitValue64(system, resource_limit_handle, which, limit_value); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_MapInsecureMemory64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = MapInsecureMemory64(system, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void SvcWrap_UnmapInsecureMemory64(Core::System& system) { + Result ret{}; + + uint64_t address{}; + uint64_t size{}; + + address = Convert<uint64_t>(GetReg64(system, 0)); + size = Convert<uint64_t>(GetReg64(system, 1)); + + ret = UnmapInsecureMemory64(system, address, size); + + SetReg64(system, 0, Convert<uint64_t>(ret)); +} + +static void Call32(Core::System& system, u32 imm) { + switch (static_cast<SvcId>(imm)) { + case SvcId::SetHeapSize: + return SvcWrap_SetHeapSize64From32(system); + case SvcId::SetMemoryPermission: + return SvcWrap_SetMemoryPermission64From32(system); + case SvcId::SetMemoryAttribute: + return SvcWrap_SetMemoryAttribute64From32(system); + case SvcId::MapMemory: + return SvcWrap_MapMemory64From32(system); + case SvcId::UnmapMemory: + return SvcWrap_UnmapMemory64From32(system); + case SvcId::QueryMemory: + return SvcWrap_QueryMemory64From32(system); + case SvcId::ExitProcess: + return SvcWrap_ExitProcess64From32(system); + case SvcId::CreateThread: + return SvcWrap_CreateThread64From32(system); + case SvcId::StartThread: + return SvcWrap_StartThread64From32(system); + case SvcId::ExitThread: + return SvcWrap_ExitThread64From32(system); + case SvcId::SleepThread: + return SvcWrap_SleepThread64From32(system); + case SvcId::GetThreadPriority: + return SvcWrap_GetThreadPriority64From32(system); + case SvcId::SetThreadPriority: + return SvcWrap_SetThreadPriority64From32(system); + case SvcId::GetThreadCoreMask: + return SvcWrap_GetThreadCoreMask64From32(system); + case SvcId::SetThreadCoreMask: + return SvcWrap_SetThreadCoreMask64From32(system); + case SvcId::GetCurrentProcessorNumber: + return SvcWrap_GetCurrentProcessorNumber64From32(system); + case SvcId::SignalEvent: + return SvcWrap_SignalEvent64From32(system); + case SvcId::ClearEvent: + return SvcWrap_ClearEvent64From32(system); + case SvcId::MapSharedMemory: + return SvcWrap_MapSharedMemory64From32(system); + case SvcId::UnmapSharedMemory: + return SvcWrap_UnmapSharedMemory64From32(system); + case SvcId::CreateTransferMemory: + return SvcWrap_CreateTransferMemory64From32(system); + case SvcId::CloseHandle: + return SvcWrap_CloseHandle64From32(system); + case SvcId::ResetSignal: + return SvcWrap_ResetSignal64From32(system); + case SvcId::WaitSynchronization: + return SvcWrap_WaitSynchronization64From32(system); + case SvcId::CancelSynchronization: + return SvcWrap_CancelSynchronization64From32(system); + case SvcId::ArbitrateLock: + return SvcWrap_ArbitrateLock64From32(system); + case SvcId::ArbitrateUnlock: + return SvcWrap_ArbitrateUnlock64From32(system); + case SvcId::WaitProcessWideKeyAtomic: + return SvcWrap_WaitProcessWideKeyAtomic64From32(system); + case SvcId::SignalProcessWideKey: + return SvcWrap_SignalProcessWideKey64From32(system); + case SvcId::GetSystemTick: + return SvcWrap_GetSystemTick64From32(system); + case SvcId::ConnectToNamedPort: + return SvcWrap_ConnectToNamedPort64From32(system); + case SvcId::SendSyncRequestLight: + return SvcWrap_SendSyncRequestLight64From32(system); + case SvcId::SendSyncRequest: + return SvcWrap_SendSyncRequest64From32(system); + case SvcId::SendSyncRequestWithUserBuffer: + return SvcWrap_SendSyncRequestWithUserBuffer64From32(system); + case SvcId::SendAsyncRequestWithUserBuffer: + return SvcWrap_SendAsyncRequestWithUserBuffer64From32(system); + case SvcId::GetProcessId: + return SvcWrap_GetProcessId64From32(system); + case SvcId::GetThreadId: + return SvcWrap_GetThreadId64From32(system); + case SvcId::Break: + return SvcWrap_Break64From32(system); + case SvcId::OutputDebugString: + return SvcWrap_OutputDebugString64From32(system); + case SvcId::ReturnFromException: + return SvcWrap_ReturnFromException64From32(system); + case SvcId::GetInfo: + return SvcWrap_GetInfo64From32(system); + case SvcId::FlushEntireDataCache: + return SvcWrap_FlushEntireDataCache64From32(system); + case SvcId::FlushDataCache: + return SvcWrap_FlushDataCache64From32(system); + case SvcId::MapPhysicalMemory: + return SvcWrap_MapPhysicalMemory64From32(system); + case SvcId::UnmapPhysicalMemory: + return SvcWrap_UnmapPhysicalMemory64From32(system); + case SvcId::GetDebugFutureThreadInfo: + return SvcWrap_GetDebugFutureThreadInfo64From32(system); + case SvcId::GetLastThreadInfo: + return SvcWrap_GetLastThreadInfo64From32(system); + case SvcId::GetResourceLimitLimitValue: + return SvcWrap_GetResourceLimitLimitValue64From32(system); + case SvcId::GetResourceLimitCurrentValue: + return SvcWrap_GetResourceLimitCurrentValue64From32(system); + case SvcId::SetThreadActivity: + return SvcWrap_SetThreadActivity64From32(system); + case SvcId::GetThreadContext3: + return SvcWrap_GetThreadContext364From32(system); + case SvcId::WaitForAddress: + return SvcWrap_WaitForAddress64From32(system); + case SvcId::SignalToAddress: + return SvcWrap_SignalToAddress64From32(system); + case SvcId::SynchronizePreemptionState: + return SvcWrap_SynchronizePreemptionState64From32(system); + case SvcId::GetResourceLimitPeakValue: + return SvcWrap_GetResourceLimitPeakValue64From32(system); + case SvcId::CreateIoPool: + return SvcWrap_CreateIoPool64From32(system); + case SvcId::CreateIoRegion: + return SvcWrap_CreateIoRegion64From32(system); + case SvcId::KernelDebug: + return SvcWrap_KernelDebug64From32(system); + case SvcId::ChangeKernelTraceState: + return SvcWrap_ChangeKernelTraceState64From32(system); + case SvcId::CreateSession: + return SvcWrap_CreateSession64From32(system); + case SvcId::AcceptSession: + return SvcWrap_AcceptSession64From32(system); + case SvcId::ReplyAndReceiveLight: + return SvcWrap_ReplyAndReceiveLight64From32(system); + case SvcId::ReplyAndReceive: + return SvcWrap_ReplyAndReceive64From32(system); + case SvcId::ReplyAndReceiveWithUserBuffer: + return SvcWrap_ReplyAndReceiveWithUserBuffer64From32(system); + case SvcId::CreateEvent: + return SvcWrap_CreateEvent64From32(system); + case SvcId::MapIoRegion: + return SvcWrap_MapIoRegion64From32(system); + case SvcId::UnmapIoRegion: + return SvcWrap_UnmapIoRegion64From32(system); + case SvcId::MapPhysicalMemoryUnsafe: + return SvcWrap_MapPhysicalMemoryUnsafe64From32(system); + case SvcId::UnmapPhysicalMemoryUnsafe: + return SvcWrap_UnmapPhysicalMemoryUnsafe64From32(system); + case SvcId::SetUnsafeLimit: + return SvcWrap_SetUnsafeLimit64From32(system); + case SvcId::CreateCodeMemory: + return SvcWrap_CreateCodeMemory64From32(system); + case SvcId::ControlCodeMemory: + return SvcWrap_ControlCodeMemory64From32(system); + case SvcId::SleepSystem: + return SvcWrap_SleepSystem64From32(system); + case SvcId::ReadWriteRegister: + return SvcWrap_ReadWriteRegister64From32(system); + case SvcId::SetProcessActivity: + return SvcWrap_SetProcessActivity64From32(system); + case SvcId::CreateSharedMemory: + return SvcWrap_CreateSharedMemory64From32(system); + case SvcId::MapTransferMemory: + return SvcWrap_MapTransferMemory64From32(system); + case SvcId::UnmapTransferMemory: + return SvcWrap_UnmapTransferMemory64From32(system); + case SvcId::CreateInterruptEvent: + return SvcWrap_CreateInterruptEvent64From32(system); + case SvcId::QueryPhysicalAddress: + return SvcWrap_QueryPhysicalAddress64From32(system); + case SvcId::QueryIoMapping: + return SvcWrap_QueryIoMapping64From32(system); + case SvcId::CreateDeviceAddressSpace: + return SvcWrap_CreateDeviceAddressSpace64From32(system); + case SvcId::AttachDeviceAddressSpace: + return SvcWrap_AttachDeviceAddressSpace64From32(system); + case SvcId::DetachDeviceAddressSpace: + return SvcWrap_DetachDeviceAddressSpace64From32(system); + case SvcId::MapDeviceAddressSpaceByForce: + return SvcWrap_MapDeviceAddressSpaceByForce64From32(system); + case SvcId::MapDeviceAddressSpaceAligned: + return SvcWrap_MapDeviceAddressSpaceAligned64From32(system); + case SvcId::UnmapDeviceAddressSpace: + return SvcWrap_UnmapDeviceAddressSpace64From32(system); + case SvcId::InvalidateProcessDataCache: + return SvcWrap_InvalidateProcessDataCache64From32(system); + case SvcId::StoreProcessDataCache: + return SvcWrap_StoreProcessDataCache64From32(system); + case SvcId::FlushProcessDataCache: + return SvcWrap_FlushProcessDataCache64From32(system); + case SvcId::DebugActiveProcess: + return SvcWrap_DebugActiveProcess64From32(system); + case SvcId::BreakDebugProcess: + return SvcWrap_BreakDebugProcess64From32(system); + case SvcId::TerminateDebugProcess: + return SvcWrap_TerminateDebugProcess64From32(system); + case SvcId::GetDebugEvent: + return SvcWrap_GetDebugEvent64From32(system); + case SvcId::ContinueDebugEvent: + return SvcWrap_ContinueDebugEvent64From32(system); + case SvcId::GetProcessList: + return SvcWrap_GetProcessList64From32(system); + case SvcId::GetThreadList: + return SvcWrap_GetThreadList64From32(system); + case SvcId::GetDebugThreadContext: + return SvcWrap_GetDebugThreadContext64From32(system); + case SvcId::SetDebugThreadContext: + return SvcWrap_SetDebugThreadContext64From32(system); + case SvcId::QueryDebugProcessMemory: + return SvcWrap_QueryDebugProcessMemory64From32(system); + case SvcId::ReadDebugProcessMemory: + return SvcWrap_ReadDebugProcessMemory64From32(system); + case SvcId::WriteDebugProcessMemory: + return SvcWrap_WriteDebugProcessMemory64From32(system); + case SvcId::SetHardwareBreakPoint: + return SvcWrap_SetHardwareBreakPoint64From32(system); + case SvcId::GetDebugThreadParam: + return SvcWrap_GetDebugThreadParam64From32(system); + case SvcId::GetSystemInfo: + return SvcWrap_GetSystemInfo64From32(system); + case SvcId::CreatePort: + return SvcWrap_CreatePort64From32(system); + case SvcId::ManageNamedPort: + return SvcWrap_ManageNamedPort64From32(system); + case SvcId::ConnectToPort: + return SvcWrap_ConnectToPort64From32(system); + case SvcId::SetProcessMemoryPermission: + return SvcWrap_SetProcessMemoryPermission64From32(system); + case SvcId::MapProcessMemory: + return SvcWrap_MapProcessMemory64From32(system); + case SvcId::UnmapProcessMemory: + return SvcWrap_UnmapProcessMemory64From32(system); + case SvcId::QueryProcessMemory: + return SvcWrap_QueryProcessMemory64From32(system); + case SvcId::MapProcessCodeMemory: + return SvcWrap_MapProcessCodeMemory64From32(system); + case SvcId::UnmapProcessCodeMemory: + return SvcWrap_UnmapProcessCodeMemory64From32(system); + case SvcId::CreateProcess: + return SvcWrap_CreateProcess64From32(system); + case SvcId::StartProcess: + return SvcWrap_StartProcess64From32(system); + case SvcId::TerminateProcess: + return SvcWrap_TerminateProcess64From32(system); + case SvcId::GetProcessInfo: + return SvcWrap_GetProcessInfo64From32(system); + case SvcId::CreateResourceLimit: + return SvcWrap_CreateResourceLimit64From32(system); + case SvcId::SetResourceLimitLimitValue: + return SvcWrap_SetResourceLimitLimitValue64From32(system); + case SvcId::CallSecureMonitor: + return SvcWrap_CallSecureMonitor64From32(system); + case SvcId::MapInsecureMemory: + return SvcWrap_MapInsecureMemory64From32(system); + case SvcId::UnmapInsecureMemory: + return SvcWrap_UnmapInsecureMemory64From32(system); + default: + LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm); + break; } - return &SVC_Table_32[func_num]; } -static const FunctionDef* GetSVCInfo64(u32 func_num) { - if (func_num >= std::size(SVC_Table_64)) { - LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num); - return nullptr; +static void Call64(Core::System& system, u32 imm) { + switch (static_cast<SvcId>(imm)) { + case SvcId::SetHeapSize: + return SvcWrap_SetHeapSize64(system); + case SvcId::SetMemoryPermission: + return SvcWrap_SetMemoryPermission64(system); + case SvcId::SetMemoryAttribute: + return SvcWrap_SetMemoryAttribute64(system); + case SvcId::MapMemory: + return SvcWrap_MapMemory64(system); + case SvcId::UnmapMemory: + return SvcWrap_UnmapMemory64(system); + case SvcId::QueryMemory: + return SvcWrap_QueryMemory64(system); + case SvcId::ExitProcess: + return SvcWrap_ExitProcess64(system); + case SvcId::CreateThread: + return SvcWrap_CreateThread64(system); + case SvcId::StartThread: + return SvcWrap_StartThread64(system); + case SvcId::ExitThread: + return SvcWrap_ExitThread64(system); + case SvcId::SleepThread: + return SvcWrap_SleepThread64(system); + case SvcId::GetThreadPriority: + return SvcWrap_GetThreadPriority64(system); + case SvcId::SetThreadPriority: + return SvcWrap_SetThreadPriority64(system); + case SvcId::GetThreadCoreMask: + return SvcWrap_GetThreadCoreMask64(system); + case SvcId::SetThreadCoreMask: + return SvcWrap_SetThreadCoreMask64(system); + case SvcId::GetCurrentProcessorNumber: + return SvcWrap_GetCurrentProcessorNumber64(system); + case SvcId::SignalEvent: + return SvcWrap_SignalEvent64(system); + case SvcId::ClearEvent: + return SvcWrap_ClearEvent64(system); + case SvcId::MapSharedMemory: + return SvcWrap_MapSharedMemory64(system); + case SvcId::UnmapSharedMemory: + return SvcWrap_UnmapSharedMemory64(system); + case SvcId::CreateTransferMemory: + return SvcWrap_CreateTransferMemory64(system); + case SvcId::CloseHandle: + return SvcWrap_CloseHandle64(system); + case SvcId::ResetSignal: + return SvcWrap_ResetSignal64(system); + case SvcId::WaitSynchronization: + return SvcWrap_WaitSynchronization64(system); + case SvcId::CancelSynchronization: + return SvcWrap_CancelSynchronization64(system); + case SvcId::ArbitrateLock: + return SvcWrap_ArbitrateLock64(system); + case SvcId::ArbitrateUnlock: + return SvcWrap_ArbitrateUnlock64(system); + case SvcId::WaitProcessWideKeyAtomic: + return SvcWrap_WaitProcessWideKeyAtomic64(system); + case SvcId::SignalProcessWideKey: + return SvcWrap_SignalProcessWideKey64(system); + case SvcId::GetSystemTick: + return SvcWrap_GetSystemTick64(system); + case SvcId::ConnectToNamedPort: + return SvcWrap_ConnectToNamedPort64(system); + case SvcId::SendSyncRequestLight: + return SvcWrap_SendSyncRequestLight64(system); + case SvcId::SendSyncRequest: + return SvcWrap_SendSyncRequest64(system); + case SvcId::SendSyncRequestWithUserBuffer: + return SvcWrap_SendSyncRequestWithUserBuffer64(system); + case SvcId::SendAsyncRequestWithUserBuffer: + return SvcWrap_SendAsyncRequestWithUserBuffer64(system); + case SvcId::GetProcessId: + return SvcWrap_GetProcessId64(system); + case SvcId::GetThreadId: + return SvcWrap_GetThreadId64(system); + case SvcId::Break: + return SvcWrap_Break64(system); + case SvcId::OutputDebugString: + return SvcWrap_OutputDebugString64(system); + case SvcId::ReturnFromException: + return SvcWrap_ReturnFromException64(system); + case SvcId::GetInfo: + return SvcWrap_GetInfo64(system); + case SvcId::FlushEntireDataCache: + return SvcWrap_FlushEntireDataCache64(system); + case SvcId::FlushDataCache: + return SvcWrap_FlushDataCache64(system); + case SvcId::MapPhysicalMemory: + return SvcWrap_MapPhysicalMemory64(system); + case SvcId::UnmapPhysicalMemory: + return SvcWrap_UnmapPhysicalMemory64(system); + case SvcId::GetDebugFutureThreadInfo: + return SvcWrap_GetDebugFutureThreadInfo64(system); + case SvcId::GetLastThreadInfo: + return SvcWrap_GetLastThreadInfo64(system); + case SvcId::GetResourceLimitLimitValue: + return SvcWrap_GetResourceLimitLimitValue64(system); + case SvcId::GetResourceLimitCurrentValue: + return SvcWrap_GetResourceLimitCurrentValue64(system); + case SvcId::SetThreadActivity: + return SvcWrap_SetThreadActivity64(system); + case SvcId::GetThreadContext3: + return SvcWrap_GetThreadContext364(system); + case SvcId::WaitForAddress: + return SvcWrap_WaitForAddress64(system); + case SvcId::SignalToAddress: + return SvcWrap_SignalToAddress64(system); + case SvcId::SynchronizePreemptionState: + return SvcWrap_SynchronizePreemptionState64(system); + case SvcId::GetResourceLimitPeakValue: + return SvcWrap_GetResourceLimitPeakValue64(system); + case SvcId::CreateIoPool: + return SvcWrap_CreateIoPool64(system); + case SvcId::CreateIoRegion: + return SvcWrap_CreateIoRegion64(system); + case SvcId::KernelDebug: + return SvcWrap_KernelDebug64(system); + case SvcId::ChangeKernelTraceState: + return SvcWrap_ChangeKernelTraceState64(system); + case SvcId::CreateSession: + return SvcWrap_CreateSession64(system); + case SvcId::AcceptSession: + return SvcWrap_AcceptSession64(system); + case SvcId::ReplyAndReceiveLight: + return SvcWrap_ReplyAndReceiveLight64(system); + case SvcId::ReplyAndReceive: + return SvcWrap_ReplyAndReceive64(system); + case SvcId::ReplyAndReceiveWithUserBuffer: + return SvcWrap_ReplyAndReceiveWithUserBuffer64(system); + case SvcId::CreateEvent: + return SvcWrap_CreateEvent64(system); + case SvcId::MapIoRegion: + return SvcWrap_MapIoRegion64(system); + case SvcId::UnmapIoRegion: + return SvcWrap_UnmapIoRegion64(system); + case SvcId::MapPhysicalMemoryUnsafe: + return SvcWrap_MapPhysicalMemoryUnsafe64(system); + case SvcId::UnmapPhysicalMemoryUnsafe: + return SvcWrap_UnmapPhysicalMemoryUnsafe64(system); + case SvcId::SetUnsafeLimit: + return SvcWrap_SetUnsafeLimit64(system); + case SvcId::CreateCodeMemory: + return SvcWrap_CreateCodeMemory64(system); + case SvcId::ControlCodeMemory: + return SvcWrap_ControlCodeMemory64(system); + case SvcId::SleepSystem: + return SvcWrap_SleepSystem64(system); + case SvcId::ReadWriteRegister: + return SvcWrap_ReadWriteRegister64(system); + case SvcId::SetProcessActivity: + return SvcWrap_SetProcessActivity64(system); + case SvcId::CreateSharedMemory: + return SvcWrap_CreateSharedMemory64(system); + case SvcId::MapTransferMemory: + return SvcWrap_MapTransferMemory64(system); + case SvcId::UnmapTransferMemory: + return SvcWrap_UnmapTransferMemory64(system); + case SvcId::CreateInterruptEvent: + return SvcWrap_CreateInterruptEvent64(system); + case SvcId::QueryPhysicalAddress: + return SvcWrap_QueryPhysicalAddress64(system); + case SvcId::QueryIoMapping: + return SvcWrap_QueryIoMapping64(system); + case SvcId::CreateDeviceAddressSpace: + return SvcWrap_CreateDeviceAddressSpace64(system); + case SvcId::AttachDeviceAddressSpace: + return SvcWrap_AttachDeviceAddressSpace64(system); + case SvcId::DetachDeviceAddressSpace: + return SvcWrap_DetachDeviceAddressSpace64(system); + case SvcId::MapDeviceAddressSpaceByForce: + return SvcWrap_MapDeviceAddressSpaceByForce64(system); + case SvcId::MapDeviceAddressSpaceAligned: + return SvcWrap_MapDeviceAddressSpaceAligned64(system); + case SvcId::UnmapDeviceAddressSpace: + return SvcWrap_UnmapDeviceAddressSpace64(system); + case SvcId::InvalidateProcessDataCache: + return SvcWrap_InvalidateProcessDataCache64(system); + case SvcId::StoreProcessDataCache: + return SvcWrap_StoreProcessDataCache64(system); + case SvcId::FlushProcessDataCache: + return SvcWrap_FlushProcessDataCache64(system); + case SvcId::DebugActiveProcess: + return SvcWrap_DebugActiveProcess64(system); + case SvcId::BreakDebugProcess: + return SvcWrap_BreakDebugProcess64(system); + case SvcId::TerminateDebugProcess: + return SvcWrap_TerminateDebugProcess64(system); + case SvcId::GetDebugEvent: + return SvcWrap_GetDebugEvent64(system); + case SvcId::ContinueDebugEvent: + return SvcWrap_ContinueDebugEvent64(system); + case SvcId::GetProcessList: + return SvcWrap_GetProcessList64(system); + case SvcId::GetThreadList: + return SvcWrap_GetThreadList64(system); + case SvcId::GetDebugThreadContext: + return SvcWrap_GetDebugThreadContext64(system); + case SvcId::SetDebugThreadContext: + return SvcWrap_SetDebugThreadContext64(system); + case SvcId::QueryDebugProcessMemory: + return SvcWrap_QueryDebugProcessMemory64(system); + case SvcId::ReadDebugProcessMemory: + return SvcWrap_ReadDebugProcessMemory64(system); + case SvcId::WriteDebugProcessMemory: + return SvcWrap_WriteDebugProcessMemory64(system); + case SvcId::SetHardwareBreakPoint: + return SvcWrap_SetHardwareBreakPoint64(system); + case SvcId::GetDebugThreadParam: + return SvcWrap_GetDebugThreadParam64(system); + case SvcId::GetSystemInfo: + return SvcWrap_GetSystemInfo64(system); + case SvcId::CreatePort: + return SvcWrap_CreatePort64(system); + case SvcId::ManageNamedPort: + return SvcWrap_ManageNamedPort64(system); + case SvcId::ConnectToPort: + return SvcWrap_ConnectToPort64(system); + case SvcId::SetProcessMemoryPermission: + return SvcWrap_SetProcessMemoryPermission64(system); + case SvcId::MapProcessMemory: + return SvcWrap_MapProcessMemory64(system); + case SvcId::UnmapProcessMemory: + return SvcWrap_UnmapProcessMemory64(system); + case SvcId::QueryProcessMemory: + return SvcWrap_QueryProcessMemory64(system); + case SvcId::MapProcessCodeMemory: + return SvcWrap_MapProcessCodeMemory64(system); + case SvcId::UnmapProcessCodeMemory: + return SvcWrap_UnmapProcessCodeMemory64(system); + case SvcId::CreateProcess: + return SvcWrap_CreateProcess64(system); + case SvcId::StartProcess: + return SvcWrap_StartProcess64(system); + case SvcId::TerminateProcess: + return SvcWrap_TerminateProcess64(system); + case SvcId::GetProcessInfo: + return SvcWrap_GetProcessInfo64(system); + case SvcId::CreateResourceLimit: + return SvcWrap_CreateResourceLimit64(system); + case SvcId::SetResourceLimitLimitValue: + return SvcWrap_SetResourceLimitLimitValue64(system); + case SvcId::CallSecureMonitor: + return SvcWrap_CallSecureMonitor64(system); + case SvcId::MapInsecureMemory: + return SvcWrap_MapInsecureMemory64(system); + case SvcId::UnmapInsecureMemory: + return SvcWrap_UnmapInsecureMemory64(system); + default: + LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm); + break; } - return &SVC_Table_64[func_num]; } +// clang-format on -void Call(Core::System& system, u32 immediate) { +void Call(Core::System& system, u32 imm) { auto& kernel = system.Kernel(); kernel.EnterSVCProfile(); - auto* thread = GetCurrentThreadPointer(kernel); - thread->SetIsCallingSvc(); - - const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) - : GetSVCInfo32(immediate); - if (info) { - if (info->func) { - info->func(system); - } else { - LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name); - } + if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) { + Call64(system, imm); } else { - LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); + Call32(system, imm); } kernel.ExitSVCProfile(); |