diff options
Diffstat (limited to 'src/core')
209 files changed, 12977 insertions, 5150 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0252c8c31..ff5502d87 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -182,6 +182,8 @@ add_library(core STATIC hle/kernel/k_auto_object_container.cpp hle/kernel/k_auto_object_container.h hle/kernel/k_affinity_mask.h + hle/kernel/k_capabilities.cpp + hle/kernel/k_capabilities.h hle/kernel/k_class_token.cpp hle/kernel/k_class_token.h hle/kernel/k_client_port.cpp @@ -193,6 +195,8 @@ add_library(core STATIC hle/kernel/k_condition_variable.cpp hle/kernel/k_condition_variable.h hle/kernel/k_debug.h + hle/kernel/k_device_address_space.cpp + hle/kernel/k_device_address_space.h hle/kernel/k_dynamic_page_manager.h hle/kernel/k_dynamic_resource_manager.h hle/kernel/k_dynamic_slab_heap.h @@ -221,11 +225,14 @@ add_library(core STATIC hle/kernel/k_memory_manager.h hle/kernel/k_memory_region.h hle/kernel/k_memory_region_type.h + hle/kernel/k_object_name.cpp + hle/kernel/k_object_name.h hle/kernel/k_page_bitmap.h hle/kernel/k_page_buffer.cpp hle/kernel/k_page_buffer.h hle/kernel/k_page_heap.cpp hle/kernel/k_page_heap.h + hle/kernel/k_page_group.cpp hle/kernel/k_page_group.h hle/kernel/k_page_table.cpp hle/kernel/k_page_table.h @@ -293,7 +300,43 @@ add_library(core STATIC hle/kernel/svc.h hle/kernel/svc_common.h hle/kernel/svc_types.h - hle/kernel/svc_wrap.h + hle/kernel/svc/svc_activity.cpp + hle/kernel/svc/svc_address_arbiter.cpp + hle/kernel/svc/svc_address_translation.cpp + hle/kernel/svc/svc_cache.cpp + hle/kernel/svc/svc_code_memory.cpp + hle/kernel/svc/svc_condition_variable.cpp + hle/kernel/svc/svc_debug.cpp + hle/kernel/svc/svc_debug_string.cpp + hle/kernel/svc/svc_device_address_space.cpp + hle/kernel/svc/svc_event.cpp + hle/kernel/svc/svc_exception.cpp + hle/kernel/svc/svc_info.cpp + hle/kernel/svc/svc_insecure_memory.cpp + hle/kernel/svc/svc_interrupt_event.cpp + hle/kernel/svc/svc_io_pool.cpp + hle/kernel/svc/svc_ipc.cpp + hle/kernel/svc/svc_kernel_debug.cpp + hle/kernel/svc/svc_light_ipc.cpp + hle/kernel/svc/svc_lock.cpp + hle/kernel/svc/svc_memory.cpp + hle/kernel/svc/svc_physical_memory.cpp + hle/kernel/svc/svc_port.cpp + hle/kernel/svc/svc_power_management.cpp + hle/kernel/svc/svc_process.cpp + hle/kernel/svc/svc_process_memory.cpp + hle/kernel/svc/svc_processor.cpp + hle/kernel/svc/svc_query_memory.cpp + hle/kernel/svc/svc_register.cpp + hle/kernel/svc/svc_resource_limit.cpp + hle/kernel/svc/svc_secure_monitor_call.cpp + hle/kernel/svc/svc_session.cpp + hle/kernel/svc/svc_shared_memory.cpp + hle/kernel/svc/svc_synchronization.cpp + hle/kernel/svc/svc_thread.cpp + hle/kernel/svc/svc_thread_profiler.cpp + hle/kernel/svc/svc_tick.cpp + hle/kernel/svc/svc_transfer_memory.cpp hle/result.h hle/service/acc/acc.cpp hle/service/acc/acc.h @@ -343,8 +386,6 @@ add_library(core STATIC hle/service/am/omm.h hle/service/am/spsm.cpp hle/service/am/spsm.h - hle/service/am/tcap.cpp - hle/service/am/tcap.h hle/service/aoc/aoc_u.cpp hle/service/aoc/aoc_u.h hle/service/apm/apm.cpp @@ -355,28 +396,18 @@ add_library(core STATIC hle/service/apm/apm_interface.h hle/service/audio/audctl.cpp hle/service/audio/audctl.h - hle/service/audio/auddbg.cpp - hle/service/audio/auddbg.h - hle/service/audio/audin_a.cpp - hle/service/audio/audin_a.h hle/service/audio/audin_u.cpp hle/service/audio/audin_u.h hle/service/audio/audio.cpp hle/service/audio/audio.h - hle/service/audio/audout_a.cpp - hle/service/audio/audout_a.h hle/service/audio/audout_u.cpp hle/service/audio/audout_u.h hle/service/audio/audrec_a.cpp hle/service/audio/audrec_a.h hle/service/audio/audrec_u.cpp hle/service/audio/audrec_u.h - hle/service/audio/audren_a.cpp - hle/service/audio/audren_a.h hle/service/audio/audren_u.cpp hle/service/audio/audren_u.h - hle/service/audio/codecctl.cpp - hle/service/audio/codecctl.h hle/service/audio/errors.h hle/service/audio/hwopus.cpp hle/service/audio/hwopus.h @@ -671,8 +702,6 @@ add_library(core STATIC hle/service/sm/sm_controller.h hle/service/sockets/bsd.cpp hle/service/sockets/bsd.h - hle/service/sockets/ethc.cpp - hle/service/sockets/ethc.h hle/service/sockets/nsd.cpp hle/service/sockets/nsd.h hle/service/sockets/sfdnsres.cpp @@ -739,8 +768,6 @@ add_library(core STATIC hle/service/vi/vi_s.h hle/service/vi/vi_u.cpp hle/service/vi/vi_u.h - hle/service/wlan/wlan.cpp - hle/service/wlan/wlan.h internal_network/network.cpp internal_network/network.h internal_network/network_interface.cpp diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 2df7b0ee8..4a331d4c1 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -1,14 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#ifndef _MSC_VER -#include <cxxabi.h> -#endif - #include <map> #include <optional> + #include "common/bit_field.h" #include "common/common_types.h" +#include "common/demangle.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/arm/symbols.h" @@ -45,9 +43,9 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt std::map<std::string, Symbols::Symbols> symbols; for (const auto& module : modules) { - symbols.insert_or_assign(module.second, - Symbols::GetSymbols(module.first, system.Memory(), - system.CurrentProcess()->Is64BitProcess())); + symbols.insert_or_assign( + module.second, Symbols::GetSymbols(module.first, system.Memory(), + system.ApplicationProcess()->Is64BitProcess())); } for (auto& entry : out) { @@ -71,20 +69,8 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt const auto symbol_set = symbols.find(entry.module); if (symbol_set != symbols.end()) { const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); - if (symbol.has_value()) { -#ifdef _MSC_VER - // TODO(DarkLordZach): Add demangling of symbol names. - entry.name = *symbol; -#else - int status{-1}; - char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)}; - if (status == 0 && demangled != nullptr) { - entry.name = demangled; - std::free(demangled); - } else { - entry.name = *symbol; - } -#endif + if (symbol) { + entry.name = Common::DemangleSymbol(*symbol); } } } diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 7d62d030e..c40771c97 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -5,6 +5,7 @@ #include <array> #include <span> +#include <string> #include <vector> #include <dynarmic/interface/halt_reason.h> diff --git a/src/core/core.cpp b/src/core/core.cpp index 47292cd78..fb9b25d12 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -186,7 +186,7 @@ struct System::Impl { void Run() { std::unique_lock<std::mutex> lk(suspend_guard); - kernel.Suspend(false); + kernel.SuspendApplication(false); core_timing.SyncPause(false); is_paused.store(false, std::memory_order_relaxed); } @@ -195,7 +195,7 @@ struct System::Impl { std::unique_lock<std::mutex> lk(suspend_guard); core_timing.SyncPause(true); - kernel.Suspend(true); + kernel.SuspendApplication(true); is_paused.store(true, std::memory_order_relaxed); } @@ -203,17 +203,17 @@ struct System::Impl { return is_paused.load(std::memory_order_relaxed); } - std::unique_lock<std::mutex> StallProcesses() { + std::unique_lock<std::mutex> StallApplication() { std::unique_lock<std::mutex> lk(suspend_guard); - kernel.Suspend(true); + kernel.SuspendApplication(true); core_timing.SyncPause(true); return lk; } - void UnstallProcesses() { + void UnstallApplication() { if (!IsPaused()) { core_timing.SyncPause(false); - kernel.Suspend(false); + kernel.SuspendApplication(false); } } @@ -221,7 +221,7 @@ struct System::Impl { debugger = std::make_unique<Debugger>(system, port); } - SystemResultStatus SetupForMainProcess(System& system, Frontend::EmuWindow& emu_window) { + SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) { LOG_DEBUG(Core, "initialized OK"); // Setting changes may require a full system reinitialization (e.g., disabling multicore). @@ -273,7 +273,7 @@ struct System::Impl { return SystemResultStatus::ErrorGetLoader; } - SystemResultStatus init_result{SetupForMainProcess(system, emu_window)}; + SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; if (init_result != SystemResultStatus::Success) { LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", static_cast<int>(init_result)); @@ -302,7 +302,7 @@ struct System::Impl { static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); } AddGlueRegistrationForProcess(*app_loader, *main_process); - kernel.MakeCurrentProcess(main_process); + kernel.MakeApplicationProcess(main_process); kernel.InitializeCores(); // Initialize cheat engine @@ -585,12 +585,12 @@ void System::DetachDebugger() { } } -std::unique_lock<std::mutex> System::StallProcesses() { - return impl->StallProcesses(); +std::unique_lock<std::mutex> System::StallApplication() { + return impl->StallApplication(); } -void System::UnstallProcesses() { - impl->UnstallProcesses(); +void System::UnstallApplication() { + impl->UnstallApplication(); } void System::InitializeDebugger() { @@ -648,8 +648,8 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const { return impl->kernel.GlobalSchedulerContext(); } -Kernel::KProcess* System::CurrentProcess() { - return impl->kernel.CurrentProcess(); +Kernel::KProcess* System::ApplicationProcess() { + return impl->kernel.ApplicationProcess(); } Core::DeviceMemory& System::DeviceMemory() { @@ -660,8 +660,8 @@ const Core::DeviceMemory& System::DeviceMemory() const { return *impl->device_memory; } -const Kernel::KProcess* System::CurrentProcess() const { - return impl->kernel.CurrentProcess(); +const Kernel::KProcess* System::ApplicationProcess() const { + return impl->kernel.ApplicationProcess(); } ARM_Interface& System::ArmInterface(std::size_t core_index) { @@ -760,8 +760,8 @@ const Core::SpeedLimiter& System::SpeedLimiter() const { return impl->speed_limiter; } -u64 System::GetCurrentProcessProgramID() const { - return impl->kernel.CurrentProcess()->GetProgramID(); +u64 System::GetApplicationProcessProgramID() const { + return impl->kernel.ApplicationProcess()->GetProgramID(); } Loader::ResultStatus System::GetGameName(std::string& out) const { @@ -880,11 +880,11 @@ bool System::GetExitLock() const { return impl->exit_lock; } -void System::SetCurrentProcessBuildID(const CurrentBuildProcessID& id) { +void System::SetApplicationProcessBuildID(const CurrentBuildProcessID& id) { impl->build_id = id; } -const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const { +const System::CurrentBuildProcessID& System::GetApplicationProcessBuildID() const { return impl->build_id; } diff --git a/src/core/core.h b/src/core/core.h index fb5cda2f5..0042ac170 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -184,8 +184,8 @@ public: /// Forcibly detach the debugger if it is running. void DetachDebugger(); - std::unique_lock<std::mutex> StallProcesses(); - void UnstallProcesses(); + std::unique_lock<std::mutex> StallApplication(); + void UnstallApplication(); /** * Initialize the debugger. @@ -295,11 +295,11 @@ public: /// Gets the manager for the guest device memory [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const; - /// Provides a pointer to the current process - [[nodiscard]] Kernel::KProcess* CurrentProcess(); + /// Provides a pointer to the application process + [[nodiscard]] Kernel::KProcess* ApplicationProcess(); - /// Provides a constant pointer to the current process. - [[nodiscard]] const Kernel::KProcess* CurrentProcess() const; + /// Provides a constant pointer to the application process. + [[nodiscard]] const Kernel::KProcess* ApplicationProcess() const; /// Provides a reference to the core timing instance. [[nodiscard]] Timing::CoreTiming& CoreTiming(); @@ -331,7 +331,7 @@ public: /// Provides a constant reference to the speed limiter [[nodiscard]] const Core::SpeedLimiter& SpeedLimiter() const; - [[nodiscard]] u64 GetCurrentProcessProgramID() const; + [[nodiscard]] u64 GetApplicationProcessProgramID() const; /// Gets the name of the current game [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const; @@ -396,8 +396,8 @@ public: void SetExitLock(bool locked); [[nodiscard]] bool GetExitLock() const; - void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); - [[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const; + void SetApplicationProcessBuildID(const CurrentBuildProcessID& id); + [[nodiscard]] const CurrentBuildProcessID& GetApplicationProcessBuildID() const; /// Register a host thread as an emulated CPU Core. void RegisterCoreThread(std::size_t id); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 0e7b5f943..3a63b52e3 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -45,7 +45,7 @@ CoreTiming::~CoreTiming() { } void CoreTiming::ThreadEntry(CoreTiming& instance) { - constexpr char name[] = "HostTiming"; + static constexpr char name[] = "HostTiming"; MicroProfileOnThreadCreate(name); Common::SetCurrentThreadName(name); Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); @@ -142,16 +142,24 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time, } void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, - std::uintptr_t user_data) { - std::scoped_lock scope{basic_lock}; - const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { - return e.type.lock().get() == event_type.get() && e.user_data == user_data; - }); - - // Removing random items breaks the invariant so we have to re-establish it. - if (itr != event_queue.end()) { - event_queue.erase(itr, event_queue.end()); - std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + std::uintptr_t user_data, bool wait) { + { + std::scoped_lock lk{basic_lock}; + const auto itr = + std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { + return e.type.lock().get() == event_type.get() && e.user_data == user_data; + }); + + // Removing random items breaks the invariant so we have to re-establish it. + if (itr != event_queue.end()) { + event_queue.erase(itr, event_queue.end()); + std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + } + } + + // Force any in-progress events to finish + if (wait) { + std::scoped_lock lk{advance_lock}; } } @@ -190,20 +198,6 @@ u64 CoreTiming::GetClockTicks() const { return CpuCyclesToClockCycles(ticks); } -void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { - std::scoped_lock lock{basic_lock}; - - const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { - return e.type.lock().get() == event_type.get(); - }); - - // Removing random items breaks the invariant so we have to re-establish it. - if (itr != event_queue.end()) { - event_queue.erase(itr, event_queue.end()); - std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - } -} - std::optional<s64> CoreTiming::Advance() { std::scoped_lock lock{advance_lock, basic_lock}; global_timer = GetGlobalTimeNs().count(); diff --git a/src/core/core_timing.h b/src/core/core_timing.h index b5925193c..da366637b 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -98,10 +98,13 @@ public: const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0, bool absolute_time = false); - void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); + void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data, + bool wait = true); - /// We only permit one event of each type in the queue at a time. - void RemoveEvent(const std::shared_ptr<EventType>& event_type); + void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type, + std::uintptr_t user_data) { + UnscheduleEvent(event_type, user_data, false); + } void AddTicks(u64 ticks_to_add); diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index a64a9ac64..945ec528e 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -11,6 +11,7 @@ #include "common/hex_util.h" #include "common/logging/log.h" #include "common/scope_exit.h" +#include "common/settings.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/debugger/gdbstub.h" @@ -95,7 +96,7 @@ static std::string EscapeXML(std::string_view data) { GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) : DebuggerFrontend(backend_), system{system_} { - if (system.CurrentProcess()->Is64BitProcess()) { + if (system.ApplicationProcess()->Is64BitProcess()) { arch = std::make_unique<GDBStubA64>(); } else { arch = std::make_unique<GDBStubA32>(); @@ -339,15 +340,15 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { success = true; break; case BreakpointType::WriteWatch: - success = system.CurrentProcess()->InsertWatchpoint(system, addr, size, - Kernel::DebugWatchpointType::Write); + success = system.ApplicationProcess()->InsertWatchpoint(system, addr, size, + Kernel::DebugWatchpointType::Write); break; case BreakpointType::ReadWatch: - success = system.CurrentProcess()->InsertWatchpoint(system, addr, size, - Kernel::DebugWatchpointType::Read); + success = system.ApplicationProcess()->InsertWatchpoint(system, addr, size, + Kernel::DebugWatchpointType::Read); break; case BreakpointType::AccessWatch: - success = system.CurrentProcess()->InsertWatchpoint( + success = system.ApplicationProcess()->InsertWatchpoint( system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite); break; case BreakpointType::Hardware: @@ -390,15 +391,15 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { break; } case BreakpointType::WriteWatch: - success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size, - Kernel::DebugWatchpointType::Write); + success = system.ApplicationProcess()->RemoveWatchpoint(system, addr, size, + Kernel::DebugWatchpointType::Write); break; case BreakpointType::ReadWatch: - success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size, - Kernel::DebugWatchpointType::Read); + success = system.ApplicationProcess()->RemoveWatchpoint(system, addr, size, + Kernel::DebugWatchpointType::Read); break; case BreakpointType::AccessWatch: - success = system.CurrentProcess()->RemoveWatchpoint( + success = system.ApplicationProcess()->RemoveWatchpoint( system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite); break; case BreakpointType::Hardware: @@ -481,7 +482,7 @@ static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& static std::optional<std::string> GetThreadName(Core::System& system, const Kernel::KThread* thread) { - if (system.CurrentProcess()->Is64BitProcess()) { + if (system.ApplicationProcess()->Is64BitProcess()) { return GetNameFromThreadType64(system.Memory(), thread); } else { return GetNameFromThreadType32(system.Memory(), thread); @@ -554,7 +555,7 @@ void GDBStub::HandleQuery(std::string_view command) { SendReply(fmt::format("TextSeg={:x}", main->first)); } else { SendReply(fmt::format("TextSeg={:x}", - system.CurrentProcess()->PageTable().GetCodeRegionStart())); + system.ApplicationProcess()->PageTable().GetCodeRegionStart())); } } else if (command.starts_with("Xfer:libraries:read::")) { Loader::AppLoader::Modules modules; @@ -728,10 +729,28 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; std::string reply; - auto* process = system.CurrentProcess(); + auto* process = system.ApplicationProcess(); auto& page_table = process->PageTable(); - if (command_str == "get info") { + const char* commands = "Commands:\n" + " get fastmem\n" + " get info\n" + " get mappings\n"; + + if (command_str == "get fastmem") { + if (Settings::IsFastmemEnabled()) { + const auto& impl = page_table.PageTableImpl(); + const auto region = reinterpret_cast<uintptr_t>(impl.fastmem_arena); + const auto region_bits = impl.current_address_space_width_in_bits; + const auto region_size = 1ULL << region_bits; + + reply = fmt::format("Region bits: {}\n" + "Host address: {:#x} - {:#x}\n", + region_bits, region, region + region_size - 1); + } else { + reply = "Fastmem is not enabled.\n"; + } + } else if (command_str == "get info") { Loader::AppLoader::Modules modules; system.GetAppLoader().ReadNSOModules(modules); @@ -787,9 +806,10 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { cur_addr = next_address; } } else if (command_str == "help") { - reply = "Commands:\n get info\n get mappings\n"; + reply = commands; } else { - reply = "Unknown command.\nCommands:\n get info\n get mappings\n"; + reply = "Unknown command.\n"; + reply += commands; } std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()}; diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp index 4bef09bd7..831c48513 100644 --- a/src/core/debugger/gdbstub_arch.cpp +++ b/src/core/debugger/gdbstub_arch.cpp @@ -41,9 +41,8 @@ static void PutSIMDRegister(std::array<u32, 64>& simd_regs, size_t offset, const // For sample XML files see the GDB source /gdb/features // This XML defines what the registers are for this specific ARM device -std::string GDBStubA64::GetTargetXML() const { - constexpr const char* target_xml = - R"(<?xml version="1.0"?> +std::string_view GDBStubA64::GetTargetXML() const { + return R"(<?xml version="1.0"?> <!DOCTYPE target SYSTEM "gdb-target.dtd"> <target version="1.0"> <architecture>aarch64</architecture> @@ -178,8 +177,6 @@ std::string GDBStubA64::GetTargetXML() const { <reg name="fpcr" bitsize="32"/> </feature> </target>)"; - - return target_xml; } std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const { @@ -270,9 +267,8 @@ u32 GDBStubA64::BreakpointInstruction() const { return 0xd4200000; } -std::string GDBStubA32::GetTargetXML() const { - constexpr const char* target_xml = - R"(<?xml version="1.0"?> +std::string_view GDBStubA32::GetTargetXML() const { + return R"(<?xml version="1.0"?> <!DOCTYPE target SYSTEM "gdb-target.dtd"> <target version="1.0"> <architecture>arm</architecture> @@ -378,8 +374,6 @@ std::string GDBStubA32::GetTargetXML() const { <reg name="fpscr" bitsize="32" type="int" group="float" regnum="80"/> </feature> </target>)"; - - return target_xml; } std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const { diff --git a/src/core/debugger/gdbstub_arch.h b/src/core/debugger/gdbstub_arch.h index 2540d6456..34530c788 100644 --- a/src/core/debugger/gdbstub_arch.h +++ b/src/core/debugger/gdbstub_arch.h @@ -16,7 +16,7 @@ namespace Core { class GDBStubArch { public: virtual ~GDBStubArch() = default; - virtual std::string GetTargetXML() const = 0; + virtual std::string_view GetTargetXML() const = 0; virtual std::string RegRead(const Kernel::KThread* thread, size_t id) const = 0; virtual void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const = 0; virtual std::string ReadRegisters(const Kernel::KThread* thread) const = 0; @@ -27,7 +27,7 @@ public: class GDBStubA64 final : public GDBStubArch { public: - std::string GetTargetXML() const override; + std::string_view GetTargetXML() const override; std::string RegRead(const Kernel::KThread* thread, size_t id) const override; void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const override; std::string ReadRegisters(const Kernel::KThread* thread) const override; @@ -47,7 +47,7 @@ private: class GDBStubA32 final : public GDBStubArch { public: - std::string GetTargetXML() const override; + std::string_view GetTargetXML() const override; std::string RegRead(const Kernel::KThread* thread, size_t id) const override; void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const override; std::string ReadRegisters(const Kernel::KThread* thread) const override; diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index 5aab428bb..efdf18cee 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp @@ -41,12 +41,12 @@ static IPSFileType IdentifyMagic(const std::vector<u8>& magic) { return IPSFileType::Error; } - constexpr std::array<u8, 5> patch_magic{{'P', 'A', 'T', 'C', 'H'}}; + static constexpr std::array<u8, 5> patch_magic{{'P', 'A', 'T', 'C', 'H'}}; if (std::equal(magic.begin(), magic.end(), patch_magic.begin())) { return IPSFileType::IPS; } - constexpr std::array<u8, 5> ips32_magic{{'I', 'P', 'S', '3', '2'}}; + static constexpr std::array<u8, 5> ips32_magic{{'I', 'P', 'S', '3', '2'}}; if (std::equal(magic.begin(), magic.end(), ips32_magic.begin())) { return IPSFileType::IPS32; } @@ -55,12 +55,12 @@ static IPSFileType IdentifyMagic(const std::vector<u8>& magic) { } static bool IsEOF(IPSFileType type, const std::vector<u8>& data) { - constexpr std::array<u8, 3> eof{{'E', 'O', 'F'}}; + static constexpr std::array<u8, 3> eof{{'E', 'O', 'F'}}; if (type == IPSFileType::IPS && std::equal(data.begin(), data.end(), eof.begin())) { return true; } - constexpr std::array<u8, 4> eeof{{'E', 'E', 'O', 'F'}}; + static constexpr std::array<u8, 4> eeof{{'E', 'E', 'O', 'F'}}; return type == IPSFileType::IPS32 && std::equal(data.begin(), data.end(), eeof.begin()); } diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 878d832c2..a6960170c 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -71,7 +71,7 @@ static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bo } static std::string GetCNMTName(TitleType type, u64 title_id) { - constexpr std::array<const char*, 9> TITLE_TYPE_NAMES{ + static constexpr std::array<const char*, 9> TITLE_TYPE_NAMES{ "SystemProgram", "SystemData", "SystemUpdate", diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 1567da231..769065b6f 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -172,7 +172,7 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir, // be interpreted as the title id of the current process. if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { if (title_id == 0) { - title_id = system.GetCurrentProcessProgramID(); + title_id = system.GetApplicationProcessProgramID(); } } diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 13cbdb734..45567b840 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -25,6 +25,26 @@ constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, }; +static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>(); + +static constexpr inline u64 VirtualCoreMask = [] { + u64 mask = 0; + for (size_t i = 0; i < NumVirtualCores; ++i) { + mask |= (UINT64_C(1) << i); + } + return mask; +}(); + +static constexpr inline u64 ConvertVirtualCoreMaskToPhysical(u64 v_core_mask) { + u64 p_core_mask = 0; + while (v_core_mask != 0) { + const u64 next = std::countr_zero(v_core_mask); + v_core_mask &= ~(static_cast<u64>(1) << next); + p_core_mask |= (static_cast<u64>(1) << VirtualToPhysicalCoreMap[next]); + } + return p_core_mask; +} + // Cortex-A57 supports 4 memory watchpoints constexpr u64 NUM_WATCHPOINTS = 4; diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 1c91bbe40..17d663379 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -23,7 +23,8 @@ void EmulatedConsole::SetTouchParams() { // We can't use mouse as touch if native mouse is enabled if (!Settings::values.mouse_enabled) { - touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + touch_params[index++] = + Common::ParamPackage{"engine:mouse,axis_x:0,axis_y:1,button:0,port:2"}; } touch_params[index++] = diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 71364c323..6d5a3dead 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> +#include <common/scope_exit.h> #include "common/polyfill_ranges.h" #include "common/thread.h" @@ -11,6 +12,7 @@ namespace Core::HID { constexpr s32 HID_JOYSTICK_MAX = 0x7fff; constexpr s32 HID_TRIGGER_MAX = 0x7fff; +constexpr u32 TURBO_BUTTON_DELAY = 4; // Use a common UUID for TAS and Virtual Gamepad constexpr Common::UUID TAS_UUID = Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; @@ -93,6 +95,7 @@ void EmulatedController::ReloadFromSettings() { motion_params[index] = Common::ParamPackage(player.motions[index]); } + controller.color_values = {}; controller.colors_state.fullkey = { .body = GetNpadColor(player.body_color_left), .button = GetNpadColor(player.button_color_left), @@ -106,6 +109,8 @@ void EmulatedController::ReloadFromSettings() { .button = GetNpadColor(player.button_color_right), }; + ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs); + // Other or debug controller should always be a pro controller if (npad_id_type != NpadIdType::Other) { SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); @@ -132,18 +137,28 @@ void EmulatedController::LoadDevices() { trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR]; + color_params[LeftIndex] = left_joycon; + color_params[RightIndex] = right_joycon; + color_params[LeftIndex].Set("color", true); + color_params[RightIndex].Set("color", true); + battery_params[LeftIndex] = left_joycon; battery_params[RightIndex] = right_joycon; battery_params[LeftIndex].Set("battery", true); battery_params[RightIndex].Set("battery", true); - camera_params = Common::ParamPackage{"engine:camera,camera:1"}; - nfc_params = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; + camera_params[0] = right_joycon; + camera_params[0].Set("camera", true); + camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; + ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; + nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; + nfc_params[1] = right_joycon; + nfc_params[1].Set("nfc", true); output_params[LeftIndex] = left_joycon; output_params[RightIndex] = right_joycon; - output_params[2] = camera_params; - output_params[3] = nfc_params; + output_params[2] = camera_params[1]; + output_params[3] = nfc_params[0]; output_params[LeftIndex].Set("output", true); output_params[RightIndex].Set("output", true); output_params[2].Set("output", true); @@ -159,8 +174,11 @@ void EmulatedController::LoadDevices() { Common::Input::CreateInputDevice); std::ranges::transform(battery_params, battery_devices.begin(), Common::Input::CreateInputDevice); - camera_devices = Common::Input::CreateInputDevice(camera_params); - nfc_devices = Common::Input::CreateInputDevice(nfc_params); + std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(camera_params, camera_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(ring_params, ring_analog_devices.begin(), + Common::Input::CreateInputDevice); + std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice); std::ranges::transform(output_params, output_devices.begin(), Common::Input::CreateOutputDevice); @@ -322,6 +340,19 @@ void EmulatedController::ReloadInput() { battery_devices[index]->ForceUpdate(); } + for (std::size_t index = 0; index < color_devices.size(); ++index) { + if (!color_devices[index]) { + continue; + } + color_devices[index]->SetCallback({ + .on_change = + [this, index](const Common::Input::CallbackStatus& callback) { + SetColors(callback, index); + }, + }); + color_devices[index]->ForceUpdate(); + } + for (std::size_t index = 0; index < motion_devices.size(); ++index) { if (!motion_devices[index]) { continue; @@ -335,22 +366,37 @@ void EmulatedController::ReloadInput() { motion_devices[index]->ForceUpdate(); } - if (camera_devices) { - camera_devices->SetCallback({ + for (std::size_t index = 0; index < camera_devices.size(); ++index) { + if (!camera_devices[index]) { + continue; + } + camera_devices[index]->SetCallback({ .on_change = [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); }, }); - camera_devices->ForceUpdate(); + camera_devices[index]->ForceUpdate(); } - if (nfc_devices) { - if (npad_id_type == NpadIdType::Handheld || npad_id_type == NpadIdType::Player1) { - nfc_devices->SetCallback({ - .on_change = - [this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); }, - }); - nfc_devices->ForceUpdate(); + for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) { + if (!ring_analog_devices[index]) { + continue; } + ring_analog_devices[index]->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); }, + }); + ring_analog_devices[index]->ForceUpdate(); + } + + for (std::size_t index = 0; index < nfc_devices.size(); ++index) { + if (!nfc_devices[index]) { + continue; + } + nfc_devices[index]->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); }, + }); + nfc_devices[index]->ForceUpdate(); } // Register TAS devices. No need to force update @@ -402,6 +448,7 @@ void EmulatedController::ReloadInput() { }, }); } + turbo_button_state = 0; } void EmulatedController::UnloadInput() { @@ -420,6 +467,9 @@ void EmulatedController::UnloadInput() { for (auto& battery : battery_devices) { battery.reset(); } + for (auto& color : color_devices) { + color.reset(); + } for (auto& output : output_devices) { output.reset(); } @@ -435,8 +485,15 @@ void EmulatedController::UnloadInput() { for (auto& stick : virtual_stick_devices) { stick.reset(); } - camera_devices.reset(); - nfc_devices.reset(); + for (auto& camera : camera_devices) { + camera.reset(); + } + for (auto& ring : ring_analog_devices) { + ring.reset(); + } + for (auto& nfc : nfc_devices) { + nfc.reset(); + } } void EmulatedController::EnableConfiguration() { @@ -448,6 +505,11 @@ void EmulatedController::EnableConfiguration() { void EmulatedController::DisableConfiguration() { is_configuring = false; + // Get Joycon colors before turning on the controller + for (const auto& color_device : color_devices) { + color_device->ForceUpdate(); + } + // Apply temporary npad type to the real controller if (tmp_npad_type != npad_type) { if (is_connected) { @@ -501,6 +563,9 @@ void EmulatedController::SaveCurrentConfig() { for (std::size_t index = 0; index < player.motions.size(); ++index) { player.motions[index] = motion_params[index].Serialize(); } + if (npad_id_type == NpadIdType::Player1) { + Settings::values.ringcon_analogs = ring_params[0].Serialize(); + } } void EmulatedController::RestoreConfig() { @@ -624,6 +689,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback } current_status.toggle = new_status.toggle; + current_status.turbo = new_status.turbo; current_status.uuid = uuid; // Update button status with current @@ -772,17 +838,21 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, if (index >= controller.stick_values.size()) { return; } - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); }); + std::scoped_lock lock{mutex}; const auto stick_value = TransformToStick(callback); // Only read stick values that have the same uuid or are over the threshold to avoid flapping if (controller.stick_values[index].uuid != uuid) { const bool is_tas = uuid == TAS_UUID; if (is_tas && stick_value.x.value == 0 && stick_value.y.value == 0) { + trigger_guard.Cancel(); return; } if (!is_tas && !stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) { + trigger_guard.Cancel(); return; } } @@ -793,8 +863,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, if (is_configuring) { controller.analog_stick_state.left = {}; controller.analog_stick_state.right = {}; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Stick, false); return; } @@ -819,9 +887,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down); break; } - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Stick, true); } void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback, @@ -829,7 +894,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac if (index >= controller.trigger_values.size()) { return; } - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); }); + std::scoped_lock lock{mutex}; const auto trigger_value = TransformToTrigger(callback); // Only read trigger values that have the same uuid or are pressed once @@ -845,13 +912,12 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac if (is_configuring) { controller.gc_trigger_state.left = 0; controller.gc_trigger_state.right = 0; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Trigger, false); return; } // Only GC controllers have analog triggers if (npad_type != NpadStyleIndex::GameCube) { + trigger_guard.Cancel(); return; } @@ -868,9 +934,6 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac controller.npad_button_state.zr.Assign(trigger.pressed.value); break; } - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Trigger, true); } void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback, @@ -878,7 +941,8 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback if (index >= controller.motion_values.size()) { return; } - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); }); + std::scoped_lock lock{mutex}; auto& raw_status = controller.motion_values[index].raw_status; auto& emulated = controller.motion_values[index].emulated; @@ -893,14 +957,12 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback raw_status.gyro.y.value, raw_status.gyro.z.value, }); - emulated.SetGyroThreshold(raw_status.gyro.x.properties.threshold); + emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold); emulated.UpdateRotation(raw_status.delta_timestamp); emulated.UpdateOrientation(raw_status.delta_timestamp); force_update_motion = raw_status.force_update; if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Motion, false); return; } @@ -910,9 +972,56 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback motion.rotation = emulated.GetRotations(); motion.orientation = emulated.GetOrientation(); motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); +} - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Motion, true); +void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback, + std::size_t index) { + if (index >= controller.color_values.size()) { + return; + } + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); }); + std::scoped_lock lock{mutex}; + controller.color_values[index] = TransformToColor(callback); + + if (is_configuring) { + return; + } + + if (controller.color_values[index].body == 0) { + trigger_guard.Cancel(); + return; + } + + controller.colors_state.fullkey = { + .body = GetNpadColor(controller.color_values[index].body), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + if (npad_type == NpadStyleIndex::ProController) { + controller.colors_state.left = { + .body = GetNpadColor(controller.color_values[index].left_grip), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + controller.colors_state.right = { + .body = GetNpadColor(controller.color_values[index].right_grip), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + } else { + switch (index) { + case LeftIndex: + controller.colors_state.left = { + .body = GetNpadColor(controller.color_values[index].body), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + break; + case RightIndex: + controller.colors_state.right = { + .body = GetNpadColor(controller.color_values[index].body), + .button = GetNpadColor(controller.color_values[index].buttons), + }; + break; + } + } } void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback, @@ -920,12 +1029,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac if (index >= controller.battery_values.size()) { return; } - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); }); + std::scoped_lock lock{mutex}; controller.battery_values[index] = TransformToBattery(callback); if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Battery, false); return; } @@ -981,18 +1089,14 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac }; break; } - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Battery, true); } void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); }); + std::scoped_lock lock{mutex}; controller.camera_values = TransformToCamera(callback); if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::IrSensor, false); return; } @@ -1000,18 +1104,28 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback controller.camera_state.format = static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format); controller.camera_state.data = controller.camera_values.data; +} - lock.unlock(); - TriggerOnChange(ControllerTriggerType::IrSensor, true); +void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) { + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); }); + std::scoped_lock lock{mutex}; + const auto force_value = TransformToStick(callback); + + controller.ring_analog_value = force_value.x; + + if (is_configuring) { + return; + } + + controller.ring_analog_state.force = force_value.x.value; } void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { - std::unique_lock lock{mutex}; + SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); }); + std::scoped_lock lock{mutex}; controller.nfc_values = TransformToNfc(callback); if (is_configuring) { - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Nfc, false); return; } @@ -1019,9 +1133,6 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { controller.nfc_values.state, controller.nfc_values.data, }; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Nfc, true); } bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { @@ -1053,7 +1164,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v .type = type, }; return output_devices[device_index]->SetVibration(status) == - Common::Input::VibrationError::None; + Common::Input::DriverResult::Success; } bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { @@ -1075,16 +1186,32 @@ bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { return output_devices[device_index]->IsVibrationEnabled(); } -bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { - LOG_INFO(Service_HID, "Set polling mode {}", polling_mode); - auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; +Common::Input::DriverResult EmulatedController::SetPollingMode( + EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) { + LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index); + + auto& left_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Left)]; + auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; auto& nfc_output_device = output_devices[3]; - const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); - const auto mapped_nfc_result = output_device->SetPollingMode(polling_mode); + if (device_index == EmulatedDeviceIndex::LeftIndex) { + return left_output_device->SetPollingMode(polling_mode); + } + + if (device_index == EmulatedDeviceIndex::RightIndex) { + const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); + const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode); - return virtual_nfc_result == Common::Input::PollingError::None || - mapped_nfc_result == Common::Input::PollingError::None; + if (virtual_nfc_result == Common::Input::DriverResult::Success) { + return virtual_nfc_result; + } + return mapped_nfc_result; + } + + left_output_device->SetPollingMode(polling_mode); + right_output_device->SetPollingMode(polling_mode); + nfc_output_device->SetPollingMode(polling_mode); + return Common::Input::DriverResult::Success; } bool EmulatedController::SetCameraFormat( @@ -1095,13 +1222,22 @@ bool EmulatedController::SetCameraFormat( auto& camera_output_device = output_devices[2]; if (right_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>( - camera_format)) == Common::Input::CameraError::None) { + camera_format)) == Common::Input::DriverResult::Success) { return true; } // Fallback to Qt camera if native device doesn't have support return camera_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>( - camera_format)) == Common::Input::CameraError::None; + camera_format)) == Common::Input::DriverResult::Success; +} + +Common::ParamPackage EmulatedController::GetRingParam() const { + return ring_params[0]; +} + +void EmulatedController::SetRingParam(Common::ParamPackage param) { + ring_params[0] = std::move(param); + ReloadInput(); } bool EmulatedController::HasNfc() const { @@ -1148,6 +1284,26 @@ void EmulatedController::SetLedPattern() { } } +void EmulatedController::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode) { + for (auto& motion : controller.motion_values) { + switch (mode) { + case GyroscopeZeroDriftMode::Loose: + motion_sensitivity = motion.emulated.IsAtRestLoose; + motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose); + break; + case GyroscopeZeroDriftMode::Tight: + motion_sensitivity = motion.emulated.IsAtRestThight; + motion.emulated.SetGyroThreshold(motion.emulated.ThresholdThight); + break; + case GyroscopeZeroDriftMode::Standard: + default: + motion_sensitivity = motion.emulated.IsAtRestStandard; + motion.emulated.SetGyroThreshold(motion.emulated.ThresholdStandard); + break; + } + } +} + void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) { supported_style_tag = supported_styles; if (!is_connected) { @@ -1255,39 +1411,35 @@ void EmulatedController::Connect(bool use_temporary_value) { return; } - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); }); + std::scoped_lock lock{mutex}; if (is_configuring) { tmp_is_connected = true; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Connected, false); return; } if (is_connected) { + trigger_guard.Cancel(); return; } is_connected = true; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Connected, true); } void EmulatedController::Disconnect() { - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); }); + std::scoped_lock lock{mutex}; if (is_configuring) { tmp_is_connected = false; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Disconnected, false); return; } if (!is_connected) { + trigger_guard.Cancel(); return; } is_connected = false; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Disconnected, true); } bool EmulatedController::IsConnected(bool get_temporary_value) const { @@ -1312,19 +1464,21 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c } void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { - std::unique_lock lock{mutex}; + auto trigger_guard = + SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); }); + std::scoped_lock lock{mutex}; if (is_configuring) { if (tmp_npad_type == npad_type_) { + trigger_guard.Cancel(); return; } tmp_npad_type = npad_type_; - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Type, false); return; } if (npad_type == npad_type_) { + trigger_guard.Cancel(); return; } if (is_connected) { @@ -1332,9 +1486,6 @@ void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { NpadIdTypeToIndex(npad_id_type)); } npad_type = npad_type_; - - lock.unlock(); - TriggerOnChange(ControllerTriggerType::Type, true); } LedPattern EmulatedController::GetLedPattern() const { @@ -1395,6 +1546,10 @@ CameraValues EmulatedController::GetCameraValues() const { return controller.camera_values; } +RingAnalogValue EmulatedController::GetRingSensorValues() const { + return controller.ring_analog_value; +} + HomeButtonState EmulatedController::GetHomeButtons() const { std::scoped_lock lock{mutex}; if (is_configuring) { @@ -1416,7 +1571,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const { if (is_configuring) { return {}; } - return controller.npad_button_state; + return {controller.npad_button_state.raw & GetTurboButtonMask()}; } DebugPadButton EmulatedController::GetDebugPadButtons() const { @@ -1428,22 +1583,12 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const { } AnalogSticks EmulatedController::GetSticks() const { - std::unique_lock lock{mutex}; + std::scoped_lock lock{mutex}; if (is_configuring) { return {}; } - // Some drivers like stick from buttons need constant refreshing - for (auto& device : stick_devices) { - if (!device) { - continue; - } - lock.unlock(); - device->SoftUpdate(); - lock.lock(); - } - return controller.analog_stick_state; } @@ -1488,6 +1633,10 @@ const CameraState& EmulatedController::GetCamera() const { return controller.camera_state; } +RingSensorForce EmulatedController::GetRingSensorForce() const { + return controller.ring_analog_state; +} + const NfcState& EmulatedController::GetNfc() const { std::scoped_lock lock{mutex}; return controller.nfc_state; @@ -1530,4 +1679,74 @@ void EmulatedController::DeleteCallback(int key) { } callback_list.erase(iterator); } + +void EmulatedController::TurboButtonUpdate() { + turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2); +} + +NpadButton EmulatedController::GetTurboButtonMask() const { + // Apply no mask when disabled + if (turbo_button_state < TURBO_BUTTON_DELAY) { + return {NpadButton::All}; + } + + NpadButtonState button_mask{}; + for (std::size_t index = 0; index < controller.button_values.size(); ++index) { + if (!controller.button_values[index].turbo) { + continue; + } + + switch (index) { + case Settings::NativeButton::A: + button_mask.a.Assign(1); + break; + case Settings::NativeButton::B: + button_mask.b.Assign(1); + break; + case Settings::NativeButton::X: + button_mask.x.Assign(1); + break; + case Settings::NativeButton::Y: + button_mask.y.Assign(1); + break; + case Settings::NativeButton::L: + button_mask.l.Assign(1); + break; + case Settings::NativeButton::R: + button_mask.r.Assign(1); + break; + case Settings::NativeButton::ZL: + button_mask.zl.Assign(1); + break; + case Settings::NativeButton::ZR: + button_mask.zr.Assign(1); + break; + case Settings::NativeButton::DLeft: + button_mask.left.Assign(1); + break; + case Settings::NativeButton::DUp: + button_mask.up.Assign(1); + break; + case Settings::NativeButton::DRight: + button_mask.right.Assign(1); + break; + case Settings::NativeButton::DDown: + button_mask.down.Assign(1); + break; + case Settings::NativeButton::SL: + button_mask.left_sl.Assign(1); + button_mask.right_sl.Assign(1); + break; + case Settings::NativeButton::SR: + button_mask.left_sr.Assign(1); + button_mask.right_sr.Assign(1); + break; + default: + break; + } + } + + return static_cast<NpadButton>(~button_mask.raw); +} + } // namespace Core::HID diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index a398543a6..a9da465a2 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -35,19 +35,27 @@ using ControllerMotionDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>; using TriggerDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>; +using ColorDevices = + std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; using BatteryDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; -using CameraDevices = std::unique_ptr<Common::Input::InputDevice>; -using NfcDevices = std::unique_ptr<Common::Input::InputDevice>; +using CameraDevices = + std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; +using RingAnalogDevices = + std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; +using NfcDevices = + std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>; using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>; using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; +using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>; using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>; -using CameraParams = Common::ParamPackage; -using NfcParams = Common::ParamPackage; +using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>; +using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>; +using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>; using OutputParams = std::array<Common::ParamPackage, output_devices_size>; using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>; @@ -58,6 +66,7 @@ using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::Native using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>; using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>; using CameraValues = Common::Input::CameraStatus; +using RingAnalogValue = Common::Input::AnalogStatus; using NfcValues = Common::Input::NfcStatus; using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>; @@ -84,6 +93,10 @@ struct CameraState { std::size_t sample{}; }; +struct RingSensorForce { + f32 force; +}; + struct NfcState { Common::Input::NfcState state{}; std::vector<u8> data{}; @@ -116,6 +129,7 @@ struct ControllerStatus { BatteryValues battery_values{}; VibrationValues vibration_values{}; CameraValues camera_values{}; + RingAnalogValue ring_analog_value{}; NfcValues nfc_values{}; // Data for HID serices @@ -129,6 +143,7 @@ struct ControllerStatus { ControllerColors colors_state{}; BatteryLevelState battery_state{}; CameraState camera_state{}; + RingSensorForce ring_analog_state{}; NfcState nfc_state{}; }; @@ -141,6 +156,7 @@ enum class ControllerTriggerType { Battery, Vibration, IrSensor, + RingController, Nfc, Connected, Disconnected, @@ -294,6 +310,9 @@ public: /// Returns the latest camera status from the controller with parameters CameraValues GetCameraValues() const; + /// Returns the latest status of analog input from the ring sensor with parameters + RingAnalogValue GetRingSensorValues() const; + /// Returns the latest status of button input for the hid::HomeButton service HomeButtonState GetHomeButtons() const; @@ -324,6 +343,9 @@ public: /// Returns the latest camera status from the controller const CameraState& GetCamera() const; + /// Returns the latest ringcon force sensor value + RingSensorForce GetRingSensorForce() const; + /// Returns the latest ntag status from the controller const NfcState& GetNfc() const; @@ -341,10 +363,12 @@ public: /** * Sets the desired data to be polled from a controller + * @param device_index index of the controller to set the polling mode * @param polling_mode type of input desired buttons, gyro, nfc, ir, etc. - * @return true if SetPollingMode was successfull + * @return driver result from this command */ - bool SetPollingMode(Common::Input::PollingMode polling_mode); + Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index, + Common::Input::PollingMode polling_mode); /** * Sets the desired camera format to be polled from a controller @@ -353,6 +377,15 @@ public: */ bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format); + // Returns the current mapped ring device + Common::ParamPackage GetRingParam() const; + + /** + * Updates the current mapped ring device + * @param param ParamPackage with ring sensor data to be mapped + */ + void SetRingParam(Common::ParamPackage param); + /// Returns true if the device has nfc support bool HasNfc() const; @@ -365,6 +398,9 @@ public: /// Asks the output device to change the player led pattern void SetLedPattern(); + /// Changes sensitivity of the motion sensor + void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode); + /** * Adds a callback to the list of events * @param update_callback A ConsoleUpdateCallback that will be triggered @@ -378,6 +414,9 @@ public: */ void DeleteCallback(int key); + /// Swaps the state of the turbo buttons + void TurboButtonUpdate(); + private: /// creates input devices from params void LoadDevices(); @@ -433,9 +472,16 @@ private: void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index); /** + * Updates the color status of the controller + * @param callback A CallbackStatus containing the color status + * @param index color ID of the to be updated + */ + void SetColors(const Common::Input::CallbackStatus& callback, std::size_t index); + + /** * Updates the battery status of the controller * @param callback A CallbackStatus containing the battery status - * @param index Button ID of the to be updated + * @param index battery ID of the to be updated */ void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index); @@ -446,6 +492,12 @@ private: void SetCamera(const Common::Input::CallbackStatus& callback); /** + * Updates the ring analog sensor status of the ring controller + * @param callback A CallbackStatus containing the force status + */ + void SetRingAnalog(const Common::Input::CallbackStatus& callback); + + /** * Updates the nfc status of the controller * @param callback A CallbackStatus containing the nfc status */ @@ -465,6 +517,8 @@ private: */ void TriggerOnChange(ControllerTriggerType type, bool is_service_update); + NpadButton GetTurboButtonMask() const; + const NpadIdType npad_id_type; NpadStyleIndex npad_type{NpadStyleIndex::None}; NpadStyleIndex original_npad_type{NpadStyleIndex::None}; @@ -472,8 +526,9 @@ private: bool is_connected{false}; bool is_configuring{false}; bool system_buttons_enabled{true}; - f32 motion_sensitivity{0.01f}; + f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; bool force_update_motion{false}; + u32 turbo_button_state{0}; // Temporary values to avoid doing changes while the controller is in configuring mode NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; @@ -484,7 +539,9 @@ private: ControllerMotionParams motion_params; TriggerParams trigger_params; BatteryParams battery_params; + ColorParams color_params; CameraParams camera_params; + RingAnalogParams ring_params; NfcParams nfc_params; OutputParams output_params; @@ -493,7 +550,9 @@ private: ControllerMotionDevices motion_devices; TriggerDevices trigger_devices; BatteryDevices battery_devices; + ColorDevices color_devices; CameraDevices camera_devices; + RingAnalogDevices ring_analog_devices; NfcDevices nfc_devices; OutputDevices output_devices; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index e421828d2..578a6ff61 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -14,7 +14,6 @@ EmulatedDevices::EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default; void EmulatedDevices::ReloadFromSettings() { - ring_params = Common::ParamPackage(Settings::values.ringcon_analogs); ReloadInput(); } @@ -35,9 +34,12 @@ void EmulatedDevices::ReloadInput() { // First two axis are reserved for mouse position key_index = 2; for (auto& mouse_device : mouse_analog_devices) { + // Mouse axis are only mapped on port 1, pad 0 Common::ParamPackage mouse_params; mouse_params.Set("engine", "mouse"); mouse_params.Set("axis", static_cast<int>(key_index)); + mouse_params.Set("port", 1); + mouse_params.Set("pad", 0); mouse_device = Common::Input::CreateInputDevice(mouse_params); key_index++; } @@ -66,8 +68,6 @@ void EmulatedDevices::ReloadInput() { key_index++; } - ring_analog_device = Common::Input::CreateInputDevice(ring_params); - for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { continue; @@ -122,13 +122,6 @@ void EmulatedDevices::ReloadInput() { }, }); } - - if (ring_analog_device) { - ring_analog_device->SetCallback({ - .on_change = - [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); }, - }); - } } void EmulatedDevices::UnloadInput() { @@ -145,7 +138,6 @@ void EmulatedDevices::UnloadInput() { for (auto& button : keyboard_modifier_devices) { button.reset(); } - ring_analog_device.reset(); } void EmulatedDevices::EnableConfiguration() { @@ -165,7 +157,6 @@ void EmulatedDevices::SaveCurrentConfig() { if (!is_configuring) { return; } - Settings::values.ringcon_analogs = ring_params.Serialize(); } void EmulatedDevices::RestoreConfig() { @@ -175,15 +166,6 @@ void EmulatedDevices::RestoreConfig() { ReloadFromSettings(); } -Common::ParamPackage EmulatedDevices::GetRingParam() const { - return ring_params; -} - -void EmulatedDevices::SetRingParam(Common::ParamPackage param) { - ring_params = std::move(param); - ReloadInput(); -} - void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { @@ -430,23 +412,6 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac TriggerOnChange(DeviceTriggerType::Mouse); } -void EmulatedDevices::SetRingAnalog(const Common::Input::CallbackStatus& callback) { - std::lock_guard lock{mutex}; - const auto force_value = TransformToStick(callback); - - device_status.ring_analog_value = force_value.x; - - if (is_configuring) { - device_status.ring_analog_value = {}; - TriggerOnChange(DeviceTriggerType::RingController); - return; - } - - device_status.ring_analog_state.force = force_value.x.value; - - TriggerOnChange(DeviceTriggerType::RingController); -} - KeyboardValues EmulatedDevices::GetKeyboardValues() const { std::scoped_lock lock{mutex}; return device_status.keyboard_values; @@ -462,10 +427,6 @@ MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { return device_status.mouse_button_values; } -RingAnalogValue EmulatedDevices::GetRingSensorValues() const { - return device_status.ring_analog_value; -} - KeyboardKey EmulatedDevices::GetKeyboard() const { std::scoped_lock lock{mutex}; return device_status.keyboard_state; @@ -491,10 +452,6 @@ AnalogStickState EmulatedDevices::GetMouseWheel() const { return device_status.mouse_wheel_state; } -RingSensorForce EmulatedDevices::GetRingSensorForce() const { - return device_status.ring_analog_state; -} - void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { std::scoped_lock lock{callback_mutex}; for (const auto& poller_pair : callback_list) { diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 4cdbf9dc6..76f9150df 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -26,11 +26,9 @@ using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice using MouseAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMouseWheel::NumMouseWheels>; using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>; -using RingAnalogDevice = std::unique_ptr<Common::Input::InputDevice>; using MouseButtonParams = std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>; -using RingAnalogParams = Common::ParamPackage; using KeyboardValues = std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardKeys>; @@ -41,17 +39,12 @@ using MouseButtonValues = using MouseAnalogValues = std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>; using MouseStickValue = Common::Input::TouchStatus; -using RingAnalogValue = Common::Input::AnalogStatus; struct MousePosition { f32 x; f32 y; }; -struct RingSensorForce { - f32 force; -}; - struct DeviceStatus { // Data from input_common KeyboardValues keyboard_values{}; @@ -59,7 +52,6 @@ struct DeviceStatus { MouseButtonValues mouse_button_values{}; MouseAnalogValues mouse_analog_values{}; MouseStickValue mouse_stick_value{}; - RingAnalogValue ring_analog_value{}; // Data for HID serices KeyboardKey keyboard_state{}; @@ -67,7 +59,6 @@ struct DeviceStatus { MouseButton mouse_button_state{}; MousePosition mouse_position_state{}; AnalogStickState mouse_wheel_state{}; - RingSensorForce ring_analog_state{}; }; enum class DeviceTriggerType { @@ -138,9 +129,6 @@ public: /// Returns the latest status of button input from the mouse with parameters MouseButtonValues GetMouseButtonsValues() const; - /// Returns the latest status of analog input from the ring sensor with parameters - RingAnalogValue GetRingSensorValues() const; - /// Returns the latest status of button input from the keyboard KeyboardKey GetKeyboard() const; @@ -156,9 +144,6 @@ public: /// Returns the latest mouse wheel change AnalogStickState GetMouseWheel() const; - /// Returns the latest ringcon force sensor value - RingSensorForce GetRingSensorForce() const; - /** * Adds a callback to the list of events * @param update_callback InterfaceUpdateCallback that will be triggered @@ -224,14 +209,11 @@ private: bool is_configuring{false}; - RingAnalogParams ring_params; - KeyboardDevices keyboard_devices; KeyboardModifierDevices keyboard_modifier_devices; MouseButtonDevices mouse_button_devices; MouseAnalogDevices mouse_analog_devices; MouseStickDevice mouse_stick_device; - RingAnalogDevice ring_analog_device; mutable std::mutex mutex; mutable std::mutex callback_mutex; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index e3b1cfbc6..6b35f448c 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -282,6 +282,13 @@ enum class VibrationGcErmCommand : u64 { StopHard = 2, }; +// This is nn::hid::GyroscopeZeroDriftMode +enum class GyroscopeZeroDriftMode : u32 { + Loose = 0, + Standard = 1, + Tight = 2, +}; + // This is nn::hid::NpadStyleTag struct NpadStyleTag { union { diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 502692875..3f7b8c090 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -304,6 +304,18 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal return nfc; } +Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) { + switch (callback.type) { + case Common::Input::InputType::Color: + return callback.color_status; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type); + return {}; + break; + } +} + void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; float& raw_value = analog.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index b7eb6e660..c51c03e57 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -88,11 +88,19 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu * Converts raw input data into a valid nfc status. * * @param callback Supported callbacks: Nfc. - * @return A valid CameraObject object. + * @return A valid data tag vector. */ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback); /** + * Converts raw input data into a valid color status. + * + * @param callback Supported callbacks: Color. + * @return A valid Color object. + */ +Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback); + +/** * Converts raw analog data into a valid analog value * @param analog An analog object containing raw data and properties * @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f. diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp index b1f658e62..eef6edf4b 100644 --- a/src/core/hid/motion_input.cpp +++ b/src/core/hid/motion_input.cpp @@ -9,7 +9,7 @@ namespace Core::HID { MotionInput::MotionInput() { // Initialize PID constants with default values SetPID(0.3f, 0.005f, 0.0f); - SetGyroThreshold(0.007f); + SetGyroThreshold(ThresholdStandard); } void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) { @@ -26,11 +26,11 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { gyro = gyroscope - gyro_bias; // Auto adjust drift to minimize drift - if (!IsMoving(0.1f)) { + if (!IsMoving(IsAtRestRelaxed)) { gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); } - if (gyro.Length() < gyro_threshold) { + if (gyro.Length() < gyro_threshold * user_gyro_threshold) { gyro = {}; } else { only_accelerometer = false; @@ -49,6 +49,10 @@ void MotionInput::SetGyroThreshold(f32 threshold) { gyro_threshold = threshold; } +void MotionInput::SetUserGyroThreshold(f32 threshold) { + user_gyro_threshold = threshold / ThresholdStandard; +} + void MotionInput::EnableReset(bool reset) { reset_enabled = reset; } @@ -208,7 +212,7 @@ void MotionInput::ResetOrientation() { if (!reset_enabled || only_accelerometer) { return; } - if (!IsMoving(0.5f) && accel.z <= -0.9f) { + if (!IsMoving(IsAtRestRelaxed) && accel.z <= -0.9f) { ++reset_counter; if (reset_counter > 900) { quat.w = 0; diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h index f5fd90db5..9180bb9aa 100644 --- a/src/core/hid/motion_input.h +++ b/src/core/hid/motion_input.h @@ -11,6 +11,15 @@ namespace Core::HID { class MotionInput { public: + static constexpr float ThresholdLoose = 0.01f; + static constexpr float ThresholdStandard = 0.007f; + static constexpr float ThresholdThight = 0.002f; + + static constexpr float IsAtRestRelaxed = 0.05f; + static constexpr float IsAtRestLoose = 0.02f; + static constexpr float IsAtRestStandard = 0.01f; + static constexpr float IsAtRestThight = 0.005f; + explicit MotionInput(); MotionInput(const MotionInput&) = default; @@ -26,6 +35,9 @@ public: void SetGyroBias(const Common::Vec3f& bias); void SetGyroThreshold(f32 threshold); + /// Applies a modifier on top of the normal gyro threshold + void SetUserGyroThreshold(f32 threshold); + void EnableReset(bool reset); void ResetRotations(); @@ -74,6 +86,9 @@ private: // Minimum gyro amplitude to detect if the device is moving f32 gyro_threshold = 0.0f; + // Multiplies gyro_threshold by this value + f32 user_gyro_threshold = 0.0f; + // Number of invalid sequential data u32 reset_counter = 0; diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index a86bec252..38d6cfaff 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -148,7 +148,7 @@ public: if (context->GetManager()->IsDomain()) { context->AddDomainObject(std::move(iface)); } else { - kernel.CurrentProcess()->GetResourceLimit()->Reserve( + kernel.ApplicationProcess()->GetResourceLimit()->Reserve( Kernel::LimitableResource::SessionCountMax, 1); auto* session = Kernel::KSession::Create(kernel); diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 738b6d0f1..494151eef 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -11,6 +11,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/scratch_buffer.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_auto_object.h" @@ -325,7 +326,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa return ResultSuccess; } -std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { +std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) const { const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && BufferDescriptorA()[buffer_index].Size()}; if (is_buffer_a) { @@ -345,6 +346,33 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { } } +std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { + static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a; + static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x; + + const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && + BufferDescriptorA()[buffer_index].Size()}; + if (is_buffer_a) { + ASSERT_OR_EXECUTE_MSG( + BufferDescriptorA().size() > buffer_index, { return {}; }, + "BufferDescriptorA invalid buffer_index {}", buffer_index); + auto& read_buffer = read_buffer_a[buffer_index]; + read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size()); + memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(), + read_buffer.size()); + return read_buffer; + } else { + ASSERT_OR_EXECUTE_MSG( + BufferDescriptorX().size() > buffer_index, { return {}; }, + "BufferDescriptorX invalid buffer_index {}", buffer_index); + auto& read_buffer = read_buffer_x[buffer_index]; + read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size()); + memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(), + read_buffer.size()); + return read_buffer; + } +} + std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, std::size_t buffer_index) const { if (size == 0) { diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index e252b5f4b..5bf4f171b 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -7,6 +7,7 @@ #include <functional> #include <memory> #include <optional> +#include <span> #include <string> #include <type_traits> #include <vector> @@ -270,8 +271,11 @@ public: return domain_message_header.has_value(); } - /// Helper function to read a buffer using the appropriate buffer descriptor - [[nodiscard]] std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const; + /// Helper function to get a span of a buffer using the appropriate buffer descriptor + [[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const; + + /// Helper function to read a copy of a buffer using the appropriate buffer descriptor + [[nodiscard]] std::vector<u8> ReadBufferCopy(std::size_t buffer_index = 0) const; /// Helper function to write a buffer using the appropriate buffer descriptor std::size_t WriteBuffer(const void* buffer, std::size_t size, diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 7b363eb1e..abdb5639f 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -11,10 +11,12 @@ #include "core/hle/kernel/init/init_slab_setup.h" #include "core/hle/kernel/k_code_memory.h" #include "core/hle/kernel/k_debug.h" +#include "core/hle/kernel/k_device_address_space.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event_info.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_object_name.h" #include "core/hle/kernel/k_page_buffer.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_process.h" @@ -43,10 +45,12 @@ namespace Kernel::Init { HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \ HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \ + HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__) \ HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ HANDLER(KThreadLocalPage, \ (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \ ##__VA_ARGS__) \ + HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ##__VA_ARGS__) \ HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \ HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 2827763d5..e8118c2b8 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -24,9 +24,7 @@ private: friend class ::Kernel::KClassTokenGenerator; \ static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \ static constexpr inline const char* const TypeName = #CLASS; \ - static constexpr inline ClassTokenType ClassToken() { \ - return ::Kernel::ClassToken<CLASS>; \ - } \ + static constexpr inline ClassTokenType ClassToken() { return ::Kernel::ClassToken<CLASS>; } \ \ public: \ YUZU_NON_COPYABLE(CLASS); \ @@ -37,15 +35,9 @@ public: constexpr ClassTokenType Token = ClassToken(); \ return TypeObj(TypeName, Token); \ } \ - static constexpr const char* GetStaticTypeName() { \ - return TypeName; \ - } \ - virtual TypeObj GetTypeObj() ATTRIBUTE { \ - return GetStaticTypeObj(); \ - } \ - virtual const char* GetTypeName() ATTRIBUTE { \ - return GetStaticTypeName(); \ - } \ + static constexpr const char* GetStaticTypeName() { return TypeName; } \ + virtual TypeObj GetTypeObj() ATTRIBUTE { return GetStaticTypeObj(); } \ + virtual const char* GetTypeName() ATTRIBUTE { return GetStaticTypeName(); } \ \ private: \ constexpr bool operator!=(const TypeObj& rhs) @@ -245,8 +237,8 @@ public: } template <typename U> - requires(std::derived_from<T, U> || - std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) { + requires(std::derived_from<T, U> || std::derived_from<U, T>) + constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) { if constexpr (std::derived_from<U, T>) { // Upcast. m_obj = rhs.m_obj; diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp new file mode 100644 index 000000000..2907cc6e3 --- /dev/null +++ b/src/core/hle/kernel/k_capabilities.cpp @@ -0,0 +1,358 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hardware_properties.h" +#include "core/hle/kernel/k_capabilities.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/kernel/svc_version.h" + +namespace Kernel { + +Result KCapabilities::InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table) { + // We're initializing an initial process. + m_svc_access_flags.reset(); + m_irq_access_flags.reset(); + m_debug_capabilities = 0; + m_handle_table_size = 0; + m_intended_kernel_version = 0; + m_program_type = 0; + + // Initial processes may run on all cores. + constexpr u64 VirtMask = Core::Hardware::VirtualCoreMask; + constexpr u64 PhysMask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(VirtMask); + + m_core_mask = VirtMask; + m_phys_core_mask = PhysMask; + + // Initial processes may use any user priority they like. + m_priority_mask = ~0xFULL; + + // Here, Nintendo sets the kernel version to the current kernel version. + // We will follow suit and set the version to the highest supported kernel version. + KernelVersion intended_kernel_version{}; + intended_kernel_version.major_version.Assign(Svc::SupportedKernelMajorVersion); + intended_kernel_version.minor_version.Assign(Svc::SupportedKernelMinorVersion); + m_intended_kernel_version = intended_kernel_version.raw; + + // Parse the capabilities array. + R_RETURN(this->SetCapabilities(kern_caps, page_table)); +} + +Result KCapabilities::InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table) { + // We're initializing a user process. + m_svc_access_flags.reset(); + m_irq_access_flags.reset(); + m_debug_capabilities = 0; + m_handle_table_size = 0; + m_intended_kernel_version = 0; + m_program_type = 0; + + // User processes must specify what cores/priorities they can use. + m_core_mask = 0; + m_priority_mask = 0; + + // Parse the user capabilities array. + R_RETURN(this->SetCapabilities(user_caps, page_table)); +} + +Result KCapabilities::SetCorePriorityCapability(const u32 cap) { + // We can't set core/priority if we've already set them. + R_UNLESS(m_core_mask == 0, ResultInvalidArgument); + R_UNLESS(m_priority_mask == 0, ResultInvalidArgument); + + // Validate the core/priority. + CorePriority pack{cap}; + const u32 min_core = pack.minimum_core_id; + const u32 max_core = pack.maximum_core_id; + const u32 max_prio = pack.lowest_thread_priority; + const u32 min_prio = pack.highest_thread_priority; + + R_UNLESS(min_core <= max_core, ResultInvalidCombination); + R_UNLESS(min_prio <= max_prio, ResultInvalidCombination); + R_UNLESS(max_core < Core::Hardware::NumVirtualCores, ResultInvalidCoreId); + + ASSERT(max_prio < Common::BitSize<u64>()); + + // Set core mask. + for (auto core_id = min_core; core_id <= max_core; core_id++) { + m_core_mask |= (1ULL << core_id); + } + ASSERT((m_core_mask & Core::Hardware::VirtualCoreMask) == m_core_mask); + + // Set physical core mask. + m_phys_core_mask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(m_core_mask); + + // Set priority mask. + for (auto prio = min_prio; prio <= max_prio; prio++) { + m_priority_mask |= (1ULL << prio); + } + + // We must have some core/priority we can use. + R_UNLESS(m_core_mask != 0, ResultInvalidArgument); + R_UNLESS(m_priority_mask != 0, ResultInvalidArgument); + + // Processes must not have access to kernel thread priorities. + R_UNLESS((m_priority_mask & 0xF) == 0, ResultInvalidArgument); + + R_SUCCEED(); +} + +Result KCapabilities::SetSyscallMaskCapability(const u32 cap, u32& set_svc) { + // Validate the index. + SyscallMask pack{cap}; + const u32 mask = pack.mask; + const u32 index = pack.index; + + const u32 index_flag = (1U << index); + R_UNLESS((set_svc & index_flag) == 0, ResultInvalidCombination); + set_svc |= index_flag; + + // Set SVCs. + for (size_t i = 0; i < decltype(SyscallMask::mask)::bits; i++) { + const u32 svc_id = static_cast<u32>(decltype(SyscallMask::mask)::bits * index + i); + if (mask & (1U << i)) { + R_UNLESS(this->SetSvcAllowed(svc_id), ResultOutOfRange); + } + } + + R_SUCCEED(); +} + +Result KCapabilities::MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table) { + const auto range_pack = MapRange{cap}; + const auto size_pack = MapRangeSize{size_cap}; + + // Get/validate address/size + const u64 phys_addr = range_pack.address.Value() * PageSize; + + // Validate reserved bits are unused. + R_UNLESS(size_pack.reserved.Value() == 0, ResultOutOfRange); + + const size_t num_pages = size_pack.pages; + const size_t size = num_pages * PageSize; + R_UNLESS(num_pages != 0, ResultInvalidSize); + R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress); + R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress); + + // Do the mapping. + [[maybe_unused]] const KMemoryPermission perm = range_pack.read_only.Value() + ? KMemoryPermission::UserRead + : KMemoryPermission::UserReadWrite; + if (MapRangeSize{size_cap}.normal) { + // R_RETURN(page_table->MapStatic(phys_addr, size, perm)); + } else { + // R_RETURN(page_table->MapIo(phys_addr, size, perm)); + } + + UNIMPLEMENTED(); + R_SUCCEED(); +} + +Result KCapabilities::MapIoPage_(const u32 cap, KPageTable* page_table) { + // Get/validate address/size + const u64 phys_addr = MapIoPage{cap}.address.Value() * PageSize; + const size_t num_pages = 1; + const size_t size = num_pages * PageSize; + R_UNLESS(num_pages != 0, ResultInvalidSize); + R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress); + R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress); + + // Do the mapping. + // R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite)); + + UNIMPLEMENTED(); + R_SUCCEED(); +} + +template <typename F> +Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) { + // Define the allowed memory regions. + constexpr std::array<KMemoryRegionType, 4> MemoryRegions{ + KMemoryRegionType_None, + KMemoryRegionType_KernelTraceBuffer, + KMemoryRegionType_OnMemoryBootImage, + KMemoryRegionType_DTB, + }; + + // Extract regions/read only. + const MapRegion pack{cap}; + const std::array<RegionType, 3> types{pack.region0, pack.region1, pack.region2}; + const std::array<u32, 3> ro{pack.read_only0, pack.read_only1, pack.read_only2}; + + for (size_t i = 0; i < types.size(); i++) { + const auto type = types[i]; + const auto perm = ro[i] ? KMemoryPermission::UserRead : KMemoryPermission::UserReadWrite; + switch (type) { + case RegionType::NoMapping: + break; + case RegionType::KernelTraceBuffer: + case RegionType::OnMemoryBootImage: + case RegionType::DTB: + R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm)); + break; + default: + R_THROW(ResultNotFound); + } + } + + R_SUCCEED(); +} + +Result KCapabilities::MapRegion_(const u32 cap, KPageTable* page_table) { + // Map each region into the process's page table. + return ProcessMapRegionCapability( + cap, [](KMemoryRegionType region_type, KMemoryPermission perm) -> Result { + // R_RETURN(page_table->MapRegion(region_type, perm)); + UNIMPLEMENTED(); + R_SUCCEED(); + }); +} + +Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) { + // Check that each region has a physical backing store. + return ProcessMapRegionCapability( + cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result { + R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived( + region_type) != nullptr, + ResultOutOfRange); + R_SUCCEED(); + }); +} + +Result KCapabilities::SetInterruptPairCapability(const u32 cap) { + // Extract interrupts. + const InterruptPair pack{cap}; + const std::array<u32, 2> ids{pack.interrupt_id0, pack.interrupt_id1}; + + for (size_t i = 0; i < ids.size(); i++) { + if (ids[i] != PaddingInterruptId) { + UNIMPLEMENTED(); + // R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(ids[i]), ResultOutOfRange); + // R_UNLESS(this->SetInterruptPermitted(ids[i]), ResultOutOfRange); + } + } + + R_SUCCEED(); +} + +Result KCapabilities::SetProgramTypeCapability(const u32 cap) { + // Validate. + const ProgramType pack{cap}; + R_UNLESS(pack.reserved == 0, ResultReservedUsed); + + m_program_type = pack.type; + R_SUCCEED(); +} + +Result KCapabilities::SetKernelVersionCapability(const u32 cap) { + // Ensure we haven't set our version before. + R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version == 0, ResultInvalidArgument); + + // Set, ensure that we set a valid version. + m_intended_kernel_version = cap; + R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version != 0, ResultInvalidArgument); + + R_SUCCEED(); +} + +Result KCapabilities::SetHandleTableCapability(const u32 cap) { + // Validate. + const HandleTable pack{cap}; + R_UNLESS(pack.reserved == 0, ResultReservedUsed); + + m_handle_table_size = pack.size; + R_SUCCEED(); +} + +Result KCapabilities::SetDebugFlagsCapability(const u32 cap) { + // Validate. + const DebugFlags pack{cap}; + R_UNLESS(pack.reserved == 0, ResultReservedUsed); + + DebugFlags debug_capabilities{m_debug_capabilities}; + debug_capabilities.allow_debug.Assign(pack.allow_debug); + debug_capabilities.force_debug.Assign(pack.force_debug); + m_debug_capabilities = debug_capabilities.raw; + + R_SUCCEED(); +} + +Result KCapabilities::SetCapability(const u32 cap, u32& set_flags, u32& set_svc, + KPageTable* page_table) { + // Validate this is a capability we can act on. + const auto type = GetCapabilityType(cap); + R_UNLESS(type != CapabilityType::Invalid, ResultInvalidArgument); + + // If the type is padding, we have no work to do. + R_SUCCEED_IF(type == CapabilityType::Padding); + + // Check that we haven't already processed this capability. + const auto flag = GetCapabilityFlag(type); + R_UNLESS(((set_flags & InitializeOnceFlags) & flag) == 0, ResultInvalidCombination); + set_flags |= flag; + + // Process the capability. + switch (type) { + case CapabilityType::CorePriority: + R_RETURN(this->SetCorePriorityCapability(cap)); + case CapabilityType::SyscallMask: + R_RETURN(this->SetSyscallMaskCapability(cap, set_svc)); + case CapabilityType::MapIoPage: + R_RETURN(this->MapIoPage_(cap, page_table)); + case CapabilityType::MapRegion: + R_RETURN(this->MapRegion_(cap, page_table)); + case CapabilityType::InterruptPair: + R_RETURN(this->SetInterruptPairCapability(cap)); + case CapabilityType::ProgramType: + R_RETURN(this->SetProgramTypeCapability(cap)); + case CapabilityType::KernelVersion: + R_RETURN(this->SetKernelVersionCapability(cap)); + case CapabilityType::HandleTable: + R_RETURN(this->SetHandleTableCapability(cap)); + case CapabilityType::DebugFlags: + R_RETURN(this->SetDebugFlagsCapability(cap)); + default: + R_THROW(ResultInvalidArgument); + } +} + +Result KCapabilities::SetCapabilities(std::span<const u32> caps, KPageTable* page_table) { + u32 set_flags = 0, set_svc = 0; + + for (size_t i = 0; i < caps.size(); i++) { + const u32 cap{caps[i]}; + + if (GetCapabilityType(cap) == CapabilityType::MapRange) { + // Check that the pair cap exists. + R_UNLESS((++i) < caps.size(), ResultInvalidCombination); + + // Check the pair cap is a map range cap. + const u32 size_cap{caps[i]}; + R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange, + ResultInvalidCombination); + + // Map the range. + R_TRY(this->MapRange_(cap, size_cap, page_table)); + } else { + R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); + } + } + + R_SUCCEED(); +} + +Result KCapabilities::CheckCapabilities(KernelCore& kernel, std::span<const u32> caps) { + for (auto cap : caps) { + // Check the capability refers to a valid region. + if (GetCapabilityType(cap) == CapabilityType::MapRegion) { + R_TRY(CheckMapRegion(kernel, cap)); + } + } + + R_SUCCEED(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_capabilities.h b/src/core/hle/kernel/k_capabilities.h new file mode 100644 index 000000000..cd96f8d23 --- /dev/null +++ b/src/core/hle/kernel/k_capabilities.h @@ -0,0 +1,295 @@ + +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <bitset> +#include <span> + +#include "common/bit_field.h" +#include "common/common_types.h" + +#include "core/hle/kernel/svc_types.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KPageTable; +class KernelCore; + +class KCapabilities { +public: + constexpr explicit KCapabilities() = default; + + Result InitializeForKIP(std::span<const u32> kern_caps, KPageTable* page_table); + Result InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table); + + static Result CheckCapabilities(KernelCore& kernel, std::span<const u32> user_caps); + + constexpr u64 GetCoreMask() const { + return m_core_mask; + } + + constexpr u64 GetPhysicalCoreMask() const { + return m_phys_core_mask; + } + + constexpr u64 GetPriorityMask() const { + return m_priority_mask; + } + + constexpr s32 GetHandleTableSize() const { + return m_handle_table_size; + } + + constexpr const Svc::SvcAccessFlagSet& GetSvcPermissions() const { + return m_svc_access_flags; + } + + constexpr bool IsPermittedSvc(u32 id) const { + return (id < m_svc_access_flags.size()) && m_svc_access_flags[id]; + } + + constexpr bool IsPermittedInterrupt(u32 id) const { + return (id < m_irq_access_flags.size()) && m_irq_access_flags[id]; + } + + constexpr bool IsPermittedDebug() const { + return DebugFlags{m_debug_capabilities}.allow_debug.Value() != 0; + } + + constexpr bool CanForceDebug() const { + return DebugFlags{m_debug_capabilities}.force_debug.Value() != 0; + } + + constexpr u32 GetIntendedKernelMajorVersion() const { + return KernelVersion{m_intended_kernel_version}.major_version; + } + + constexpr u32 GetIntendedKernelMinorVersion() const { + return KernelVersion{m_intended_kernel_version}.minor_version; + } + +private: + static constexpr size_t InterruptIdCount = 0x400; + using InterruptFlagSet = std::bitset<InterruptIdCount>; + + enum class CapabilityType : u32 { + CorePriority = (1U << 3) - 1, + SyscallMask = (1U << 4) - 1, + MapRange = (1U << 6) - 1, + MapIoPage = (1U << 7) - 1, + MapRegion = (1U << 10) - 1, + InterruptPair = (1U << 11) - 1, + ProgramType = (1U << 13) - 1, + KernelVersion = (1U << 14) - 1, + HandleTable = (1U << 15) - 1, + DebugFlags = (1U << 16) - 1, + + Invalid = 0U, + Padding = ~0U, + }; + + using RawCapabilityValue = u32; + + static constexpr CapabilityType GetCapabilityType(const RawCapabilityValue value) { + return static_cast<CapabilityType>((~value & (value + 1)) - 1); + } + + static constexpr u32 GetCapabilityFlag(CapabilityType type) { + return static_cast<u32>(type) + 1; + } + + template <CapabilityType Type> + static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1; + + template <CapabilityType Type> + static constexpr inline u32 CapabilityId = std::countr_zero(CapabilityFlag<Type>); + + union CorePriority { + static_assert(CapabilityId<CapabilityType::CorePriority> + 1 == 4); + + RawCapabilityValue raw; + BitField<0, 4, CapabilityType> id; + BitField<4, 6, u32> lowest_thread_priority; + BitField<10, 6, u32> highest_thread_priority; + BitField<16, 8, u32> minimum_core_id; + BitField<24, 8, u32> maximum_core_id; + }; + + union SyscallMask { + static_assert(CapabilityId<CapabilityType::SyscallMask> + 1 == 5); + + RawCapabilityValue raw; + BitField<0, 5, CapabilityType> id; + BitField<5, 24, u32> mask; + BitField<29, 3, u32> index; + }; + + // #undef MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES + static constexpr u64 PhysicalMapAllowedMask = (1ULL << 36) - 1; + + union MapRange { + static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7); + + RawCapabilityValue raw; + BitField<0, 7, CapabilityType> id; + BitField<7, 24, u32> address; + BitField<31, 1, u32> read_only; + }; + + union MapRangeSize { + static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7); + + RawCapabilityValue raw; + BitField<0, 7, CapabilityType> id; + BitField<7, 20, u32> pages; + BitField<27, 4, u32> reserved; + BitField<31, 1, u32> normal; + }; + + union MapIoPage { + static_assert(CapabilityId<CapabilityType::MapIoPage> + 1 == 8); + + RawCapabilityValue raw; + BitField<0, 8, CapabilityType> id; + BitField<8, 24, u32> address; + }; + + enum class RegionType : u32 { + NoMapping = 0, + KernelTraceBuffer = 1, + OnMemoryBootImage = 2, + DTB = 3, + }; + + union MapRegion { + static_assert(CapabilityId<CapabilityType::MapRegion> + 1 == 11); + + RawCapabilityValue raw; + BitField<0, 11, CapabilityType> id; + BitField<11, 6, RegionType> region0; + BitField<17, 1, u32> read_only0; + BitField<18, 6, RegionType> region1; + BitField<24, 1, u32> read_only1; + BitField<25, 6, RegionType> region2; + BitField<31, 1, u32> read_only2; + }; + + union InterruptPair { + static_assert(CapabilityId<CapabilityType::InterruptPair> + 1 == 12); + + RawCapabilityValue raw; + BitField<0, 12, CapabilityType> id; + BitField<12, 10, u32> interrupt_id0; + BitField<22, 10, u32> interrupt_id1; + }; + + union ProgramType { + static_assert(CapabilityId<CapabilityType::ProgramType> + 1 == 14); + + RawCapabilityValue raw; + BitField<0, 14, CapabilityType> id; + BitField<14, 3, u32> type; + BitField<17, 15, u32> reserved; + }; + + union KernelVersion { + static_assert(CapabilityId<CapabilityType::KernelVersion> + 1 == 15); + + RawCapabilityValue raw; + BitField<0, 15, CapabilityType> id; + BitField<15, 4, u32> major_version; + BitField<19, 13, u32> minor_version; + }; + + union HandleTable { + static_assert(CapabilityId<CapabilityType::HandleTable> + 1 == 16); + + RawCapabilityValue raw; + BitField<0, 16, CapabilityType> id; + BitField<16, 10, u32> size; + BitField<26, 6, u32> reserved; + }; + + union DebugFlags { + static_assert(CapabilityId<CapabilityType::DebugFlags> + 1 == 17); + + RawCapabilityValue raw; + BitField<0, 17, CapabilityType> id; + BitField<17, 1, u32> allow_debug; + BitField<18, 1, u32> force_debug; + BitField<19, 13, u32> reserved; + }; + + static_assert(sizeof(CorePriority) == 4); + static_assert(sizeof(SyscallMask) == 4); + static_assert(sizeof(MapRange) == 4); + static_assert(sizeof(MapRangeSize) == 4); + static_assert(sizeof(MapIoPage) == 4); + static_assert(sizeof(MapRegion) == 4); + static_assert(sizeof(InterruptPair) == 4); + static_assert(sizeof(ProgramType) == 4); + static_assert(sizeof(KernelVersion) == 4); + static_assert(sizeof(HandleTable) == 4); + static_assert(sizeof(DebugFlags) == 4); + + static constexpr u32 InitializeOnceFlags = + CapabilityFlag<CapabilityType::CorePriority> | CapabilityFlag<CapabilityType::ProgramType> | + CapabilityFlag<CapabilityType::KernelVersion> | + CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::DebugFlags>; + + static const u32 PaddingInterruptId = 0x3FF; + static_assert(PaddingInterruptId < InterruptIdCount); + +private: + constexpr bool SetSvcAllowed(u32 id) { + if (id < m_svc_access_flags.size()) [[likely]] { + m_svc_access_flags[id] = true; + return true; + } else { + return false; + } + } + + constexpr bool SetInterruptPermitted(u32 id) { + if (id < m_irq_access_flags.size()) [[likely]] { + m_irq_access_flags[id] = true; + return true; + } else { + return false; + } + } + + Result SetCorePriorityCapability(const u32 cap); + Result SetSyscallMaskCapability(const u32 cap, u32& set_svc); + Result MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table); + Result MapIoPage_(const u32 cap, KPageTable* page_table); + Result MapRegion_(const u32 cap, KPageTable* page_table); + Result SetInterruptPairCapability(const u32 cap); + Result SetProgramTypeCapability(const u32 cap); + Result SetKernelVersionCapability(const u32 cap); + Result SetHandleTableCapability(const u32 cap); + Result SetDebugFlagsCapability(const u32 cap); + + template <typename F> + static Result ProcessMapRegionCapability(const u32 cap, F f); + static Result CheckMapRegion(KernelCore& kernel, const u32 cap); + + Result SetCapability(const u32 cap, u32& set_flags, u32& set_svc, KPageTable* page_table); + Result SetCapabilities(std::span<const u32> caps, KPageTable* page_table); + +private: + Svc::SvcAccessFlagSet m_svc_access_flags{}; + InterruptFlagSet m_irq_access_flags{}; + u64 m_core_mask{}; + u64 m_phys_core_mask{}; + u64 m_priority_mask{}; + u32 m_debug_capabilities{}; + s32 m_handle_table_size{}; + u32 m_intended_kernel_version{}; + u32 m_program_type{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 2ec623a58..c72a91a76 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -60,7 +60,8 @@ bool KClientPort::IsSignaled() const { Result KClientPort::CreateSession(KClientSession** out) { // Reserve a new session from the resource limit. - KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), + //! FIXME: we are reserving this from the wrong resource limit! + KScopedResourceReservation session_reservation(kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax); R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index 4b1c134d4..6c44a9e99 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -21,19 +21,19 @@ KCodeMemory::KCodeMemory(KernelCore& kernel_) Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) { // Set members. - m_owner = kernel.CurrentProcess(); + m_owner = GetCurrentProcessPointer(kernel); // Get the owner page table. auto& page_table = m_owner->PageTable(); // Construct the page group. - m_page_group = {}; + m_page_group.emplace(kernel, page_table.GetBlockInfoManager()); // Lock the memory. - R_TRY(page_table.LockForCodeMemory(&m_page_group, addr, size)) + R_TRY(page_table.LockForCodeMemory(std::addressof(*m_page_group), addr, size)) // Clear the memory. - for (const auto& block : m_page_group.Nodes()) { + for (const auto& block : *m_page_group) { std::memset(device_memory.GetPointer<void>(block.GetAddress()), 0xFF, block.GetSize()); } @@ -51,12 +51,13 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si void KCodeMemory::Finalize() { // Unlock. if (!m_is_mapped && !m_is_owner_mapped) { - const size_t size = m_page_group.GetNumPages() * PageSize; - m_owner->PageTable().UnlockForCodeMemory(m_address, size, m_page_group); + const size_t size = m_page_group->GetNumPages() * PageSize; + m_owner->PageTable().UnlockForCodeMemory(m_address, size, *m_page_group); } // Close the page group. - m_page_group = {}; + m_page_group->Close(); + m_page_group->Finalize(); // Close our reference to our owner. m_owner->Close(); @@ -64,7 +65,7 @@ void KCodeMemory::Finalize() { Result KCodeMemory::Map(VAddr address, size_t size) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); @@ -73,8 +74,8 @@ Result KCodeMemory::Map(VAddr address, size_t size) { R_UNLESS(!m_is_mapped, ResultInvalidState); // Map the memory. - R_TRY(kernel.CurrentProcess()->PageTable().MapPages( - address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); + R_TRY(GetCurrentProcess(kernel).PageTable().MapPageGroup( + address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); // Mark ourselves as mapped. m_is_mapped = true; @@ -84,14 +85,14 @@ Result KCodeMemory::Map(VAddr address, size_t size) { Result KCodeMemory::Unmap(VAddr address, size_t size) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); // Unmap the memory. - R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group, - KMemoryState::CodeOut)); + R_TRY(GetCurrentProcess(kernel).PageTable().UnmapPageGroup(address, *m_page_group, + KMemoryState::CodeOut)); // Mark ourselves as unmapped. m_is_mapped = false; @@ -101,7 +102,7 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) { Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); @@ -124,8 +125,8 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission } // Map the memory. - R_TRY( - m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm)); + R_TRY(m_owner->PageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode, + k_perm)); // Mark ourselves as mapped. m_is_owner_mapped = true; @@ -135,13 +136,13 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) { // Validate the size. - R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); + R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); // Lock ourselves. KScopedLightLock lk(m_lock); // Unmap the memory. - R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode)); + R_TRY(m_owner->PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode)); // Mark ourselves as unmapped. m_is_owner_mapped = false; diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h index 2e7e1436a..5b260b385 100644 --- a/src/core/hle/kernel/k_code_memory.h +++ b/src/core/hle/kernel/k_code_memory.h @@ -3,6 +3,8 @@ #pragma once +#include <optional> + #include "common/common_types.h" #include "core/device_memory.h" #include "core/hle/kernel/k_auto_object.h" @@ -49,11 +51,11 @@ public: return m_address; } size_t GetSize() const { - return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0; + return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0; } private: - KPageGroup m_page_group{}; + std::optional<KPageGroup> m_page_group{}; KProcess* m_owner{}; VAddr m_address{}; KLightLock m_lock; diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 124149697..3f0be1c3f 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -164,14 +164,14 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask)); // Get the lock owner thread. - owner_thread = kernel.CurrentProcess() - ->GetHandleTable() + owner_thread = GetCurrentProcess(kernel) + .GetHandleTable() .GetObjectWithoutPseudoHandle<KThread>(handle) .ReleasePointerUnsafe(); R_UNLESS(owner_thread != nullptr, ResultInvalidHandle); // Update the lock. - cur_thread->SetAddressKey(addr, value); + cur_thread->SetUserAddressKey(addr, value); owner_thread->AddWaiter(cur_thread); // Begin waiting. @@ -213,8 +213,8 @@ void KConditionVariable::SignalImpl(KThread* thread) { thread->EndWait(ResultSuccess); } else { // Get the previous owner. - KThread* owner_thread = kernel.CurrentProcess() - ->GetHandleTable() + KThread* owner_thread = GetCurrentProcess(kernel) + .GetHandleTable() .GetObjectWithoutPseudoHandle<KThread>( static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask)) .ReleasePointerUnsafe(); diff --git a/src/core/hle/kernel/k_device_address_space.cpp b/src/core/hle/kernel/k_device_address_space.cpp new file mode 100644 index 000000000..27659ea3b --- /dev/null +++ b/src/core/hle/kernel/k_device_address_space.cpp @@ -0,0 +1,150 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "core/core.h" +#include "core/hle/kernel/k_device_address_space.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel_) + : KAutoObjectWithSlabHeapAndContainer(kernel_), m_lock(kernel_), m_is_initialized(false) {} +KDeviceAddressSpace::~KDeviceAddressSpace() = default; + +void KDeviceAddressSpace::Initialize() { + // This just forwards to the device page table manager. + // KDevicePageTable::Initialize(); +} + +// Member functions. +Result KDeviceAddressSpace::Initialize(u64 address, u64 size) { + // Initialize the device page table. + // R_TRY(m_table.Initialize(address, size)); + + // Set member variables. + m_space_address = address; + m_space_size = size; + m_is_initialized = true; + + R_SUCCEED(); +} + +void KDeviceAddressSpace::Finalize() { + // Finalize the table. + // m_table.Finalize(); +} + +Result KDeviceAddressSpace::Attach(Svc::DeviceName device_name) { + // Lock the address space. + KScopedLightLock lk(m_lock); + + // Attach. + // R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size)); + R_SUCCEED(); +} + +Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) { + // Lock the address space. + KScopedLightLock lk(m_lock); + + // Detach. + // R_RETURN(m_table.Detach(device_name)); + R_SUCCEED(); +} + +Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, size_t size, + u64 device_address, u32 option, bool is_aligned) { + // Check that the address falls within the space. + R_UNLESS((m_space_address <= device_address && + device_address + size - 1 <= m_space_address + m_space_size - 1), + ResultInvalidCurrentMemory); + + // Decode the option. + const Svc::MapDeviceAddressSpaceOption option_pack{option}; + const auto device_perm = option_pack.permission.Value(); + const auto flags = option_pack.flags.Value(); + const auto reserved = option_pack.reserved.Value(); + + // Validate the option. + // TODO: It is likely that this check for flags == none is only on NX board. + R_UNLESS(flags == Svc::MapDeviceAddressSpaceFlag::None, ResultInvalidEnumValue); + R_UNLESS(reserved == 0, ResultInvalidEnumValue); + + // Lock the address space. + KScopedLightLock lk(m_lock); + + // Lock the page table to prevent concurrent device mapping operations. + // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); + + // Lock the pages. + bool is_io{}; + R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size, + ConvertToKMemoryPermission(device_perm), + is_aligned, true)); + + // Ensure that if we fail, we don't keep unmapped pages locked. + ON_RESULT_FAILURE { + ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess); + }; + + // Check that the io status is allowable. + if (is_io) { + R_UNLESS(static_cast<u32>(flags & Svc::MapDeviceAddressSpaceFlag::NotIoRegister) == 0, + ResultInvalidCombination); + } + + // Map the pages. + { + // Perform the mapping. + // R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, + // is_aligned, is_io)); + + // Ensure that we unmap the pages if we fail to update the protections. + // NOTE: Nintendo does not check the result of this unmap call. + // ON_RESULT_FAILURE { m_table.Unmap(device_address, size); }; + + // Update the protections in accordance with how much we mapped. + // R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size)); + } + + // We succeeded. + R_SUCCEED(); +} + +Result KDeviceAddressSpace::Unmap(KPageTable* page_table, VAddr process_address, size_t size, + u64 device_address) { + // Check that the address falls within the space. + R_UNLESS((m_space_address <= device_address && + device_address + size - 1 <= m_space_address + m_space_size - 1), + ResultInvalidCurrentMemory); + + // Lock the address space. + KScopedLightLock lk(m_lock); + + // Lock the page table to prevent concurrent device mapping operations. + // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); + + // Lock the pages. + R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true)); + + // Unmap the pages. + { + // If we fail to unmap, we want to do a partial unlock. + // ON_RESULT_FAILURE { + // ASSERT(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size) == + // ResultSuccess); + // }; + + // Perform the unmap. + // R_TRY(m_table.Unmap(page_table, process_address, size, device_address)); + } + + // Unlock the pages. + ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess); + + R_SUCCEED(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_device_address_space.h b/src/core/hle/kernel/k_device_address_space.h new file mode 100644 index 000000000..4709df995 --- /dev/null +++ b/src/core/hle/kernel/k_device_address_space.h @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <string> + +#include "common/common_types.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KDeviceAddressSpace final + : public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject); + +public: + explicit KDeviceAddressSpace(KernelCore& kernel); + ~KDeviceAddressSpace(); + + Result Initialize(u64 address, u64 size); + void Finalize(); + + bool IsInitialized() const { + return m_is_initialized; + } + static void PostDestroy(uintptr_t arg) {} + + Result Attach(Svc::DeviceName device_name); + Result Detach(Svc::DeviceName device_name); + + Result MapByForce(KPageTable* page_table, VAddr process_address, size_t size, + u64 device_address, u32 option) { + R_RETURN(this->Map(page_table, process_address, size, device_address, option, false)); + } + + Result MapAligned(KPageTable* page_table, VAddr process_address, size_t size, + u64 device_address, u32 option) { + R_RETURN(this->Map(page_table, process_address, size, device_address, option, true)); + } + + Result Unmap(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address); + + static void Initialize(); + +private: + Result Map(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address, + u32 option, bool is_aligned); + +private: + KLightLock m_lock; + // KDevicePageTable m_table; + u64 m_space_address{}; + u64 m_space_size{}; + bool m_is_initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 37a24e7d9..d7660630c 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -90,7 +90,8 @@ public: // Handle pseudo-handles. if constexpr (std::derived_from<KProcess, T>) { if (handle == Svc::PseudoHandle::CurrentProcess) { - auto* const cur_process = m_kernel.CurrentProcess(); + //! FIXME: this is the wrong process! + auto* const cur_process = m_kernel.ApplicationProcess(); ASSERT(cur_process != nullptr); return cur_process; } diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp index 6bba79ea0..4dcd53821 100644 --- a/src/core/hle/kernel/k_hardware_timer.cpp +++ b/src/core/hle/kernel/k_hardware_timer.cpp @@ -18,7 +18,8 @@ void KHardwareTimer::Initialize() { } void KHardwareTimer::Finalize() { - this->DisableInterrupt(); + m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); + m_wakeup_time = std::numeric_limits<s64>::max(); m_event_type.reset(); } @@ -59,7 +60,8 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) { } void KHardwareTimer::DisableInterrupt() { - m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); + m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type, + reinterpret_cast<uintptr_t>(this)); m_wakeup_time = std::numeric_limits<s64>::max(); } diff --git a/src/core/hle/kernel/k_interrupt_manager.cpp b/src/core/hle/kernel/k_interrupt_manager.cpp index 4a6b60d26..fe6a20168 100644 --- a/src/core/hle/kernel/k_interrupt_manager.cpp +++ b/src/core/hle/kernel/k_interrupt_manager.cpp @@ -16,7 +16,7 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) { auto& current_thread = GetCurrentThread(kernel); - if (auto* process = kernel.CurrentProcess(); process) { + if (auto* process = GetCurrentProcessPointer(kernel); process) { // If the user disable count is set, we may need to pin the current thread. if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) { KScopedSchedulerLock sl{kernel}; diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 43185320d..d791acbe3 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -68,7 +68,7 @@ bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { // Add the current thread as a waiter on the owner. KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL); - cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); + cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); owner_thread->AddWaiter(cur_thread); // Begin waiting to hold the lock. diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h index fd6e1d3e6..17fa1a6ed 100644 --- a/src/core/hle/kernel/k_memory_layout.h +++ b/src/core/hle/kernel/k_memory_layout.h @@ -67,9 +67,9 @@ constexpr size_t KernelPageBufferAdditionalSize = 0x33C000; constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize + KernelPageBufferHeapSize; -constexpr bool IsKernelAddressKey(VAddr key) { - return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast; -} +//! NB: Use KThread::GetAddressKeyIsKernel(). +//! See explanation for deviation of GetAddressKey. +bool IsKernelAddressKey(VAddr key) = delete; constexpr bool IsKernelAddress(VAddr address) { return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index bd33571da..cd6ea388e 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -223,7 +223,7 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, // Ensure that we don't leave anything un-freed. ON_RESULT_FAILURE { - for (const auto& it : out->Nodes()) { + for (const auto& it : *out) { auto& manager = this->GetManager(it.GetAddress()); const size_t node_num_pages = std::min<u64>( it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); @@ -285,7 +285,7 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op m_has_optimized_process[static_cast<size_t>(pool)], true)); // Open the first reference to the pages. - for (const auto& block : out->Nodes()) { + for (const auto& block : *out) { PAddr cur_address = block.GetAddress(); size_t remaining_pages = block.GetNumPages(); while (remaining_pages > 0) { @@ -335,7 +335,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32 // Perform optimized memory tracking, if we should. if (optimized) { // Iterate over the allocated blocks. - for (const auto& block : out->Nodes()) { + for (const auto& block : *out) { // Get the block extents. const PAddr block_address = block.GetAddress(); const size_t block_pages = block.GetNumPages(); @@ -391,7 +391,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32 } } else { // Set all the allocated memory. - for (const auto& block : out->Nodes()) { + for (const auto& block : *out) { std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern, block.GetSize()); } diff --git a/src/core/hle/kernel/k_object_name.cpp b/src/core/hle/kernel/k_object_name.cpp new file mode 100644 index 000000000..df3a1c4c5 --- /dev/null +++ b/src/core/hle/kernel/k_object_name.cpp @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_object_name.h" + +namespace Kernel { + +KObjectNameGlobalData::KObjectNameGlobalData(KernelCore& kernel) : m_object_list_lock{kernel} {} +KObjectNameGlobalData::~KObjectNameGlobalData() = default; + +void KObjectName::Initialize(KAutoObject* obj, const char* name) { + // Set member variables. + m_object = obj; + std::strncpy(m_name.data(), name, sizeof(m_name) - 1); + m_name[sizeof(m_name) - 1] = '\x00'; + + // Open a reference to the object we hold. + m_object->Open(); +} + +bool KObjectName::MatchesName(const char* name) const { + return std::strncmp(m_name.data(), name, sizeof(m_name)) == 0; +} + +Result KObjectName::NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name) { + // Create a new object name. + KObjectName* new_name = KObjectName::Allocate(kernel); + R_UNLESS(new_name != nullptr, ResultOutOfResource); + + // Initialize the new name. + new_name->Initialize(obj, name); + + // Check if there's an existing name. + { + // Get the global data. + KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()}; + + // Ensure we have exclusive access to the global list. + KScopedLightLock lk{gd.GetObjectListLock()}; + + // If the object doesn't exist, put it into the list. + KScopedAutoObject existing_object = FindImpl(kernel, name); + if (existing_object.IsNull()) { + gd.GetObjectList().push_back(*new_name); + R_SUCCEED(); + } + } + + // The object already exists, which is an error condition. Perform cleanup. + obj->Close(); + KObjectName::Free(kernel, new_name); + R_THROW(ResultInvalidState); +} + +Result KObjectName::Delete(KernelCore& kernel, KAutoObject* obj, const char* compare_name) { + // Get the global data. + KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()}; + + // Ensure we have exclusive access to the global list. + KScopedLightLock lk{gd.GetObjectListLock()}; + + // Find a matching entry in the list, and delete it. + for (auto& name : gd.GetObjectList()) { + if (name.MatchesName(compare_name) && obj == name.GetObject()) { + // We found a match, clean up its resources. + obj->Close(); + gd.GetObjectList().erase(gd.GetObjectList().iterator_to(name)); + KObjectName::Free(kernel, std::addressof(name)); + R_SUCCEED(); + } + } + + // We didn't find the object in the list. + R_THROW(ResultNotFound); +} + +KScopedAutoObject<KAutoObject> KObjectName::Find(KernelCore& kernel, const char* name) { + // Get the global data. + KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()}; + + // Ensure we have exclusive access to the global list. + KScopedLightLock lk{gd.GetObjectListLock()}; + + return FindImpl(kernel, name); +} + +KScopedAutoObject<KAutoObject> KObjectName::FindImpl(KernelCore& kernel, const char* compare_name) { + // Get the global data. + KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()}; + + // Try to find a matching object in the global list. + for (const auto& name : gd.GetObjectList()) { + if (name.MatchesName(compare_name)) { + return name.GetObject(); + } + } + + // There's no matching entry in the list. + return nullptr; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_object_name.h b/src/core/hle/kernel/k_object_name.h new file mode 100644 index 000000000..b7f943134 --- /dev/null +++ b/src/core/hle/kernel/k_object_name.h @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> +#include <memory> +#include <boost/intrusive/list.hpp> + +#include "core/hle/kernel/k_light_lock.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +class KObjectNameGlobalData; + +class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> { +public: + explicit KObjectName(KernelCore&) {} + virtual ~KObjectName() = default; + + static constexpr size_t NameLengthMax = 12; + using List = boost::intrusive::list<KObjectName>; + + static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name); + static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name); + + static KScopedAutoObject<KAutoObject> Find(KernelCore& kernel, const char* name); + + template <typename Derived> + static Result Delete(KernelCore& kernel, const char* name) { + // Find the object. + KScopedAutoObject obj = Find(kernel, name); + R_UNLESS(obj.IsNotNull(), ResultNotFound); + + // Cast the object to the desired type. + Derived* derived = obj->DynamicCast<Derived*>(); + R_UNLESS(derived != nullptr, ResultNotFound); + + // Check that the object is closed. + R_UNLESS(derived->IsServerClosed(), ResultInvalidState); + + return Delete(kernel, obj.GetPointerUnsafe(), name); + } + + template <typename Derived> + requires(std::derived_from<Derived, KAutoObject>) + static KScopedAutoObject<Derived> Find(KernelCore& kernel, const char* name) { + return Find(kernel, name); + } + +private: + static KScopedAutoObject<KAutoObject> FindImpl(KernelCore& kernel, const char* name); + + void Initialize(KAutoObject* obj, const char* name); + + bool MatchesName(const char* name) const; + KAutoObject* GetObject() const { + return m_object; + } + +private: + std::array<char, NameLengthMax> m_name{}; + KAutoObject* m_object{}; +}; + +class KObjectNameGlobalData { +public: + explicit KObjectNameGlobalData(KernelCore& kernel); + ~KObjectNameGlobalData(); + + KLightLock& GetObjectListLock() { + return m_object_list_lock; + } + + KObjectName::List& GetObjectList() { + return m_object_list; + } + +private: + KLightLock m_object_list_lock; + KObjectName::List m_object_list; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_page_group.cpp b/src/core/hle/kernel/k_page_group.cpp new file mode 100644 index 000000000..d8c644a33 --- /dev/null +++ b/src/core/hle/kernel/k_page_group.cpp @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_dynamic_resource_manager.h" +#include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_page_group.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +void KPageGroup::Finalize() { + KBlockInfo* cur = m_first_block; + while (cur != nullptr) { + KBlockInfo* next = cur->GetNext(); + m_manager->Free(cur); + cur = next; + } + + m_first_block = nullptr; + m_last_block = nullptr; +} + +void KPageGroup::CloseAndReset() { + auto& mm = m_kernel.MemoryManager(); + + KBlockInfo* cur = m_first_block; + while (cur != nullptr) { + KBlockInfo* next = cur->GetNext(); + mm.Close(cur->GetAddress(), cur->GetNumPages()); + m_manager->Free(cur); + cur = next; + } + + m_first_block = nullptr; + m_last_block = nullptr; +} + +size_t KPageGroup::GetNumPages() const { + size_t num_pages = 0; + + for (const auto& it : *this) { + num_pages += it.GetNumPages(); + } + + return num_pages; +} + +Result KPageGroup::AddBlock(KPhysicalAddress addr, size_t num_pages) { + // Succeed immediately if we're adding no pages. + R_SUCCEED_IF(num_pages == 0); + + // Check for overflow. + ASSERT(addr < addr + num_pages * PageSize); + + // Try to just append to the last block. + if (m_last_block != nullptr) { + R_SUCCEED_IF(m_last_block->TryConcatenate(addr, num_pages)); + } + + // Allocate a new block. + KBlockInfo* new_block = m_manager->Allocate(); + R_UNLESS(new_block != nullptr, ResultOutOfResource); + + // Initialize the block. + new_block->Initialize(addr, num_pages); + + // Add the block to our list. + if (m_last_block != nullptr) { + m_last_block->SetNext(new_block); + } else { + m_first_block = new_block; + } + m_last_block = new_block; + + R_SUCCEED(); +} + +void KPageGroup::Open() const { + auto& mm = m_kernel.MemoryManager(); + + for (const auto& it : *this) { + mm.Open(it.GetAddress(), it.GetNumPages()); + } +} + +void KPageGroup::OpenFirst() const { + auto& mm = m_kernel.MemoryManager(); + + for (const auto& it : *this) { + mm.OpenFirst(it.GetAddress(), it.GetNumPages()); + } +} + +void KPageGroup::Close() const { + auto& mm = m_kernel.MemoryManager(); + + for (const auto& it : *this) { + mm.Close(it.GetAddress(), it.GetNumPages()); + } +} + +bool KPageGroup::IsEquivalentTo(const KPageGroup& rhs) const { + auto lit = this->begin(); + auto rit = rhs.begin(); + auto lend = this->end(); + auto rend = rhs.end(); + + while (lit != lend && rit != rend) { + if (*lit != *rit) { + return false; + } + + ++lit; + ++rit; + } + + return lit == lend && rit == rend; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_page_group.h b/src/core/hle/kernel/k_page_group.h index 316f172f2..c07f17663 100644 --- a/src/core/hle/kernel/k_page_group.h +++ b/src/core/hle/kernel/k_page_group.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -13,24 +13,23 @@ namespace Kernel { +class KBlockInfoManager; +class KernelCore; class KPageGroup; class KBlockInfo { -private: - friend class KPageGroup; - public: - constexpr KBlockInfo() = default; + constexpr explicit KBlockInfo() : m_next(nullptr) {} - constexpr void Initialize(PAddr addr, size_t np) { + constexpr void Initialize(KPhysicalAddress addr, size_t np) { ASSERT(Common::IsAligned(addr, PageSize)); ASSERT(static_cast<u32>(np) == np); - m_page_index = static_cast<u32>(addr) / PageSize; + m_page_index = static_cast<u32>(addr / PageSize); m_num_pages = static_cast<u32>(np); } - constexpr PAddr GetAddress() const { + constexpr KPhysicalAddress GetAddress() const { return m_page_index * PageSize; } constexpr size_t GetNumPages() const { @@ -39,10 +38,10 @@ public: constexpr size_t GetSize() const { return this->GetNumPages() * PageSize; } - constexpr PAddr GetEndAddress() const { + constexpr KPhysicalAddress GetEndAddress() const { return (m_page_index + m_num_pages) * PageSize; } - constexpr PAddr GetLastAddress() const { + constexpr KPhysicalAddress GetLastAddress() const { return this->GetEndAddress() - 1; } @@ -62,8 +61,8 @@ public: return !(*this == rhs); } - constexpr bool IsStrictlyBefore(PAddr addr) const { - const PAddr end = this->GetEndAddress(); + constexpr bool IsStrictlyBefore(KPhysicalAddress addr) const { + const KPhysicalAddress end = this->GetEndAddress(); if (m_page_index != 0 && end == 0) { return false; @@ -72,11 +71,11 @@ public: return end < addr; } - constexpr bool operator<(PAddr addr) const { + constexpr bool operator<(KPhysicalAddress addr) const { return this->IsStrictlyBefore(addr); } - constexpr bool TryConcatenate(PAddr addr, size_t np) { + constexpr bool TryConcatenate(KPhysicalAddress addr, size_t np) { if (addr != 0 && addr == this->GetEndAddress()) { m_num_pages += static_cast<u32>(np); return true; @@ -90,96 +89,118 @@ private: } private: + friend class KPageGroup; + KBlockInfo* m_next{}; u32 m_page_index{}; u32 m_num_pages{}; }; static_assert(sizeof(KBlockInfo) <= 0x10); -class KPageGroup final { +class KPageGroup { public: - class Node final { + class Iterator { public: - constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {} + using iterator_category = std::forward_iterator_tag; + using value_type = const KBlockInfo; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + constexpr explicit Iterator(pointer n) : m_node(n) {} + + constexpr bool operator==(const Iterator& rhs) const { + return m_node == rhs.m_node; + } + constexpr bool operator!=(const Iterator& rhs) const { + return !(*this == rhs); + } - constexpr u64 GetAddress() const { - return addr; + constexpr pointer operator->() const { + return m_node; + } + constexpr reference operator*() const { + return *m_node; } - constexpr std::size_t GetNumPages() const { - return num_pages; + constexpr Iterator& operator++() { + m_node = m_node->GetNext(); + return *this; } - constexpr std::size_t GetSize() const { - return GetNumPages() * PageSize; + constexpr Iterator operator++(int) { + const Iterator it{*this}; + ++(*this); + return it; } private: - u64 addr{}; - std::size_t num_pages{}; + pointer m_node{}; }; -public: - KPageGroup() = default; - KPageGroup(u64 address, u64 num_pages) { - ASSERT(AddBlock(address, num_pages).IsSuccess()); + explicit KPageGroup(KernelCore& kernel, KBlockInfoManager* m) + : m_kernel{kernel}, m_manager{m} {} + ~KPageGroup() { + this->Finalize(); } - constexpr std::list<Node>& Nodes() { - return nodes; - } + void CloseAndReset(); + void Finalize(); - constexpr const std::list<Node>& Nodes() const { - return nodes; + Iterator begin() const { + return Iterator{m_first_block}; + } + Iterator end() const { + return Iterator{nullptr}; + } + bool empty() const { + return m_first_block == nullptr; } - std::size_t GetNumPages() const { - std::size_t num_pages = 0; - for (const Node& node : nodes) { - num_pages += node.GetNumPages(); - } - return num_pages; - } - - bool IsEqual(KPageGroup& other) const { - auto this_node = nodes.begin(); - auto other_node = other.nodes.begin(); - while (this_node != nodes.end() && other_node != other.nodes.end()) { - if (this_node->GetAddress() != other_node->GetAddress() || - this_node->GetNumPages() != other_node->GetNumPages()) { - return false; - } - this_node = std::next(this_node); - other_node = std::next(other_node); - } + Result AddBlock(KPhysicalAddress addr, size_t num_pages); + void Open() const; + void OpenFirst() const; + void Close() const; + + size_t GetNumPages() const; + + bool IsEquivalentTo(const KPageGroup& rhs) const; + + bool operator==(const KPageGroup& rhs) const { + return this->IsEquivalentTo(rhs); + } - return this_node == nodes.end() && other_node == other.nodes.end(); + bool operator!=(const KPageGroup& rhs) const { + return !(*this == rhs); } - Result AddBlock(u64 address, u64 num_pages) { - if (!num_pages) { - return ResultSuccess; +private: + KernelCore& m_kernel; + KBlockInfo* m_first_block{}; + KBlockInfo* m_last_block{}; + KBlockInfoManager* m_manager{}; +}; + +class KScopedPageGroup { +public: + explicit KScopedPageGroup(const KPageGroup* gp) : m_pg(gp) { + if (m_pg) { + m_pg->Open(); } - if (!nodes.empty()) { - const auto node = nodes.back(); - if (node.GetAddress() + node.GetNumPages() * PageSize == address) { - address = node.GetAddress(); - num_pages += node.GetNumPages(); - nodes.pop_back(); - } + } + explicit KScopedPageGroup(const KPageGroup& gp) : KScopedPageGroup(std::addressof(gp)) {} + ~KScopedPageGroup() { + if (m_pg) { + m_pg->Close(); } - nodes.push_back({address, num_pages}); - return ResultSuccess; } - bool Empty() const { - return nodes.empty(); + void CancelClose() { + m_pg = nullptr; } - void Finalize() {} - private: - std::list<Node> nodes; + const KPageGroup* m_pg{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 612fc76fa..2e13d5d0d 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -100,7 +100,7 @@ constexpr size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType a KPageTable::KPageTable(Core::System& system_) : m_general_lock{system_.Kernel()}, - m_map_physical_memory_lock{system_.Kernel()}, m_system{system_} {} + m_map_physical_memory_lock{system_.Kernel()}, m_system{system_}, m_kernel{system_.Kernel()} {} KPageTable::~KPageTable() = default; @@ -373,7 +373,7 @@ Result KPageTable::MapProcessCode(VAddr addr, size_t num_pages, KMemoryState sta m_memory_block_slab_manager); // Allocate and open. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen( &pg, num_pages, KMemoryManager::EncodeOption(KMemoryManager::Pool::Application, m_allocation_option))); @@ -432,9 +432,12 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si const size_t num_pages = size / PageSize; // Create page groups for the memory being mapped. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; AddRegionToPages(src_address, num_pages, pg); + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); + // Reprotect the source as kernel-read/not mapped. const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead | KMemoryPermission::NotMapped); @@ -447,7 +450,10 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si }); // Map the alias pages. - R_TRY(MapPages(dst_address, pg, new_perm)); + const KPageProperties dst_properties = {new_perm, false, false, + DisableMergeAttribute::DisableHead}; + R_TRY( + this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_properties, false)); // We successfully mapped the alias pages, so we don't need to unprotect the src pages on // failure. @@ -593,7 +599,7 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) { const size_t size = num_pages * PageSize; // We're making a new group, not adding to an existing one. - R_UNLESS(pg.Empty(), ResultInvalidCurrentMemory); + R_UNLESS(pg.empty(), ResultInvalidCurrentMemory); // Begin traversal. Common::PageTable::TraversalContext context; @@ -640,11 +646,10 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) { R_SUCCEED(); } -bool KPageTable::IsValidPageGroup(const KPageGroup& pg_ll, VAddr addr, size_t num_pages) { +bool KPageTable::IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages) { ASSERT(this->IsLockedByCurrentThread()); const size_t size = num_pages * PageSize; - const auto& pg = pg_ll.Nodes(); const auto& memory_layout = m_system.Kernel().MemoryLayout(); // Empty groups are necessarily invalid. @@ -942,9 +947,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add ON_RESULT_FAILURE { if (cur_mapped_addr != dst_addr) { - // HACK: Manually close the pages. - HACK_ClosePages(dst_addr, (cur_mapped_addr - dst_addr) / PageSize); - ASSERT(Operate(dst_addr, (cur_mapped_addr - dst_addr) / PageSize, KMemoryPermission::None, OperationType::Unmap) .IsSuccess()); @@ -1020,9 +1022,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add // Map the page. R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, start_partial_page)); - // HACK: Manually open the pages. - HACK_OpenPages(start_partial_page, 1); - // Update tracking extents. cur_mapped_addr += PageSize; cur_block_addr += PageSize; @@ -1051,9 +1050,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add R_TRY(Operate(cur_mapped_addr, cur_block_size / PageSize, test_perm, OperationType::Map, cur_block_addr)); - // HACK: Manually open the pages. - HACK_OpenPages(cur_block_addr, cur_block_size / PageSize); - // Update tracking extents. cur_mapped_addr += cur_block_size; cur_block_addr = next_entry.phys_addr; @@ -1073,9 +1069,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add R_TRY(Operate(cur_mapped_addr, last_block_size / PageSize, test_perm, OperationType::Map, cur_block_addr)); - // HACK: Manually open the pages. - HACK_OpenPages(cur_block_addr, last_block_size / PageSize); - // Update tracking extents. cur_mapped_addr += last_block_size; cur_block_addr += last_block_size; @@ -1107,9 +1100,6 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add // Map the page. R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, end_partial_page)); - - // HACK: Manually open the pages. - HACK_OpenPages(end_partial_page, 1); } // Update memory blocks to reflect our changes @@ -1211,9 +1201,6 @@ Result KPageTable::CleanupForIpcServer(VAddr address, size_t size, KMemoryState const size_t aligned_size = aligned_end - aligned_start; const size_t aligned_num_pages = aligned_size / PageSize; - // HACK: Manually close the pages. - HACK_ClosePages(aligned_start, aligned_num_pages); - // Unmap the pages. R_TRY(Operate(aligned_start, aligned_num_pages, KMemoryPermission::None, OperationType::Unmap)); @@ -1501,17 +1488,6 @@ void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLi } } -void KPageTable::HACK_OpenPages(PAddr phys_addr, size_t num_pages) { - m_system.Kernel().MemoryManager().OpenFirst(phys_addr, num_pages); -} - -void KPageTable::HACK_ClosePages(VAddr virt_addr, size_t num_pages) { - for (size_t index = 0; index < num_pages; ++index) { - const auto paddr = GetPhysicalAddr(virt_addr + (index * PageSize)); - m_system.Kernel().MemoryManager().Close(paddr, 1); - } -} - Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Lock the physical memory lock. KScopedLightLock phys_lk(m_map_physical_memory_lock); @@ -1572,7 +1548,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); // Allocate pages for the new memory. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess( &pg, (size - mapped_size) / PageSize, m_allocate_option, 0, 0)); @@ -1650,7 +1626,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { KScopedPageTableUpdater updater(this); // Prepare to iterate over the memory. - auto pg_it = pg.Nodes().begin(); + auto pg_it = pg.begin(); PAddr pg_phys_addr = pg_it->GetAddress(); size_t pg_pages = pg_it->GetNumPages(); @@ -1680,9 +1656,6 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { last_unmap_address + 1 - cur_address) / PageSize; - // HACK: Manually close the pages. - HACK_ClosePages(cur_address, cur_pages); - // Unmap. ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap) @@ -1703,7 +1676,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Release any remaining unmapped memory. m_system.Kernel().MemoryManager().OpenFirst(pg_phys_addr, pg_pages); m_system.Kernel().MemoryManager().Close(pg_phys_addr, pg_pages); - for (++pg_it; pg_it != pg.Nodes().end(); ++pg_it) { + for (++pg_it; pg_it != pg.end(); ++pg_it) { m_system.Kernel().MemoryManager().OpenFirst(pg_it->GetAddress(), pg_it->GetNumPages()); m_system.Kernel().MemoryManager().Close(pg_it->GetAddress(), @@ -1731,7 +1704,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Check if we're at the end of the physical block. if (pg_pages == 0) { // Ensure there are more pages to map. - ASSERT(pg_it != pg.Nodes().end()); + ASSERT(pg_it != pg.end()); // Advance our physical block. ++pg_it; @@ -1742,10 +1715,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) { // Map whatever we can. const size_t cur_pages = std::min(pg_pages, map_pages); R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite, - OperationType::Map, pg_phys_addr)); - - // HACK: Manually open the pages. - HACK_OpenPages(pg_phys_addr, cur_pages); + OperationType::MapFirst, pg_phys_addr)); // Advance. cur_address += cur_pages * PageSize; @@ -1888,9 +1858,6 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) { last_address + 1 - cur_address) / PageSize; - // HACK: Manually close the pages. - HACK_ClosePages(cur_address, cur_pages); - // Unmap. ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap) .IsSuccess()); @@ -1920,7 +1887,8 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) { R_SUCCEED(); } -Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size) { +Result KPageTable::MapMemory(KProcessAddress dst_address, KProcessAddress src_address, + size_t size) { // Lock the table. KScopedLightLock lk(m_general_lock); @@ -1941,53 +1909,73 @@ Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size) KMemoryAttribute::None)); // Create an update allocator for the source. - Result src_allocator_result{ResultSuccess}; + Result src_allocator_result; KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result), m_memory_block_slab_manager, num_src_allocator_blocks); R_TRY(src_allocator_result); // Create an update allocator for the destination. - Result dst_allocator_result{ResultSuccess}; + Result dst_allocator_result; KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result), m_memory_block_slab_manager, num_dst_allocator_blocks); R_TRY(dst_allocator_result); // Map the memory. - KPageGroup page_linked_list; - const size_t num_pages{size / PageSize}; - const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>( - KMemoryPermission::KernelRead | KMemoryPermission::NotMapped); - const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked; - - AddRegionToPages(src_address, num_pages, page_linked_list); { + // Determine the number of pages being operated on. + const size_t num_pages = size / PageSize; + + // Create page groups for the memory being unmapped. + KPageGroup pg{m_kernel, m_block_info_manager}; + + // Create the page group representing the source. + R_TRY(this->MakePageGroup(pg, src_address, num_pages)); + + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); + // Reprotect the source as kernel-read/not mapped. - auto block_guard = detail::ScopeExit([&] { - Operate(src_address, num_pages, KMemoryPermission::UserReadWrite, - OperationType::ChangePermissions); - }); - R_TRY(Operate(src_address, num_pages, new_src_perm, OperationType::ChangePermissions)); - R_TRY(MapPages(dst_address, page_linked_list, KMemoryPermission::UserReadWrite)); + const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>( + KMemoryPermission::KernelRead | KMemoryPermission::NotMapped); + const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked; + const KPageProperties src_properties = {new_src_perm, false, false, + DisableMergeAttribute::DisableHeadBodyTail}; + R_TRY(this->Operate(src_address, num_pages, src_properties.perm, + OperationType::ChangePermissions)); - block_guard.Cancel(); - } + // Ensure that we unprotect the source pages on failure. + ON_RESULT_FAILURE { + const KPageProperties unprotect_properties = { + KMemoryPermission::UserReadWrite, false, false, + DisableMergeAttribute::EnableHeadBodyTail}; + ASSERT(this->Operate(src_address, num_pages, unprotect_properties.perm, + OperationType::ChangePermissions) == ResultSuccess); + }; - // Apply the memory block updates. - m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, - new_src_perm, new_src_attr, - KMemoryBlockDisableMergeAttribute::Locked, - KMemoryBlockDisableMergeAttribute::None); - m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, - KMemoryState::Stack, KMemoryPermission::UserReadWrite, - KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal, - KMemoryBlockDisableMergeAttribute::None); + // Map the alias pages. + const KPageProperties dst_map_properties = {KMemoryPermission::UserReadWrite, false, false, + DisableMergeAttribute::DisableHead}; + R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_map_properties, + false)); + + // Apply the memory block updates. + m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, + src_state, new_src_perm, new_src_attr, + KMemoryBlockDisableMergeAttribute::Locked, + KMemoryBlockDisableMergeAttribute::None); + m_memory_block_manager.Update( + std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::Stack, + KMemoryPermission::UserReadWrite, KMemoryAttribute::None, + KMemoryBlockDisableMergeAttribute::Normal, KMemoryBlockDisableMergeAttribute::None); + } R_SUCCEED(); } -Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size) { +Result KPageTable::UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, + size_t size) { // Lock the table. KScopedLightLock lk(m_general_lock); @@ -2009,108 +1997,208 @@ Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None)); // Create an update allocator for the source. - Result src_allocator_result{ResultSuccess}; + Result src_allocator_result; KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result), m_memory_block_slab_manager, num_src_allocator_blocks); R_TRY(src_allocator_result); // Create an update allocator for the destination. - Result dst_allocator_result{ResultSuccess}; + Result dst_allocator_result; KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result), m_memory_block_slab_manager, num_dst_allocator_blocks); R_TRY(dst_allocator_result); - KPageGroup src_pages; - KPageGroup dst_pages; - const size_t num_pages{size / PageSize}; + // Unmap the memory. + { + // Determine the number of pages being operated on. + const size_t num_pages = size / PageSize; - AddRegionToPages(src_address, num_pages, src_pages); - AddRegionToPages(dst_address, num_pages, dst_pages); + // Create page groups for the memory being unmapped. + KPageGroup pg{m_kernel, m_block_info_manager}; - R_UNLESS(dst_pages.IsEqual(src_pages), ResultInvalidMemoryRegion); + // Create the page group representing the destination. + R_TRY(this->MakePageGroup(pg, dst_address, num_pages)); - { - auto block_guard = detail::ScopeExit([&] { MapPages(dst_address, dst_pages, dst_perm); }); + // Ensure the page group is the valid for the source. + R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), ResultInvalidMemoryRegion); - R_TRY(Operate(dst_address, num_pages, KMemoryPermission::None, OperationType::Unmap)); - R_TRY(Operate(src_address, num_pages, KMemoryPermission::UserReadWrite, - OperationType::ChangePermissions)); + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); - block_guard.Cancel(); - } + // Unmap the aliased copy of the pages. + const KPageProperties dst_unmap_properties = {KMemoryPermission::None, false, false, + DisableMergeAttribute::None}; + R_TRY( + this->Operate(dst_address, num_pages, dst_unmap_properties.perm, OperationType::Unmap)); + + // Ensure that we re-map the aliased pages on failure. + ON_RESULT_FAILURE { + this->RemapPageGroup(updater.GetPageList(), dst_address, size, pg); + }; - // Apply the memory block updates. - m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, - KMemoryPermission::UserReadWrite, KMemoryAttribute::None, - KMemoryBlockDisableMergeAttribute::None, - KMemoryBlockDisableMergeAttribute::Locked); - m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, - KMemoryState::None, KMemoryPermission::None, - KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None, - KMemoryBlockDisableMergeAttribute::Normal); + // Try to set the permissions for the source pages back to what they should be. + const KPageProperties src_properties = {KMemoryPermission::UserReadWrite, false, false, + DisableMergeAttribute::EnableAndMergeHeadBodyTail}; + R_TRY(this->Operate(src_address, num_pages, src_properties.perm, + OperationType::ChangePermissions)); + + // Apply the memory block updates. + m_memory_block_manager.Update( + std::addressof(src_allocator), src_address, num_pages, src_state, + KMemoryPermission::UserReadWrite, KMemoryAttribute::None, + KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Locked); + m_memory_block_manager.Update( + std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::None, + KMemoryPermission::None, KMemoryAttribute::None, + KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Normal); + } R_SUCCEED(); } -Result KPageTable::MapPages(VAddr addr, const KPageGroup& page_linked_list, - KMemoryPermission perm) { +Result KPageTable::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address, + size_t num_pages, KMemoryPermission perm) { ASSERT(this->IsLockedByCurrentThread()); - VAddr cur_addr{addr}; + // Create a page group to hold the pages we allocate. + KPageGroup pg{m_kernel, m_block_info_manager}; - for (const auto& node : page_linked_list.Nodes()) { - if (const auto result{ - Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())}; - result.IsError()) { - const size_t num_pages{(addr - cur_addr) / PageSize}; + // Allocate the pages. + R_TRY( + m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); - ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap) - .IsSuccess()); + // Ensure that the page group is closed when we're done working with it. + SCOPE_EXIT({ pg.Close(); }); + + // Clear all pages. + for (const auto& it : pg) { + std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value, + it.GetSize()); + } + + // Map the pages. + R_RETURN(this->Operate(address, num_pages, pg, OperationType::MapGroup)); +} + +Result KPageTable::MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address, + const KPageGroup& pg, const KPageProperties properties, + bool reuse_ll) { + ASSERT(this->IsLockedByCurrentThread()); + + // Note the current address, so that we can iterate. + const KProcessAddress start_address = address; + KProcessAddress cur_address = address; - R_RETURN(result); + // Ensure that we clean up on failure. + ON_RESULT_FAILURE { + ASSERT(!reuse_ll); + if (cur_address != start_address) { + const KPageProperties unmap_properties = {KMemoryPermission::None, false, false, + DisableMergeAttribute::None}; + ASSERT(this->Operate(start_address, (cur_address - start_address) / PageSize, + unmap_properties.perm, OperationType::Unmap) == ResultSuccess); } + }; - cur_addr += node.GetNumPages() * PageSize; + // Iterate, mapping all pages in the group. + for (const auto& block : pg) { + // Map and advance. + const KPageProperties cur_properties = + (cur_address == start_address) + ? properties + : KPageProperties{properties.perm, properties.io, properties.uncached, + DisableMergeAttribute::None}; + this->Operate(cur_address, block.GetNumPages(), cur_properties.perm, OperationType::Map, + block.GetAddress()); + cur_address += block.GetSize(); } + // We succeeded! R_SUCCEED(); } -Result KPageTable::MapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state, - KMemoryPermission perm) { - // Check that the map is in range. - const size_t num_pages{page_linked_list.GetNumPages()}; - const size_t size{num_pages * PageSize}; - R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory); +void KPageTable::RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size, + const KPageGroup& pg) { + ASSERT(this->IsLockedByCurrentThread()); - // Lock the table. - KScopedLightLock lk(m_general_lock); + // Note the current address, so that we can iterate. + const KProcessAddress start_address = address; + const KProcessAddress last_address = start_address + size - 1; + const KProcessAddress end_address = last_address + 1; - // Check the memory state. - R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, - KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::None, KMemoryAttribute::None)); + // Iterate over the memory. + auto pg_it = pg.begin(); + ASSERT(pg_it != pg.end()); - // Create an update allocator. - Result allocator_result{ResultSuccess}; - KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), - m_memory_block_slab_manager); + KPhysicalAddress pg_phys_addr = pg_it->GetAddress(); + size_t pg_pages = pg_it->GetNumPages(); - // Map the pages. - R_TRY(MapPages(address, page_linked_list, perm)); + auto it = m_memory_block_manager.FindIterator(start_address); + while (true) { + // Check that the iterator is valid. + ASSERT(it != m_memory_block_manager.end()); - // Update the blocks. - m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm, - KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal, - KMemoryBlockDisableMergeAttribute::None); + // Get the memory info. + const KMemoryInfo info = it->GetMemoryInfo(); - R_SUCCEED(); + // Determine the range to map. + KProcessAddress map_address = std::max<VAddr>(info.GetAddress(), start_address); + const KProcessAddress map_end_address = std::min<VAddr>(info.GetEndAddress(), end_address); + ASSERT(map_end_address != map_address); + + // Determine if we should disable head merge. + const bool disable_head_merge = + info.GetAddress() >= start_address && + True(info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute::Normal); + const KPageProperties map_properties = { + info.GetPermission(), false, false, + disable_head_merge ? DisableMergeAttribute::DisableHead : DisableMergeAttribute::None}; + + // While we have pages to map, map them. + size_t map_pages = (map_end_address - map_address) / PageSize; + while (map_pages > 0) { + // Check if we're at the end of the physical block. + if (pg_pages == 0) { + // Ensure there are more pages to map. + ASSERT(pg_it != pg.end()); + + // Advance our physical block. + ++pg_it; + pg_phys_addr = pg_it->GetAddress(); + pg_pages = pg_it->GetNumPages(); + } + + // Map whatever we can. + const size_t cur_pages = std::min(pg_pages, map_pages); + ASSERT(this->Operate(map_address, map_pages, map_properties.perm, OperationType::Map, + pg_phys_addr) == ResultSuccess); + + // Advance. + map_address += cur_pages * PageSize; + map_pages -= cur_pages; + + pg_phys_addr += cur_pages * PageSize; + pg_pages -= cur_pages; + } + + // Check if we're done. + if (last_address <= info.GetLastAddress()) { + break; + } + + // Advance. + ++it; + } + + // Check that we re-mapped precisely the page group. + ASSERT((++pg_it) == pg.end()); } -Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr, - bool is_pa_valid, VAddr region_start, size_t region_num_pages, +Result KPageTable::MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment, + KPhysicalAddress phys_addr, bool is_pa_valid, + KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize); @@ -2123,26 +2211,30 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, KScopedLightLock lk(m_general_lock); // Find a random address to map at. - VAddr addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0, - this->GetNumGuardPages()); + KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, + 0, this->GetNumGuardPages()); R_UNLESS(addr != 0, ResultOutOfMemory); ASSERT(Common::IsAligned(addr, alignment)); ASSERT(this->CanContain(addr, num_pages * PageSize, state)); ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::None, KMemoryAttribute::None) - .IsSuccess()); + KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess); // Create an update allocator. - Result allocator_result{ResultSuccess}; + Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager); + R_TRY(allocator_result); + + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); // Perform mapping operation. if (is_pa_valid) { - R_TRY(this->Operate(addr, num_pages, perm, OperationType::Map, phys_addr)); + const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead}; + R_TRY(this->Operate(addr, num_pages, properties.perm, OperationType::Map, phys_addr)); } else { - UNIMPLEMENTED(); + R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm)); } // Update the blocks. @@ -2155,28 +2247,45 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, R_SUCCEED(); } -Result KPageTable::UnmapPages(VAddr addr, const KPageGroup& page_linked_list) { - ASSERT(this->IsLockedByCurrentThread()); +Result KPageTable::MapPages(KProcessAddress address, size_t num_pages, KMemoryState state, + KMemoryPermission perm) { + // Check that the map is in range. + const size_t size = num_pages * PageSize; + R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory); - VAddr cur_addr{addr}; + // Lock the table. + KScopedLightLock lk(m_general_lock); - for (const auto& node : page_linked_list.Nodes()) { - if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None, - OperationType::Unmap)}; - result.IsError()) { - R_RETURN(result); - } + // Check the memory state. + size_t num_allocator_blocks; + R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, + KMemoryState::All, KMemoryState::Free, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::None, + KMemoryAttribute::None)); - cur_addr += node.GetNumPages() * PageSize; - } + // Create an update allocator. + Result allocator_result; + KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), + m_memory_block_slab_manager, num_allocator_blocks); + R_TRY(allocator_result); + + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); + + // Map the pages. + R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm)); + + // Update the blocks. + m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm, + KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal, + KMemoryBlockDisableMergeAttribute::None); R_SUCCEED(); } -Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state) { +Result KPageTable::UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) { // Check that the unmap is in range. - const size_t num_pages{page_linked_list.GetNumPages()}; - const size_t size{num_pages * PageSize}; + const size_t size = num_pages * PageSize; R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory); // Lock the table. @@ -2190,13 +2299,18 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo KMemoryAttribute::None)); // Create an update allocator. - Result allocator_result{ResultSuccess}; + Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); + // Perform the unmap. - R_TRY(UnmapPages(address, page_linked_list)); + const KPageProperties unmap_properties = {KMemoryPermission::None, false, false, + DisableMergeAttribute::None}; + R_TRY(this->Operate(address, num_pages, unmap_properties.perm, OperationType::Unmap)); // Update the blocks. m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free, @@ -2207,29 +2321,130 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo R_SUCCEED(); } -Result KPageTable::UnmapPages(VAddr address, size_t num_pages, KMemoryState state) { - // Check that the unmap is in range. +Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg, + KProcessAddress region_start, size_t region_num_pages, + KMemoryState state, KMemoryPermission perm) { + ASSERT(!this->IsLockedByCurrentThread()); + + // Ensure this is a valid map request. + const size_t num_pages = pg.GetNumPages(); + R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state), + ResultInvalidCurrentMemory); + R_UNLESS(num_pages < region_num_pages, ResultOutOfMemory); + + // Lock the table. + KScopedLightLock lk(m_general_lock); + + // Find a random address to map at. + KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, PageSize, + 0, this->GetNumGuardPages()); + R_UNLESS(addr != 0, ResultOutOfMemory); + ASSERT(this->CanContain(addr, num_pages * PageSize, state)); + ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free, + KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess); + + // Create an update allocator. + Result allocator_result; + KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), + m_memory_block_slab_manager); + R_TRY(allocator_result); + + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); + + // Perform mapping operation. + const KPageProperties properties = {perm, state == KMemoryState::Io, false, + DisableMergeAttribute::DisableHead}; + R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false)); + + // Update the blocks. + m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm, + KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal, + KMemoryBlockDisableMergeAttribute::None); + + // We successfully mapped the pages. + *out_addr = addr; + R_SUCCEED(); +} + +Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMemoryState state, + KMemoryPermission perm) { + ASSERT(!this->IsLockedByCurrentThread()); + + // Ensure this is a valid map request. + const size_t num_pages = pg.GetNumPages(); const size_t size = num_pages * PageSize; - R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory); + R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory); // Lock the table. KScopedLightLock lk(m_general_lock); - // Check the memory state. - size_t num_allocator_blocks{}; + // Check if state allows us to map. + size_t num_allocator_blocks; + R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), addr, size, + KMemoryState::All, KMemoryState::Free, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::None, + KMemoryAttribute::None)); + + // Create an update allocator. + Result allocator_result; + KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), + m_memory_block_slab_manager, num_allocator_blocks); + R_TRY(allocator_result); + + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); + + // Perform mapping operation. + const KPageProperties properties = {perm, state == KMemoryState::Io, false, + DisableMergeAttribute::DisableHead}; + R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false)); + + // Update the blocks. + m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm, + KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal, + KMemoryBlockDisableMergeAttribute::None); + + // We successfully mapped the pages. + R_SUCCEED(); +} + +Result KPageTable::UnmapPageGroup(KProcessAddress address, const KPageGroup& pg, + KMemoryState state) { + ASSERT(!this->IsLockedByCurrentThread()); + + // Ensure this is a valid unmap request. + const size_t num_pages = pg.GetNumPages(); + const size_t size = num_pages * PageSize; + R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory); + + // Lock the table. + KScopedLightLock lk(m_general_lock); + + // Check if state allows us to unmap. + size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState::All, state, KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None)); + // Check that the page group is valid. + R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), ResultInvalidCurrentMemory); + // Create an update allocator. - Result allocator_result{ResultSuccess}; + Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); - // Perform the unmap. - R_TRY(Operate(address, num_pages, KMemoryPermission::None, OperationType::Unmap)); + // We're going to perform an update, so create a helper. + KScopedPageTableUpdater updater(this); + + // Perform unmapping operation. + const KPageProperties properties = {KMemoryPermission::None, false, false, + DisableMergeAttribute::None}; + R_TRY(this->Operate(address, num_pages, properties.perm, OperationType::Unmap)); // Update the blocks. m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free, @@ -2527,13 +2742,13 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) { R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); // Allocate pages for the heap extension. - KPageGroup pg; + KPageGroup pg{m_kernel, m_block_info_manager}; R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen( &pg, allocation_size / PageSize, KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option))); // Clear all the newly allocated pages. - for (const auto& it : pg.Nodes()) { + for (const auto& it : pg) { std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value, it.GetSize()); } @@ -2589,42 +2804,6 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) { } } -ResultVal<VAddr> KPageTable::AllocateAndMapMemory(size_t needed_num_pages, size_t align, - bool is_map_only, VAddr region_start, - size_t region_num_pages, KMemoryState state, - KMemoryPermission perm, PAddr map_addr) { - KScopedLightLock lk(m_general_lock); - - R_UNLESS(CanContain(region_start, region_num_pages * PageSize, state), - ResultInvalidCurrentMemory); - R_UNLESS(region_num_pages > needed_num_pages, ResultOutOfMemory); - const VAddr addr{ - AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)}; - R_UNLESS(addr, ResultOutOfMemory); - - // Create an update allocator. - Result allocator_result{ResultSuccess}; - KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), - m_memory_block_slab_manager); - - if (is_map_only) { - R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); - } else { - KPageGroup page_group; - R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess( - &page_group, needed_num_pages, - KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option), 0, 0)); - R_TRY(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); - } - - // Update the blocks. - m_memory_block_manager.Update(std::addressof(allocator), addr, needed_num_pages, state, perm, - KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal, - KMemoryBlockDisableMergeAttribute::None); - - return addr; -} - Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) { @@ -2795,19 +2974,28 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_ ASSERT(num_pages > 0); ASSERT(num_pages == page_group.GetNumPages()); - for (const auto& node : page_group.Nodes()) { - const size_t size{node.GetNumPages() * PageSize}; + switch (operation) { + case OperationType::MapGroup: { + // We want to maintain a new reference to every page in the group. + KScopedPageGroup spg(page_group); + + for (const auto& node : page_group) { + const size_t size{node.GetNumPages() * PageSize}; - switch (operation) { - case OperationType::MapGroup: + // Map the pages. m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress()); - break; - default: - ASSERT(false); - break; + + addr += size; } - addr += size; + // We succeeded! We want to persist the reference to the pages. + spg.CancelClose(); + + break; + } + default: + ASSERT(false); + break; } R_SUCCEED(); @@ -2822,13 +3010,29 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, ASSERT(ContainsPages(addr, num_pages)); switch (operation) { - case OperationType::Unmap: + case OperationType::Unmap: { + // Ensure that any pages we track close on exit. + KPageGroup pages_to_close{m_kernel, this->GetBlockInfoManager()}; + SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); + + this->AddRegionToPages(addr, num_pages, pages_to_close); m_system.Memory().UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize); break; + } + case OperationType::MapFirst: case OperationType::Map: { ASSERT(map_addr); ASSERT(Common::IsAligned(map_addr, PageSize)); m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr); + + // Open references to pages, if we should. + if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) { + if (operation == OperationType::MapFirst) { + m_kernel.MemoryManager().OpenFirst(map_addr, num_pages); + } else { + m_kernel.MemoryManager().Open(map_addr, num_pages); + } + } break; } case OperationType::Separate: { diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index f1ca785d7..367dab613 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -24,12 +24,36 @@ class System; namespace Kernel { +enum class DisableMergeAttribute : u8 { + None = (0U << 0), + DisableHead = (1U << 0), + DisableHeadAndBody = (1U << 1), + EnableHeadAndBody = (1U << 2), + DisableTail = (1U << 3), + EnableTail = (1U << 4), + EnableAndMergeHeadBodyTail = (1U << 5), + EnableHeadBodyTail = EnableHeadAndBody | EnableTail, + DisableHeadBodyTail = DisableHeadAndBody | DisableTail, +}; + +struct KPageProperties { + KMemoryPermission perm; + bool io; + bool uncached; + DisableMergeAttribute disable_merge_attributes; +}; +static_assert(std::is_trivial_v<KPageProperties>); +static_assert(sizeof(KPageProperties) == sizeof(u32)); + class KBlockInfoManager; class KMemoryBlockManager; class KResourceLimit; class KSystemResource; class KPageTable final { +protected: + struct PageLinkedList; + public: enum class ICacheInvalidationStrategy : u32 { InvalidateRange, InvalidateAll }; @@ -57,27 +81,12 @@ public: Result UnmapPhysicalMemory(VAddr addr, size_t size); Result MapMemory(VAddr dst_addr, VAddr src_addr, size_t size); Result UnmapMemory(VAddr dst_addr, VAddr src_addr, size_t size); - Result MapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state, - KMemoryPermission perm); - Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr, - KMemoryState state, KMemoryPermission perm) { - R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, - this->GetRegionAddress(state), - this->GetRegionSize(state) / PageSize, state, perm)); - } - Result UnmapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state); - Result UnmapPages(VAddr address, size_t num_pages, KMemoryState state); Result SetProcessMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm); KMemoryInfo QueryInfo(VAddr addr); Result SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission perm); Result SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr); Result SetMaxHeapSize(size_t size); Result SetHeapSize(VAddr* out, size_t size); - ResultVal<VAddr> AllocateAndMapMemory(size_t needed_num_pages, size_t align, bool is_map_only, - VAddr region_start, size_t region_num_pages, - KMemoryState state, KMemoryPermission perm, - PAddr map_addr = 0); - Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap); Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap); @@ -107,8 +116,46 @@ public: return *m_page_table_impl; } + KBlockInfoManager* GetBlockInfoManager() { + return m_block_info_manager; + } + bool CanContain(VAddr addr, size_t size, KMemoryState state) const; + Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment, + KPhysicalAddress phys_addr, KProcessAddress region_start, + size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { + R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, + region_num_pages, state, perm)); + } + + Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment, + KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) { + R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, + this->GetRegionAddress(state), + this->GetRegionSize(state) / PageSize, state, perm)); + } + + Result MapPages(KProcessAddress* out_addr, size_t num_pages, KMemoryState state, + KMemoryPermission perm) { + R_RETURN(this->MapPages(out_addr, num_pages, PageSize, 0, false, + this->GetRegionAddress(state), + this->GetRegionSize(state) / PageSize, state, perm)); + } + + Result MapPages(KProcessAddress address, size_t num_pages, KMemoryState state, + KMemoryPermission perm); + Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state); + + Result MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg, + KProcessAddress region_start, size_t region_num_pages, KMemoryState state, + KMemoryPermission perm); + Result MapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state, + KMemoryPermission perm); + Result UnmapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state); + void RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size, + const KPageGroup& pg); + protected: struct PageLinkedList { private: @@ -162,11 +209,9 @@ private: static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr = KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared; - Result MapPages(VAddr addr, const KPageGroup& page_linked_list, KMemoryPermission perm); - Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr, - bool is_pa_valid, VAddr region_start, size_t region_num_pages, - KMemoryState state, KMemoryPermission perm); - Result UnmapPages(VAddr addr, const KPageGroup& page_linked_list); + Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment, + KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, + size_t region_num_pages, KMemoryState state, KMemoryPermission perm); bool IsRegionContiguous(VAddr addr, u64 size) const; void AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list); KMemoryInfo QueryInfoImpl(VAddr addr); @@ -261,9 +306,10 @@ private: void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address, size_t size, KMemoryPermission prot_perm); - // HACK: These will be removed once we automatically manage page reference counts. - void HACK_OpenPages(PAddr phys_addr, size_t num_pages); - void HACK_ClosePages(VAddr virt_addr, size_t num_pages); + Result AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address, + size_t num_pages, KMemoryPermission perm); + Result MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address, + const KPageGroup& pg, const KPageProperties properties, bool reuse_ll); mutable KLightLock m_general_lock; mutable KLightLock m_map_physical_memory_lock; @@ -488,6 +534,7 @@ private: std::unique_ptr<Common::PageTable> m_page_table_impl; Core::System& m_system; + KernelCore& m_kernel; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index cb2512b0b..645c5b531 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h @@ -17,35 +17,41 @@ namespace Kernel { class KThread; template <typename T> -concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { - { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>; - {t.SetAffinityMask(0)}; +concept KPriorityQueueAffinityMask = ! +std::is_reference_v<T>&& requires(T& t) { + { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>; + { t.SetAffinityMask(0) }; - { t.GetAffinity(0) } -> std::same_as<bool>; - {t.SetAffinity(0, false)}; - {t.SetAll()}; -}; + { t.GetAffinity(0) } -> std::same_as<bool>; + { t.SetAffinity(0, false) }; + { t.SetAll() }; + }; template <typename T> -concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { - {typename T::QueueEntry()}; - {(typename T::QueueEntry()).Initialize()}; - {(typename T::QueueEntry()).SetPrev(std::addressof(t))}; - {(typename T::QueueEntry()).SetNext(std::addressof(t))}; - { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>; - { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>; - { t.GetPriorityQueueEntry(0) } -> std::same_as<typename T::QueueEntry&>; - - {t.GetAffinityMask()}; - { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } -> KPriorityQueueAffinityMask; - - { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; - { t.GetPriority() } -> Common::ConvertibleTo<s32>; - { t.IsDummyThread() } -> Common::ConvertibleTo<bool>; -}; +concept KPriorityQueueMember = ! +std::is_reference_v<T>&& requires(T& t) { + { typename T::QueueEntry() }; + { (typename T::QueueEntry()).Initialize() }; + { (typename T::QueueEntry()).SetPrev(std::addressof(t)) }; + { (typename T::QueueEntry()).SetNext(std::addressof(t)) }; + { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>; + { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>; + { + t.GetPriorityQueueEntry(0) + } -> std::same_as<typename T::QueueEntry&>; + + { t.GetAffinityMask() }; + { + std::remove_cvref_t<decltype(t.GetAffinityMask())>() + } -> KPriorityQueueAffinityMask; + + { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; + { t.GetPriority() } -> Common::ConvertibleTo<s32>; + { t.IsDummyThread() } -> Common::ConvertibleTo<bool>; + }; template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> -requires KPriorityQueueMember<Member> + requires KPriorityQueueMember<Member> class KPriorityQueue { public: using AffinityMaskType = std::remove_cv_t< diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index a1abf5d68..0e4283a0c 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -370,7 +370,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: // Initialize proces address space if (const Result result{page_table.InitializeForProcess( metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application, - 0x8000000, code_size, &kernel.GetSystemSystemResource(), resource_limit)}; + 0x8000000, code_size, &kernel.GetAppSystemResource(), resource_limit)}; result.IsError()) { R_RETURN(result); } @@ -417,9 +417,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: } void KProcess::Run(s32 main_thread_priority, u64 stack_size) { - AllocateMainThreadStack(stack_size); + ASSERT(AllocateMainThreadStack(stack_size) == ResultSuccess); resource_limit->Reserve(LimitableResource::ThreadCountMax, 1); - resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size); const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)}; ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError()); @@ -675,20 +674,31 @@ void KProcess::ChangeState(State new_state) { } Result KProcess::AllocateMainThreadStack(std::size_t stack_size) { - ASSERT(stack_size); - - // The kernel always ensures that the given stack size is page aligned. - main_thread_stack_size = Common::AlignUp(stack_size, PageSize); - - const VAddr start{page_table.GetStackRegionStart()}; - const std::size_t size{page_table.GetStackRegionEnd() - start}; - - CASCADE_RESULT(main_thread_stack_top, - page_table.AllocateAndMapMemory( - main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize, - KMemoryState::Stack, KMemoryPermission::UserReadWrite)); + // Ensure that we haven't already allocated stack. + ASSERT(main_thread_stack_size == 0); + + // Ensure that we're allocating a valid stack. + stack_size = Common::AlignUp(stack_size, PageSize); + // R_UNLESS(stack_size + image_size <= m_max_process_memory, ResultOutOfMemory); + R_UNLESS(stack_size + image_size >= image_size, ResultOutOfMemory); + + // Place a tentative reservation of memory for our new stack. + KScopedResourceReservation mem_reservation(this, Svc::LimitableResource::PhysicalMemoryMax, + stack_size); + R_UNLESS(mem_reservation.Succeeded(), ResultLimitReached); + + // Allocate and map our stack. + if (stack_size) { + KProcessAddress stack_bottom; + R_TRY(page_table.MapPages(std::addressof(stack_bottom), stack_size / PageSize, + KMemoryState::Stack, KMemoryPermission::UserReadWrite)); + + main_thread_stack_top = stack_bottom + stack_size; + main_thread_stack_size = stack_size; + } - main_thread_stack_top += main_thread_stack_size; + // We succeeded! Commit our memory reservation. + mem_reservation.Commit(); R_SUCCEED(); } diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index d6676904b..d6c214237 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -328,7 +328,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { } void KScheduler::SwitchThread(KThread* next_thread) { - KProcess* const cur_process = kernel.CurrentProcess(); + KProcess* const cur_process = GetCurrentProcessPointer(kernel); KThread* const cur_thread = GetCurrentThreadPointer(kernel); // We never want to schedule a null thread, so use the idle thread if we don't have a next. @@ -689,11 +689,11 @@ void KScheduler::RotateScheduledQueue(KernelCore& kernel, s32 core_id, s32 prior void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { // Validate preconditions. ASSERT(CanSchedule(kernel)); - ASSERT(kernel.CurrentProcess() != nullptr); + ASSERT(GetCurrentProcessPointer(kernel) != nullptr); // Get the current thread and process. KThread& cur_thread = GetCurrentThread(kernel); - KProcess& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = GetCurrentProcess(kernel); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -728,11 +728,11 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { // Validate preconditions. ASSERT(CanSchedule(kernel)); - ASSERT(kernel.CurrentProcess() != nullptr); + ASSERT(GetCurrentProcessPointer(kernel) != nullptr); // Get the current thread and process. KThread& cur_thread = GetCurrentThread(kernel); - KProcess& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = GetCurrentProcess(kernel); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -816,11 +816,11 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { void KScheduler::YieldToAnyThread(KernelCore& kernel) { // Validate preconditions. ASSERT(CanSchedule(kernel)); - ASSERT(kernel.CurrentProcess() != nullptr); + ASSERT(GetCurrentProcessPointer(kernel) != nullptr); // Get the current thread and process. KThread& cur_thread = GetCurrentThread(kernel); - KProcess& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = GetCurrentProcess(kernel); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h index 857e21156..59b3e32ae 100644 --- a/src/core/hle/kernel/k_scoped_lock.h +++ b/src/core/hle/kernel/k_scoped_lock.h @@ -9,13 +9,14 @@ namespace Kernel { template <typename T> -concept KLockable = !std::is_reference_v<T> && requires(T & t) { - { t.Lock() } -> std::same_as<void>; - { t.Unlock() } -> std::same_as<void>; -}; +concept KLockable = ! +std::is_reference_v<T>&& requires(T& t) { + { t.Lock() } -> std::same_as<void>; + { t.Unlock() } -> std::same_as<void>; + }; template <typename T> -requires KLockable<T> + requires KLockable<T> class [[nodiscard]] KScopedLock { public: explicit KScopedLock(T* l) : lock_ptr(l) { diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index b6f6fe9d9..7e677c028 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -33,7 +33,8 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_) { name = name_; // Set our owner process. - process = kernel.CurrentProcess(); + //! FIXME: this is the wrong process! + process = kernel.ApplicationProcess(); process->Open(); // Set our port. diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index 0aa68103c..df505edfe 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -13,10 +13,7 @@ namespace Kernel { KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {} - -KSharedMemory::~KSharedMemory() { - kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, size); -} +KSharedMemory::~KSharedMemory() = default; Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_, Svc::MemoryPermission owner_permission_, @@ -49,7 +46,8 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o R_UNLESS(physical_address != 0, ResultOutOfMemory); //! Insert the result into our page group. - page_group.emplace(physical_address, num_pages); + page_group.emplace(kernel, &kernel.GetSystemSystemResource().GetBlockInfoManager()); + page_group->AddBlock(physical_address, num_pages); // Commit our reservation. memory_reservation.Commit(); @@ -62,7 +60,7 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o is_initialized = true; // Clear all pages in the memory. - for (const auto& block : page_group->Nodes()) { + for (const auto& block : *page_group) { std::memset(device_memory_.GetPointer<void>(block.GetAddress()), 0, block.GetSize()); } @@ -71,13 +69,8 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o void KSharedMemory::Finalize() { // Close and finalize the page group. - // page_group->Close(); - // page_group->Finalize(); - - //! HACK: Manually close. - for (const auto& block : page_group->Nodes()) { - kernel.MemoryManager().Close(block.GetAddress(), block.GetNumPages()); - } + page_group->Close(); + page_group->Finalize(); // Release the memory reservation. resource_limit->Release(LimitableResource::PhysicalMemoryMax, size); @@ -101,15 +94,15 @@ Result KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t m R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission); } - return target_process.PageTable().MapPages(address, *page_group, KMemoryState::Shared, - ConvertToKMemoryPermission(map_perm)); + return target_process.PageTable().MapPageGroup(address, *page_group, KMemoryState::Shared, + ConvertToKMemoryPermission(map_perm)); } Result KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) { // Validate the size. R_UNLESS(size == unmap_size, ResultInvalidSize); - return target_process.PageTable().UnmapPages(address, *page_group, KMemoryState::Shared); + return target_process.PageTable().UnmapPageGroup(address, *page_group, KMemoryState::Shared); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 21207fe99..2d3da9d66 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -330,7 +330,7 @@ void KThread::Finalize() { KThread* const waiter = std::addressof(*it); // The thread shouldn't be a kernel waiter. - ASSERT(!IsKernelAddressKey(waiter->GetAddressKey())); + ASSERT(!waiter->GetAddressKeyIsKernel()); // Clear the lock owner. waiter->SetLockOwner(nullptr); @@ -763,19 +763,6 @@ void KThread::Continue() { KScheduler::OnThreadStateChanged(kernel, this, old_state); } -void KThread::WaitUntilSuspended() { - // Make sure we have a suspend requested. - ASSERT(IsSuspendRequested()); - - // Loop until the thread is not executing on any core. - for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) { - KThread* core_thread{}; - do { - core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread(); - } while (core_thread == this); - } -} - Result KThread::SetActivity(Svc::ThreadActivity activity) { // Lock ourselves. KScopedLightLock lk(activity_pause_lock); @@ -897,7 +884,7 @@ void KThread::AddWaiterImpl(KThread* thread) { } // Keep track of how many kernel waiters we have. - if (IsKernelAddressKey(thread->GetAddressKey())) { + if (thread->GetAddressKeyIsKernel()) { ASSERT((num_kernel_waiters++) >= 0); KScheduler::SetSchedulerUpdateNeeded(kernel); } @@ -911,7 +898,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Keep track of how many kernel waiters we have. - if (IsKernelAddressKey(thread->GetAddressKey())) { + if (thread->GetAddressKeyIsKernel()) { ASSERT((num_kernel_waiters--) > 0); KScheduler::SetSchedulerUpdateNeeded(kernel); } @@ -987,7 +974,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { KThread* thread = std::addressof(*it); // Keep track of how many kernel waiters we have. - if (IsKernelAddressKey(thread->GetAddressKey())) { + if (thread->GetAddressKeyIsKernel()) { ASSERT((num_kernel_waiters--) > 0); KScheduler::SetSchedulerUpdateNeeded(kernel); } @@ -1279,6 +1266,14 @@ KThread& GetCurrentThread(KernelCore& kernel) { return *GetCurrentThreadPointer(kernel); } +KProcess* GetCurrentProcessPointer(KernelCore& kernel) { + return GetCurrentThread(kernel).GetOwnerProcess(); +} + +KProcess& GetCurrentProcess(KernelCore& kernel) { + return *GetCurrentProcessPointer(kernel); +} + s32 GetCurrentCoreId(KernelCore& kernel) { return GetCurrentThread(kernel).GetCurrentCore(); } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 7cd94a340..ca82ce3b6 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -110,6 +110,8 @@ enum class StepState : u32 { void SetCurrentThread(KernelCore& kernel, KThread* thread); [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); +[[nodiscard]] KProcess* GetCurrentProcessPointer(KernelCore& kernel); +[[nodiscard]] KProcess& GetCurrentProcess(KernelCore& kernel); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, @@ -214,8 +216,6 @@ public: void Continue(); - void WaitUntilSuspended(); - constexpr void SetSyncedIndex(s32 index) { synced_index = index; } @@ -607,13 +607,30 @@ public: return address_key_value; } - void SetAddressKey(VAddr key) { + [[nodiscard]] bool GetAddressKeyIsKernel() const { + return address_key_is_kernel; + } + + //! NB: intentional deviation from official kernel. + // + // Separate SetAddressKey into user and kernel versions + // to cope with arbitrary host pointers making their way + // into things. + + void SetUserAddressKey(VAddr key) { address_key = key; + address_key_is_kernel = false; } - void SetAddressKey(VAddr key, u32 val) { + void SetUserAddressKey(VAddr key, u32 val) { address_key = key; address_key_value = val; + address_key_is_kernel = false; + } + + void SetKernelAddressKey(VAddr key) { + address_key = key; + address_key_is_kernel = true; } void ClearWaitQueue() { @@ -662,7 +679,7 @@ private: union SyncObjectBuffer { std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{}; std::array<Handle, - Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))> + Svc::ArgumentHandleCountMax * (sizeof(KSynchronizationObject*) / sizeof(Handle))> handles; constexpr SyncObjectBuffer() {} }; @@ -683,10 +700,8 @@ private: }; template <typename T> - requires( - std::same_as<T, KThread> || - std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs, - const KThread& rhs) { + requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>) + static constexpr int Compare(const T& lhs, const KThread& rhs) { const u64 l_key = lhs.GetConditionVariableKey(); const u64 r_key = rhs.GetConditionVariableKey(); @@ -772,6 +787,7 @@ private: bool debug_attached{}; s8 priority_inheritance_count{}; bool resource_limit_release_hint{}; + bool address_key_is_kernel{}; StackParameters stack_parameters{}; Common::SpinLock context_guard{}; diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h index fe0cff084..71254eb55 100644 --- a/src/core/hle/kernel/k_thread_local_page.h +++ b/src/core/hle/kernel/k_thread_local_page.h @@ -70,10 +70,8 @@ public: } template <typename T> - requires(std::same_as<T, KThreadLocalPage> || - std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs, - const KThreadLocalPage& - rhs) { + requires(std::same_as<T, KThreadLocalPage> || std::same_as<T, RedBlackKeyType>) + static constexpr int Compare(const T& lhs, const KThreadLocalPage& rhs) { const VAddr lval = GetRedBlackKey(lhs); const VAddr rval = GetRedBlackKey(rhs); diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp index 9f34c2d46..faa5c73b5 100644 --- a/src/core/hle/kernel/k_transfer_memory.cpp +++ b/src/core/hle/kernel/k_transfer_memory.cpp @@ -16,7 +16,7 @@ KTransferMemory::~KTransferMemory() = default; Result KTransferMemory::Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_) { // Set members. - owner = kernel.CurrentProcess(); + owner = GetCurrentProcessPointer(kernel); // TODO(bunnei): Lock for transfer memory diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1fb25f221..3a68a5633 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -29,6 +29,7 @@ #include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_object_name.h" #include "core/hle/kernel/k_page_buffer.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" @@ -84,6 +85,7 @@ struct KernelCore::Impl { InitializeShutdownThreads(); InitializePhysicalCores(); InitializePreemption(kernel); + InitializeGlobalData(kernel); // Initialize the Dynamic Slab Heaps. { @@ -102,13 +104,13 @@ struct KernelCore::Impl { void InitializeCores() { for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - cores[core_id]->Initialize((*current_process).Is64BitProcess()); - system.Memory().SetCurrentPageTable(*current_process, core_id); + cores[core_id]->Initialize((*application_process).Is64BitProcess()); + system.Memory().SetCurrentPageTable(*application_process, core_id); } } - void CloseCurrentProcess() { - KProcess* old_process = current_process.exchange(nullptr); + void CloseApplicationProcess() { + KProcess* old_process = application_process.exchange(nullptr); if (old_process == nullptr) { return; } @@ -182,7 +184,7 @@ struct KernelCore::Impl { } } - CloseCurrentProcess(); + CloseApplicationProcess(); // Track kernel objects that were not freed on shutdown { @@ -194,6 +196,8 @@ struct KernelCore::Impl { } } + object_name_global_data.reset(); + // Ensure that the object list container is finalized and properly shutdown. global_object_list_container->Finalize(); global_object_list_container.reset(); @@ -363,8 +367,12 @@ struct KernelCore::Impl { } } - void MakeCurrentProcess(KProcess* process) { - current_process = process; + void InitializeGlobalData(KernelCore& kernel) { + object_name_global_data = std::make_unique<KObjectNameGlobalData>(kernel); + } + + void MakeApplicationProcess(KProcess* process) { + application_process = process; } static inline thread_local u32 host_thread_id = UINT32_MAX; @@ -821,7 +829,7 @@ struct KernelCore::Impl { // Lists all processes that exist in the current session. std::vector<KProcess*> process_list; - std::atomic<KProcess*> current_process{}; + std::atomic<KProcess*> application_process{}; std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; @@ -838,6 +846,8 @@ struct KernelCore::Impl { std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container; + std::unique_ptr<KObjectNameGlobalData> object_name_global_data; + /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; @@ -941,20 +951,20 @@ void KernelCore::AppendNewProcess(KProcess* process) { impl->process_list.push_back(process); } -void KernelCore::MakeCurrentProcess(KProcess* process) { - impl->MakeCurrentProcess(process); +void KernelCore::MakeApplicationProcess(KProcess* process) { + impl->MakeApplicationProcess(process); } -KProcess* KernelCore::CurrentProcess() { - return impl->current_process; +KProcess* KernelCore::ApplicationProcess() { + return impl->application_process; } -const KProcess* KernelCore::CurrentProcess() const { - return impl->current_process; +const KProcess* KernelCore::ApplicationProcess() const { + return impl->application_process; } -void KernelCore::CloseCurrentProcess() { - impl->CloseCurrentProcess(); +void KernelCore::CloseApplicationProcess() { + impl->CloseApplicationProcess(); } const std::vector<KProcess*>& KernelCore::GetProcessList() const { @@ -1138,6 +1148,10 @@ void KernelCore::SetCurrentEmuThread(KThread* thread) { impl->SetCurrentEmuThread(thread); } +KObjectNameGlobalData& KernelCore::ObjectNameGlobalData() { + return *impl->object_name_global_data; +} + KMemoryManager& KernelCore::MemoryManager() { return *impl->memory_manager; } @@ -1146,6 +1160,14 @@ const KMemoryManager& KernelCore::MemoryManager() const { return *impl->memory_manager; } +KSystemResource& KernelCore::GetAppSystemResource() { + return *impl->app_system_resource; +} + +const KSystemResource& KernelCore::GetAppSystemResource() const { + return *impl->app_system_resource; +} + KSystemResource& KernelCore::GetSystemSystemResource() { return *impl->sys_system_resource; } @@ -1194,32 +1216,39 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const { return *impl->hidbus_shared_mem; } -void KernelCore::Suspend(bool suspended) { +void KernelCore::SuspendApplication(bool suspended) { const bool should_suspend{exception_exited || suspended}; const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; - std::vector<KScopedAutoObject<KThread>> process_threads; - { - KScopedSchedulerLock sl{*this}; + // Get the application process. + KScopedAutoObject<KProcess> process = ApplicationProcess(); + if (process.IsNull()) { + return; + } - if (auto* process = CurrentProcess(); process != nullptr) { - process->SetActivity(activity); + // Set the new activity. + process->SetActivity(activity); - if (!should_suspend) { - // Runnable now; no need to wait. - return; - } + // Wait for process execution to stop. + bool must_wait{should_suspend}; - for (auto* thread : process->GetThreadList()) { - process_threads.emplace_back(thread); + // KernelCore::SuspendApplication must be called from locked context, + // or we could race another call to SetActivity, interfering with waiting. + while (must_wait) { + KScopedSchedulerLock sl{*this}; + + // Assume that all threads have finished running. + must_wait = false; + + for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { + if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == + process.GetPointerUnsafe()) { + // A thread has not finished running yet. + // Continue waiting. + must_wait = true; } } } - - // Wait for execution to stop. - for (auto& thread : process_threads) { - thread->WaitUntilSuspended(); - } } void KernelCore::ShutdownCores() { @@ -1238,9 +1267,9 @@ bool KernelCore::IsShuttingDown() const { return impl->IsShuttingDown(); } -void KernelCore::ExceptionalExit() { +void KernelCore::ExceptionalExitApplication() { exception_exited = true; - Suspend(true); + SuspendApplication(true); } void KernelCore::EnterSVCProfile() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 8d22f8d2c..6e0668f7f 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -35,6 +35,7 @@ class GlobalSchedulerContext; class KAutoObjectWithListContainer; class KClientSession; class KDebug; +class KDeviceAddressSpace; class KDynamicPageManager; class KEvent; class KEventInfo; @@ -43,6 +44,8 @@ class KHardwareTimer; class KLinkedListNode; class KMemoryLayout; class KMemoryManager; +class KObjectName; +class KObjectNameGlobalData; class KPageBuffer; class KPageBufferSlabHeap; class KPort; @@ -130,17 +133,17 @@ public: /// Adds the given shared pointer to an internal list of active processes. void AppendNewProcess(KProcess* process); - /// Makes the given process the new current process. - void MakeCurrentProcess(KProcess* process); + /// Makes the given process the new application process. + void MakeApplicationProcess(KProcess* process); - /// Retrieves a pointer to the current process. - KProcess* CurrentProcess(); + /// Retrieves a pointer to the application process. + KProcess* ApplicationProcess(); - /// Retrieves a const pointer to the current process. - const KProcess* CurrentProcess() const; + /// Retrieves a const pointer to the application process. + const KProcess* ApplicationProcess() const; - /// Closes the current process. - void CloseCurrentProcess(); + /// Closes the application process. + void CloseApplicationProcess(); /// Retrieves the list of processes. const std::vector<KProcess*>& GetProcessList() const; @@ -239,12 +242,21 @@ public: /// Register the current thread as a non CPU core thread. void RegisterHostThread(KThread* existing_thread = nullptr); + /// Gets global data for KObjectName. + KObjectNameGlobalData& ObjectNameGlobalData(); + /// Gets the virtual memory manager for the kernel. KMemoryManager& MemoryManager(); /// Gets the virtual memory manager for the kernel. const KMemoryManager& MemoryManager() const; + /// Gets the application resource manager. + KSystemResource& GetAppSystemResource(); + + /// Gets the application resource manager. + const KSystemResource& GetAppSystemResource() const; + /// Gets the system resource manager. KSystemResource& GetSystemSystemResource(); @@ -281,11 +293,11 @@ public: /// Gets the shared memory object for HIDBus services. const Kernel::KSharedMemory& GetHidBusSharedMem() const; - /// Suspend/unsuspend all processes. - void Suspend(bool suspend); + /// Suspend/unsuspend application process. + void SuspendApplication(bool suspend); - /// Exceptional exit all processes. - void ExceptionalExit(); + /// Exceptional exit application process. + void ExceptionalExitApplication(); /// Notify emulated CPU cores to shut down. void ShutdownCores(); @@ -359,10 +371,14 @@ public: return slab_heap_container->transfer_memory; } else if constexpr (std::is_same_v<T, KCodeMemory>) { return slab_heap_container->code_memory; + } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) { + return slab_heap_container->device_address_space; } else if constexpr (std::is_same_v<T, KPageBuffer>) { return slab_heap_container->page_buffer; } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { return slab_heap_container->thread_local_page; + } else if constexpr (std::is_same_v<T, KObjectName>) { + return slab_heap_container->object_name; } else if constexpr (std::is_same_v<T, KSessionRequest>) { return slab_heap_container->session_request; } else if constexpr (std::is_same_v<T, KSecureSystemResource>) { @@ -431,8 +447,10 @@ private: KSlabHeap<KThread> thread; KSlabHeap<KTransferMemory> transfer_memory; KSlabHeap<KCodeMemory> code_memory; + KSlabHeap<KDeviceAddressSpace> device_address_space; KSlabHeap<KPageBuffer> page_buffer; KSlabHeap<KThreadLocalPage> thread_local_page; + KSlabHeap<KObjectName> object_name; KSlabHeap<KSessionRequest> session_request; KSlabHeap<KSecureSystemResource> secure_system_resource; KSlabHeap<KEventInfo> event_info; diff --git a/src/core/hle/kernel/memory_types.h b/src/core/hle/kernel/memory_types.h index 3975507bd..92b8b37ac 100644 --- a/src/core/hle/kernel/memory_types.h +++ b/src/core/hle/kernel/memory_types.h @@ -14,4 +14,7 @@ constexpr std::size_t PageSize{1 << PageBits}; using Page = std::array<u8, PageSize>; +using KPhysicalAddress = PAddr; +using KProcessAddress = VAddr; + } // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index fb2ba4c6b..fb8e7933e 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -3,6 +3,7 @@ #pragma once +#include <condition_variable> #include <cstddef> #include <memory> #include <mutex> 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(); diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index 13f061b83..36e619959 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h @@ -1,16 +1,536 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#pragma once +// This file is automatically generated using svc_generator.py. -#include "common/common_types.h" +#pragma once namespace Core { class System; } +#include "common/common_types.h" +#include "core/hle/kernel/svc_types.h" +#include "core/hle/result.h" + namespace Kernel::Svc { -void Call(Core::System& system, u32 immediate); +// clang-format off +Result SetHeapSize(Core::System& system, uintptr_t* out_address, uint64_t size); +Result SetMemoryPermission(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm); +Result SetMemoryAttribute(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr); +Result MapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result UnmapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result QueryMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, uint64_t address); +void ExitProcess(Core::System& system); +Result CreateThread(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg, uint64_t stack_bottom, int32_t priority, int32_t core_id); +Result StartThread(Core::System& system, Handle thread_handle); +void ExitThread(Core::System& system); +void SleepThread(Core::System& system, int64_t ns); +Result GetThreadPriority(Core::System& system, int32_t* out_priority, Handle thread_handle); +Result SetThreadPriority(Core::System& system, Handle thread_handle, int32_t priority); +Result GetThreadCoreMask(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle); +Result SetThreadCoreMask(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask); +int32_t GetCurrentProcessorNumber(Core::System& system); +Result SignalEvent(Core::System& system, Handle event_handle); +Result ClearEvent(Core::System& system, Handle event_handle); +Result MapSharedMemory(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size, MemoryPermission map_perm); +Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size); +Result CreateTransferMemory(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size, MemoryPermission map_perm); +Result CloseHandle(Core::System& system, Handle handle); +Result ResetSignal(Core::System& system, Handle handle); +Result WaitSynchronization(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, int64_t timeout_ns); +Result CancelSynchronization(Core::System& system, Handle handle); +Result ArbitrateLock(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag); +Result ArbitrateUnlock(Core::System& system, uint64_t address); +Result WaitProcessWideKeyAtomic(Core::System& system, uint64_t address, uint64_t cv_key, uint32_t tag, int64_t timeout_ns); +void SignalProcessWideKey(Core::System& system, uint64_t cv_key, int32_t count); +int64_t GetSystemTick(Core::System& system); +Result ConnectToNamedPort(Core::System& system, Handle* out_handle, uint64_t name); +Result SendSyncRequest(Core::System& system, Handle session_handle); +Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle); +Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle); +Result GetProcessId(Core::System& system, uint64_t* out_process_id, Handle process_handle); +Result GetThreadId(Core::System& system, uint64_t* out_thread_id, Handle thread_handle); +void Break(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size); +Result OutputDebugString(Core::System& system, uint64_t debug_str, uint64_t len); +void ReturnFromException(Core::System& system, Result result); +Result GetInfo(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype); +void FlushEntireDataCache(Core::System& system); +Result FlushDataCache(Core::System& system, uint64_t address, uint64_t size); +Result MapPhysicalMemory(Core::System& system, uint64_t address, uint64_t size); +Result UnmapPhysicalMemory(Core::System& system, uint64_t address, uint64_t size); +Result GetDebugFutureThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns); +Result GetLastThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, uintptr_t* out_tls_address, uint32_t* out_flags); +Result GetResourceLimitLimitValue(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which); +Result GetResourceLimitCurrentValue(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which); +Result SetThreadActivity(Core::System& system, Handle thread_handle, ThreadActivity thread_activity); +Result GetThreadContext3(Core::System& system, uint64_t out_context, Handle thread_handle); +Result WaitForAddress(Core::System& system, uint64_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns); +Result SignalToAddress(Core::System& system, uint64_t address, SignalType signal_type, int32_t value, int32_t count); +void SynchronizePreemptionState(Core::System& system); +Result GetResourceLimitPeakValue(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which); +Result CreateIoPool(Core::System& system, Handle* out_handle, IoPoolType which); +Result CreateIoRegion(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint64_t size, MemoryMapping mapping, MemoryPermission perm); +void KernelDebug(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2); +void ChangeKernelTraceState(Core::System& system, KernelTraceState kern_trace_state); +Result CreateSession(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint64_t name); +Result AcceptSession(Core::System& system, Handle* out_handle, Handle port); +Result ReplyAndReceive(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns); +Result ReplyAndReceiveWithUserBuffer(Core::System& system, 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); +Result CreateEvent(Core::System& system, Handle* out_write_handle, Handle* out_read_handle); +Result MapIoRegion(Core::System& system, Handle io_region, uint64_t address, uint64_t size, MemoryPermission perm); +Result UnmapIoRegion(Core::System& system, Handle io_region, uint64_t address, uint64_t size); +Result MapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size); +Result UnmapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size); +Result SetUnsafeLimit(Core::System& system, uint64_t limit); +Result CreateCodeMemory(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size); +Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm); +void SleepSystem(Core::System& system); +Result ReadWriteRegister(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value); +Result SetProcessActivity(Core::System& system, Handle process_handle, ProcessActivity process_activity); +Result CreateSharedMemory(Core::System& system, Handle* out_handle, uint64_t size, MemoryPermission owner_perm, MemoryPermission remote_perm); +Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, MemoryPermission owner_perm); +Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size); +Result CreateInterruptEvent(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type); +Result QueryPhysicalAddress(Core::System& system, lp64::PhysicalMemoryInfo* out_info, uint64_t address); +Result QueryIoMapping(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, uint64_t physical_address, uint64_t size); +Result CreateDeviceAddressSpace(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size); +Result AttachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle); +Result DetachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle); +Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option); +Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option); +Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address); +Result InvalidateProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result StoreProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result FlushProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result DebugActiveProcess(Core::System& system, Handle* out_handle, uint64_t process_id); +Result BreakDebugProcess(Core::System& system, Handle debug_handle); +Result TerminateDebugProcess(Core::System& system, Handle debug_handle); +Result GetDebugEvent(Core::System& system, uint64_t out_info, Handle debug_handle); +Result ContinueDebugEvent(Core::System& system, Handle debug_handle, uint32_t flags, uint64_t thread_ids, int32_t num_thread_ids); +Result GetProcessList(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids, int32_t max_out_count); +Result GetThreadList(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids, int32_t max_out_count, Handle debug_handle); +Result GetDebugThreadContext(Core::System& system, uint64_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags); +Result SetDebugThreadContext(Core::System& system, Handle debug_handle, uint64_t thread_id, uint64_t context, uint32_t context_flags); +Result QueryDebugProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address); +Result ReadDebugProcessMemory(Core::System& system, uint64_t buffer, Handle debug_handle, uint64_t address, uint64_t size); +Result WriteDebugProcessMemory(Core::System& system, Handle debug_handle, uint64_t buffer, uint64_t address, uint64_t size); +Result SetHardwareBreakPoint(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value); +Result GetDebugThreadParam(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param); +Result GetSystemInfo(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype); +Result CreatePort(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint64_t name); +Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name, int32_t max_sessions); +Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port); +Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm); +Result MapProcessMemory(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size); +Result UnmapProcessMemory(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size); +Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address); +Result MapProcessCodeMemory(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result CreateProcess(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, int32_t num_caps); +Result StartProcess(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size); +Result TerminateProcess(Core::System& system, Handle process_handle); +Result GetProcessInfo(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type); +Result CreateResourceLimit(Core::System& system, Handle* out_handle); +Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value); +Result MapInsecureMemory(Core::System& system, uint64_t address, uint64_t size); +Result UnmapInsecureMemory(Core::System& system, uint64_t address, uint64_t size); + +Result SetHeapSize64From32(Core::System& system, uintptr_t* out_address, uint32_t size); +Result SetMemoryPermission64From32(Core::System& system, uint32_t address, uint32_t size, MemoryPermission perm); +Result SetMemoryAttribute64From32(Core::System& system, uint32_t address, uint32_t size, uint32_t mask, uint32_t attr); +Result MapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, uint32_t size); +Result UnmapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, uint32_t size); +Result QueryMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, uint32_t address); +void ExitProcess64From32(Core::System& system); +Result CreateThread64From32(Core::System& system, Handle* out_handle, uint32_t func, uint32_t arg, uint32_t stack_bottom, int32_t priority, int32_t core_id); +Result StartThread64From32(Core::System& system, Handle thread_handle); +void ExitThread64From32(Core::System& system); +void SleepThread64From32(Core::System& system, int64_t ns); +Result GetThreadPriority64From32(Core::System& system, int32_t* out_priority, Handle thread_handle); +Result SetThreadPriority64From32(Core::System& system, Handle thread_handle, int32_t priority); +Result GetThreadCoreMask64From32(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle); +Result SetThreadCoreMask64From32(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask); +int32_t GetCurrentProcessorNumber64From32(Core::System& system); +Result SignalEvent64From32(Core::System& system, Handle event_handle); +Result ClearEvent64From32(Core::System& system, Handle event_handle); +Result MapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, uint32_t size, MemoryPermission map_perm); +Result UnmapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, uint32_t size); +Result CreateTransferMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, uint32_t size, MemoryPermission map_perm); +Result CloseHandle64From32(Core::System& system, Handle handle); +Result ResetSignal64From32(Core::System& system, Handle handle); +Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles, int32_t num_handles, int64_t timeout_ns); +Result CancelSynchronization64From32(Core::System& system, Handle handle); +Result ArbitrateLock64From32(Core::System& system, Handle thread_handle, uint32_t address, uint32_t tag); +Result ArbitrateUnlock64From32(Core::System& system, uint32_t address); +Result WaitProcessWideKeyAtomic64From32(Core::System& system, uint32_t address, uint32_t cv_key, uint32_t tag, int64_t timeout_ns); +void SignalProcessWideKey64From32(Core::System& system, uint32_t cv_key, int32_t count); +int64_t GetSystemTick64From32(Core::System& system); +Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name); +Result SendSyncRequest64From32(Core::System& system, Handle session_handle); +Result SendSyncRequestWithUserBuffer64From32(Core::System& system, uint32_t message_buffer, uint32_t message_buffer_size, Handle session_handle); +Result SendAsyncRequestWithUserBuffer64From32(Core::System& system, Handle* out_event_handle, uint32_t message_buffer, uint32_t message_buffer_size, Handle session_handle); +Result GetProcessId64From32(Core::System& system, uint64_t* out_process_id, Handle process_handle); +Result GetThreadId64From32(Core::System& system, uint64_t* out_thread_id, Handle thread_handle); +void Break64From32(Core::System& system, BreakReason break_reason, uint32_t arg, uint32_t size); +Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint32_t len); +void ReturnFromException64From32(Core::System& system, Result result); +Result GetInfo64From32(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype); +void FlushEntireDataCache64From32(Core::System& system); +Result FlushDataCache64From32(Core::System& system, uint32_t address, uint32_t size); +Result MapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size); +Result UnmapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size); +Result GetDebugFutureThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns); +Result GetLastThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, uintptr_t* out_tls_address, uint32_t* out_flags); +Result GetResourceLimitLimitValue64From32(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which); +Result GetResourceLimitCurrentValue64From32(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which); +Result SetThreadActivity64From32(Core::System& system, Handle thread_handle, ThreadActivity thread_activity); +Result GetThreadContext364From32(Core::System& system, uint32_t out_context, Handle thread_handle); +Result WaitForAddress64From32(Core::System& system, uint32_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns); +Result SignalToAddress64From32(Core::System& system, uint32_t address, SignalType signal_type, int32_t value, int32_t count); +void SynchronizePreemptionState64From32(Core::System& system); +Result GetResourceLimitPeakValue64From32(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which); +Result CreateIoPool64From32(Core::System& system, Handle* out_handle, IoPoolType which); +Result CreateIoRegion64From32(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint32_t size, MemoryMapping mapping, MemoryPermission perm); +void KernelDebug64From32(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2); +void ChangeKernelTraceState64From32(Core::System& system, KernelTraceState kern_trace_state); +Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint32_t name); +Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port); +Result ReplyAndReceive64From32(Core::System& system, int32_t* out_index, uint32_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns); +Result ReplyAndReceiveWithUserBuffer64From32(Core::System& system, 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); +Result CreateEvent64From32(Core::System& system, Handle* out_write_handle, Handle* out_read_handle); +Result MapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size, MemoryPermission perm); +Result UnmapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size); +Result MapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size); +Result UnmapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size); +Result SetUnsafeLimit64From32(Core::System& system, uint32_t limit); +Result CreateCodeMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, uint32_t size); +Result ControlCodeMemory64From32(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm); +void SleepSystem64From32(Core::System& system); +Result ReadWriteRegister64From32(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value); +Result SetProcessActivity64From32(Core::System& system, Handle process_handle, ProcessActivity process_activity); +Result CreateSharedMemory64From32(Core::System& system, Handle* out_handle, uint32_t size, MemoryPermission owner_perm, MemoryPermission remote_perm); +Result MapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, uint32_t size, MemoryPermission owner_perm); +Result UnmapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, uint32_t size); +Result CreateInterruptEvent64From32(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type); +Result QueryPhysicalAddress64From32(Core::System& system, ilp32::PhysicalMemoryInfo* out_info, uint32_t address); +Result QueryIoMapping64From32(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, uint64_t physical_address, uint32_t size); +Result CreateDeviceAddressSpace64From32(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size); +Result AttachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, Handle das_handle); +Result DetachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, Handle das_handle); +Result MapDeviceAddressSpaceByForce64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address, uint32_t option); +Result MapDeviceAddressSpaceAligned64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address, uint32_t option); +Result UnmapDeviceAddressSpace64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address); +Result InvalidateProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result StoreProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result FlushProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result DebugActiveProcess64From32(Core::System& system, Handle* out_handle, uint64_t process_id); +Result BreakDebugProcess64From32(Core::System& system, Handle debug_handle); +Result TerminateDebugProcess64From32(Core::System& system, Handle debug_handle); +Result GetDebugEvent64From32(Core::System& system, uint32_t out_info, Handle debug_handle); +Result ContinueDebugEvent64From32(Core::System& system, Handle debug_handle, uint32_t flags, uint32_t thread_ids, int32_t num_thread_ids); +Result GetProcessList64From32(Core::System& system, int32_t* out_num_processes, uint32_t out_process_ids, int32_t max_out_count); +Result GetThreadList64From32(Core::System& system, int32_t* out_num_threads, uint32_t out_thread_ids, int32_t max_out_count, Handle debug_handle); +Result GetDebugThreadContext64From32(Core::System& system, uint32_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags); +Result SetDebugThreadContext64From32(Core::System& system, Handle debug_handle, uint64_t thread_id, uint32_t context, uint32_t context_flags); +Result QueryDebugProcessMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint32_t address); +Result ReadDebugProcessMemory64From32(Core::System& system, uint32_t buffer, Handle debug_handle, uint32_t address, uint32_t size); +Result WriteDebugProcessMemory64From32(Core::System& system, Handle debug_handle, uint32_t buffer, uint32_t address, uint32_t size); +Result SetHardwareBreakPoint64From32(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value); +Result GetDebugThreadParam64From32(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param); +Result GetSystemInfo64From32(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype); +Result CreatePort64From32(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint32_t name); +Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name, int32_t max_sessions); +Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port); +Result SetProcessMemoryPermission64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm); +Result MapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, uint64_t src_address, uint32_t size); +Result UnmapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, uint64_t src_address, uint32_t size); +Result QueryProcessMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address); +Result MapProcessCodeMemory64From32(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result UnmapProcessCodeMemory64From32(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result CreateProcess64From32(Core::System& system, Handle* out_handle, uint32_t parameters, uint32_t caps, int32_t num_caps); +Result StartProcess64From32(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size); +Result TerminateProcess64From32(Core::System& system, Handle process_handle); +Result GetProcessInfo64From32(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type); +Result CreateResourceLimit64From32(Core::System& system, Handle* out_handle); +Result SetResourceLimitLimitValue64From32(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value); +Result MapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size); +Result UnmapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size); + +Result SetHeapSize64(Core::System& system, uintptr_t* out_address, uint64_t size); +Result SetMemoryPermission64(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm); +Result SetMemoryAttribute64(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr); +Result MapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result UnmapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result QueryMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, uint64_t address); +void ExitProcess64(Core::System& system); +Result CreateThread64(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg, uint64_t stack_bottom, int32_t priority, int32_t core_id); +Result StartThread64(Core::System& system, Handle thread_handle); +void ExitThread64(Core::System& system); +void SleepThread64(Core::System& system, int64_t ns); +Result GetThreadPriority64(Core::System& system, int32_t* out_priority, Handle thread_handle); +Result SetThreadPriority64(Core::System& system, Handle thread_handle, int32_t priority); +Result GetThreadCoreMask64(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle); +Result SetThreadCoreMask64(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask); +int32_t GetCurrentProcessorNumber64(Core::System& system); +Result SignalEvent64(Core::System& system, Handle event_handle); +Result ClearEvent64(Core::System& system, Handle event_handle); +Result MapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size, MemoryPermission map_perm); +Result UnmapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size); +Result CreateTransferMemory64(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size, MemoryPermission map_perm); +Result CloseHandle64(Core::System& system, Handle handle); +Result ResetSignal64(Core::System& system, Handle handle); +Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, int64_t timeout_ns); +Result CancelSynchronization64(Core::System& system, Handle handle); +Result ArbitrateLock64(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag); +Result ArbitrateUnlock64(Core::System& system, uint64_t address); +Result WaitProcessWideKeyAtomic64(Core::System& system, uint64_t address, uint64_t cv_key, uint32_t tag, int64_t timeout_ns); +void SignalProcessWideKey64(Core::System& system, uint64_t cv_key, int32_t count); +int64_t GetSystemTick64(Core::System& system); +Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name); +Result SendSyncRequest64(Core::System& system, Handle session_handle); +Result SendSyncRequestWithUserBuffer64(Core::System& system, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle); +Result SendAsyncRequestWithUserBuffer64(Core::System& system, Handle* out_event_handle, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle); +Result GetProcessId64(Core::System& system, uint64_t* out_process_id, Handle process_handle); +Result GetThreadId64(Core::System& system, uint64_t* out_thread_id, Handle thread_handle); +void Break64(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size); +Result OutputDebugString64(Core::System& system, uint64_t debug_str, uint64_t len); +void ReturnFromException64(Core::System& system, Result result); +Result GetInfo64(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype); +void FlushEntireDataCache64(Core::System& system); +Result FlushDataCache64(Core::System& system, uint64_t address, uint64_t size); +Result MapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size); +Result UnmapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size); +Result GetDebugFutureThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns); +Result GetLastThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, uintptr_t* out_tls_address, uint32_t* out_flags); +Result GetResourceLimitLimitValue64(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which); +Result GetResourceLimitCurrentValue64(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which); +Result SetThreadActivity64(Core::System& system, Handle thread_handle, ThreadActivity thread_activity); +Result GetThreadContext364(Core::System& system, uint64_t out_context, Handle thread_handle); +Result WaitForAddress64(Core::System& system, uint64_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns); +Result SignalToAddress64(Core::System& system, uint64_t address, SignalType signal_type, int32_t value, int32_t count); +void SynchronizePreemptionState64(Core::System& system); +Result GetResourceLimitPeakValue64(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which); +Result CreateIoPool64(Core::System& system, Handle* out_handle, IoPoolType which); +Result CreateIoRegion64(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint64_t size, MemoryMapping mapping, MemoryPermission perm); +void KernelDebug64(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2); +void ChangeKernelTraceState64(Core::System& system, KernelTraceState kern_trace_state); +Result CreateSession64(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint64_t name); +Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port); +Result ReplyAndReceive64(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns); +Result ReplyAndReceiveWithUserBuffer64(Core::System& system, 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); +Result CreateEvent64(Core::System& system, Handle* out_write_handle, Handle* out_read_handle); +Result MapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size, MemoryPermission perm); +Result UnmapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size); +Result MapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size); +Result UnmapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size); +Result SetUnsafeLimit64(Core::System& system, uint64_t limit); +Result CreateCodeMemory64(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size); +Result ControlCodeMemory64(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm); +void SleepSystem64(Core::System& system); +Result ReadWriteRegister64(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value); +Result SetProcessActivity64(Core::System& system, Handle process_handle, ProcessActivity process_activity); +Result CreateSharedMemory64(Core::System& system, Handle* out_handle, uint64_t size, MemoryPermission owner_perm, MemoryPermission remote_perm); +Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, MemoryPermission owner_perm); +Result UnmapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size); +Result CreateInterruptEvent64(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type); +Result QueryPhysicalAddress64(Core::System& system, lp64::PhysicalMemoryInfo* out_info, uint64_t address); +Result QueryIoMapping64(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, uint64_t physical_address, uint64_t size); +Result CreateDeviceAddressSpace64(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size); +Result AttachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle); +Result DetachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle); +Result MapDeviceAddressSpaceByForce64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option); +Result MapDeviceAddressSpaceAligned64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option); +Result UnmapDeviceAddressSpace64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address); +Result InvalidateProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result StoreProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result FlushProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size); +Result DebugActiveProcess64(Core::System& system, Handle* out_handle, uint64_t process_id); +Result BreakDebugProcess64(Core::System& system, Handle debug_handle); +Result TerminateDebugProcess64(Core::System& system, Handle debug_handle); +Result GetDebugEvent64(Core::System& system, uint64_t out_info, Handle debug_handle); +Result ContinueDebugEvent64(Core::System& system, Handle debug_handle, uint32_t flags, uint64_t thread_ids, int32_t num_thread_ids); +Result GetProcessList64(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids, int32_t max_out_count); +Result GetThreadList64(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids, int32_t max_out_count, Handle debug_handle); +Result GetDebugThreadContext64(Core::System& system, uint64_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags); +Result SetDebugThreadContext64(Core::System& system, Handle debug_handle, uint64_t thread_id, uint64_t context, uint32_t context_flags); +Result QueryDebugProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address); +Result ReadDebugProcessMemory64(Core::System& system, uint64_t buffer, Handle debug_handle, uint64_t address, uint64_t size); +Result WriteDebugProcessMemory64(Core::System& system, Handle debug_handle, uint64_t buffer, uint64_t address, uint64_t size); +Result SetHardwareBreakPoint64(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value); +Result GetDebugThreadParam64(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param); +Result GetSystemInfo64(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype); +Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint64_t name); +Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name, int32_t max_sessions); +Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port); +Result SetProcessMemoryPermission64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm); +Result MapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size); +Result UnmapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size); +Result QueryProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address); +Result MapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result UnmapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size); +Result CreateProcess64(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, int32_t num_caps); +Result StartProcess64(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size); +Result TerminateProcess64(Core::System& system, Handle process_handle); +Result GetProcessInfo64(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type); +Result CreateResourceLimit64(Core::System& system, Handle* out_handle); +Result SetResourceLimitLimitValue64(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value); +Result MapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size); +Result UnmapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size); + +enum class SvcId : u32 { + SetHeapSize = 0x1, + SetMemoryPermission = 0x2, + SetMemoryAttribute = 0x3, + MapMemory = 0x4, + UnmapMemory = 0x5, + QueryMemory = 0x6, + ExitProcess = 0x7, + CreateThread = 0x8, + StartThread = 0x9, + ExitThread = 0xa, + SleepThread = 0xb, + GetThreadPriority = 0xc, + SetThreadPriority = 0xd, + GetThreadCoreMask = 0xe, + SetThreadCoreMask = 0xf, + GetCurrentProcessorNumber = 0x10, + SignalEvent = 0x11, + ClearEvent = 0x12, + MapSharedMemory = 0x13, + UnmapSharedMemory = 0x14, + CreateTransferMemory = 0x15, + CloseHandle = 0x16, + ResetSignal = 0x17, + WaitSynchronization = 0x18, + CancelSynchronization = 0x19, + ArbitrateLock = 0x1a, + ArbitrateUnlock = 0x1b, + WaitProcessWideKeyAtomic = 0x1c, + SignalProcessWideKey = 0x1d, + GetSystemTick = 0x1e, + ConnectToNamedPort = 0x1f, + SendSyncRequestLight = 0x20, + SendSyncRequest = 0x21, + SendSyncRequestWithUserBuffer = 0x22, + SendAsyncRequestWithUserBuffer = 0x23, + GetProcessId = 0x24, + GetThreadId = 0x25, + Break = 0x26, + OutputDebugString = 0x27, + ReturnFromException = 0x28, + GetInfo = 0x29, + FlushEntireDataCache = 0x2a, + FlushDataCache = 0x2b, + MapPhysicalMemory = 0x2c, + UnmapPhysicalMemory = 0x2d, + GetDebugFutureThreadInfo = 0x2e, + GetLastThreadInfo = 0x2f, + GetResourceLimitLimitValue = 0x30, + GetResourceLimitCurrentValue = 0x31, + SetThreadActivity = 0x32, + GetThreadContext3 = 0x33, + WaitForAddress = 0x34, + SignalToAddress = 0x35, + SynchronizePreemptionState = 0x36, + GetResourceLimitPeakValue = 0x37, + CreateIoPool = 0x39, + CreateIoRegion = 0x3a, + KernelDebug = 0x3c, + ChangeKernelTraceState = 0x3d, + CreateSession = 0x40, + AcceptSession = 0x41, + ReplyAndReceiveLight = 0x42, + ReplyAndReceive = 0x43, + ReplyAndReceiveWithUserBuffer = 0x44, + CreateEvent = 0x45, + MapIoRegion = 0x46, + UnmapIoRegion = 0x47, + MapPhysicalMemoryUnsafe = 0x48, + UnmapPhysicalMemoryUnsafe = 0x49, + SetUnsafeLimit = 0x4a, + CreateCodeMemory = 0x4b, + ControlCodeMemory = 0x4c, + SleepSystem = 0x4d, + ReadWriteRegister = 0x4e, + SetProcessActivity = 0x4f, + CreateSharedMemory = 0x50, + MapTransferMemory = 0x51, + UnmapTransferMemory = 0x52, + CreateInterruptEvent = 0x53, + QueryPhysicalAddress = 0x54, + QueryIoMapping = 0x55, + CreateDeviceAddressSpace = 0x56, + AttachDeviceAddressSpace = 0x57, + DetachDeviceAddressSpace = 0x58, + MapDeviceAddressSpaceByForce = 0x59, + MapDeviceAddressSpaceAligned = 0x5a, + UnmapDeviceAddressSpace = 0x5c, + InvalidateProcessDataCache = 0x5d, + StoreProcessDataCache = 0x5e, + FlushProcessDataCache = 0x5f, + DebugActiveProcess = 0x60, + BreakDebugProcess = 0x61, + TerminateDebugProcess = 0x62, + GetDebugEvent = 0x63, + ContinueDebugEvent = 0x64, + GetProcessList = 0x65, + GetThreadList = 0x66, + GetDebugThreadContext = 0x67, + SetDebugThreadContext = 0x68, + QueryDebugProcessMemory = 0x69, + ReadDebugProcessMemory = 0x6a, + WriteDebugProcessMemory = 0x6b, + SetHardwareBreakPoint = 0x6c, + GetDebugThreadParam = 0x6d, + GetSystemInfo = 0x6f, + CreatePort = 0x70, + ManageNamedPort = 0x71, + ConnectToPort = 0x72, + SetProcessMemoryPermission = 0x73, + MapProcessMemory = 0x74, + UnmapProcessMemory = 0x75, + QueryProcessMemory = 0x76, + MapProcessCodeMemory = 0x77, + UnmapProcessCodeMemory = 0x78, + CreateProcess = 0x79, + StartProcess = 0x7a, + TerminateProcess = 0x7b, + GetProcessInfo = 0x7c, + CreateResourceLimit = 0x7d, + SetResourceLimitLimitValue = 0x7e, + CallSecureMonitor = 0x7f, + MapInsecureMemory = 0x90, + UnmapInsecureMemory = 0x91, +}; +// clang-format on + +// Custom ABI. +Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args); +Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args); +Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args); + +Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args); +Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args); +Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args); + +void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args); +void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args); +void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args); + +// Defined in svc_light_ipc.cpp. +void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system); +void SvcWrap_ReplyAndReceiveLight64(Core::System& system); + +void SvcWrap_SendSyncRequestLight64From32(Core::System& system); +void SvcWrap_SendSyncRequestLight64(Core::System& system); + +// Defined in svc_secure_monitor_call.cpp. +void SvcWrap_CallSecureMonitor64From32(Core::System& system); +void SvcWrap_CallSecureMonitor64(Core::System& system); + +// Perform a supervisor call by index. +void Call(Core::System& system, u32 imm); } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_activity.cpp b/src/core/hle/kernel/svc/svc_activity.cpp new file mode 100644 index 000000000..63bc08555 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_activity.cpp @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +/// Sets the thread activity +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); + + // Validate the activity. + static constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { + return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; + }; + R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue); + + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Check that the activity is being set on a non-current thread for the current process. + R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(system.Kernel()), + ResultInvalidHandle); + R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy); + + // Set the activity. + R_TRY(thread->SetActivity(thread_activity)); + + return ResultSuccess; +} + +Result SetProcessActivity(Core::System& system, Handle process_handle, + ProcessActivity process_activity) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SetThreadActivity64(Core::System& system, Handle thread_handle, + ThreadActivity thread_activity) { + return SetThreadActivity(system, thread_handle, thread_activity); +} + +Result SetProcessActivity64(Core::System& system, Handle process_handle, + ProcessActivity process_activity) { + return SetProcessActivity(system, process_handle, process_activity); +} + +Result SetThreadActivity64From32(Core::System& system, Handle thread_handle, + ThreadActivity thread_activity) { + return SetThreadActivity(system, thread_handle, thread_activity); +} + +Result SetProcessActivity64From32(Core::System& system, Handle process_handle, + ProcessActivity process_activity) { + return SetProcessActivity(system, process_handle, process_activity); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_address_arbiter.cpp b/src/core/hle/kernel/svc/svc_address_arbiter.cpp new file mode 100644 index 000000000..998bd3f22 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_address_arbiter.cpp @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/kernel/svc_types.h" + +namespace Kernel::Svc { +namespace { + +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; + } +} + +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; + } +} + +} // namespace + +// Wait for an address (via Address Arbiter) +Result WaitForAddress(Core::System& system, VAddr address, 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); + + // 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; + } + + // 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; + } + + return GetCurrentProcess(system.Kernel()).WaitAddressArbiter(address, arb_type, value, timeout); +} + +// Signals to an address (via Address Arbiter) +Result SignalToAddress(Core::System& system, VAddr address, 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); + + // 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; + } + + return GetCurrentProcess(system.Kernel()) + .SignalAddressArbiter(address, signal_type, value, count); +} + +Result WaitForAddress64(Core::System& system, VAddr address, ArbitrationType arb_type, s32 value, + s64 timeout_ns) { + return WaitForAddress(system, address, arb_type, value, timeout_ns); +} + +Result SignalToAddress64(Core::System& system, VAddr address, SignalType signal_type, s32 value, + s32 count) { + return SignalToAddress(system, address, signal_type, value, count); +} + +Result WaitForAddress64From32(Core::System& system, u32 address, ArbitrationType arb_type, + s32 value, s64 timeout_ns) { + return WaitForAddress(system, address, arb_type, value, timeout_ns); +} + +Result SignalToAddress64From32(Core::System& system, u32 address, SignalType signal_type, s32 value, + s32 count) { + return SignalToAddress(system, address, signal_type, value, count); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_address_translation.cpp b/src/core/hle/kernel/svc/svc_address_translation.cpp new file mode 100644 index 000000000..c25e144cd --- /dev/null +++ b/src/core/hle/kernel/svc/svc_address_translation.cpp @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result QueryPhysicalAddress(Core::System& system, lp64::PhysicalMemoryInfo* out_info, + uint64_t address) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result QueryIoMapping(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, + uint64_t physical_address, uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result QueryPhysicalAddress64(Core::System& system, lp64::PhysicalMemoryInfo* out_info, + uint64_t address) { + R_RETURN(QueryPhysicalAddress(system, out_info, address)); +} + +Result QueryIoMapping64(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, + uint64_t physical_address, uint64_t size) { + R_RETURN(QueryIoMapping(system, out_address, out_size, physical_address, size)); +} + +Result QueryPhysicalAddress64From32(Core::System& system, ilp32::PhysicalMemoryInfo* out_info, + uint32_t address) { + lp64::PhysicalMemoryInfo info{}; + R_TRY(QueryPhysicalAddress(system, std::addressof(info), address)); + + *out_info = { + .physical_address = info.physical_address, + .virtual_address = static_cast<u32>(info.virtual_address), + .size = static_cast<u32>(info.size), + }; + R_SUCCEED(); +} + +Result QueryIoMapping64From32(Core::System& system, uintptr_t* out_address, uintptr_t* out_size, + uint64_t physical_address, uint32_t size) { + R_RETURN(QueryIoMapping(system, reinterpret_cast<uintptr_t*>(out_address), + reinterpret_cast<uintptr_t*>(out_size), physical_address, size)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_cache.cpp b/src/core/hle/kernel/svc/svc_cache.cpp new file mode 100644 index 000000000..598b71da5 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_cache.cpp @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/kernel/svc_types.h" + +namespace Kernel::Svc { + +void FlushEntireDataCache(Core::System& system) { + UNIMPLEMENTED(); +} + +Result FlushDataCache(Core::System& system, VAddr address, size_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result InvalidateProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result StoreProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result FlushProcessDataCache(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 = + GetCurrentProcess(system.Kernel()).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)); +} + +void FlushEntireDataCache64(Core::System& system) { + FlushEntireDataCache(system); +} + +Result FlushDataCache64(Core::System& system, VAddr address, size_t size) { + R_RETURN(FlushDataCache(system, address, size)); +} + +Result InvalidateProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size) { + R_RETURN(InvalidateProcessDataCache(system, process_handle, address, size)); +} + +Result StoreProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size) { + R_RETURN(StoreProcessDataCache(system, process_handle, address, size)); +} + +Result FlushProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size) { + R_RETURN(FlushProcessDataCache(system, process_handle, address, size)); +} + +void FlushEntireDataCache64From32(Core::System& system) { + return FlushEntireDataCache(system); +} + +Result FlushDataCache64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(FlushDataCache(system, address, size)); +} + +Result InvalidateProcessDataCache64From32(Core::System& system, Handle process_handle, + uint64_t address, uint64_t size) { + R_RETURN(InvalidateProcessDataCache(system, process_handle, address, size)); +} + +Result StoreProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size) { + R_RETURN(StoreProcessDataCache(system, process_handle, address, size)); +} + +Result FlushProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size) { + R_RETURN(FlushProcessDataCache(system, process_handle, address, size)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp new file mode 100644 index 000000000..538ff1c71 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_code_memory.cpp @@ -0,0 +1,171 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_code_memory.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { +namespace { + +constexpr bool IsValidMapCodeMemoryPermission(MemoryPermission perm) { + return perm == MemoryPermission::ReadWrite; +} + +constexpr bool IsValidMapToOwnerCodeMemoryPermission(MemoryPermission perm) { + return perm == MemoryPermission::Read || perm == MemoryPermission::ReadExecute; +} + +constexpr bool IsValidUnmapCodeMemoryPermission(MemoryPermission perm) { + return perm == MemoryPermission::None; +} + +constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(MemoryPermission perm) { + return perm == MemoryPermission::None; +} + +} // namespace + +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(); + + // 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); + + // Create the code memory. + + KCodeMemory* code_mem = KCodeMemory::Create(kernel); + R_UNLESS(code_mem != nullptr, ResultOutOfResource); + + // Verify that the region is in range. + R_UNLESS(GetCurrentProcess(system.Kernel()).PageTable().Contains(address, size), + ResultInvalidCurrentMemory); + + // Initialize the code memory. + R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size)); + + // Register the code memory. + KCodeMemory::Register(kernel, code_mem); + + // Add the code memory to the handle table. + R_TRY(GetCurrentProcess(system.Kernel()).GetHandleTable().Add(out, code_mem)); + + code_mem->Close(); + + return ResultSuccess; +} + +Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, + CodeMemoryOperation operation, VAddr address, size_t size, + MemoryPermission perm) { + + 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); + + // 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); + + // Get the code memory from its handle. + KScopedAutoObject code_mem = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KCodeMemory>(code_memory_handle); + R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle); + + // 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. + + // Perform the operation. + switch (operation) { + case CodeMemoryOperation::Map: { + // Check that the region is in range. + R_UNLESS(GetCurrentProcess(system.Kernel()) + .PageTable() + .CanContain(address, size, KMemoryState::CodeOut), + ResultInvalidMemoryRegion); + + // Check the memory permission. + R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Map the memory. + R_TRY(code_mem->Map(address, size)); + } break; + case CodeMemoryOperation::Unmap: { + // Check that the region is in range. + R_UNLESS(GetCurrentProcess(system.Kernel()) + .PageTable() + .CanContain(address, size, KMemoryState::CodeOut), + ResultInvalidMemoryRegion); + + // Check the memory permission. + R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // 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); + + // Check the memory permission. + R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // 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); + + // 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; + } + + return ResultSuccess; +} + +Result CreateCodeMemory64(Core::System& system, Handle* out_handle, uint64_t address, + uint64_t size) { + R_RETURN(CreateCodeMemory(system, out_handle, address, size)); +} + +Result ControlCodeMemory64(Core::System& system, Handle code_memory_handle, + CodeMemoryOperation operation, uint64_t address, uint64_t size, + MemoryPermission perm) { + R_RETURN(ControlCodeMemory(system, code_memory_handle, operation, address, size, perm)); +} + +Result CreateCodeMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, + uint32_t size) { + R_RETURN(CreateCodeMemory(system, out_handle, address, size)); +} + +Result ControlCodeMemory64From32(Core::System& system, Handle code_memory_handle, + CodeMemoryOperation operation, uint64_t address, uint64_t size, + MemoryPermission perm) { + R_RETURN(ControlCodeMemory(system, code_memory_handle, operation, address, size, perm)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_condition_variable.cpp b/src/core/hle/kernel/svc/svc_condition_variable.cpp new file mode 100644 index 000000000..8ad1a0b8f --- /dev/null +++ b/src/core/hle/kernel/svc/svc_condition_variable.cpp @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +/// Wait process wide key atomic +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); + + // 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; + } + + // 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; + } + + // Wait on the condition variable. + return GetCurrentProcess(system.Kernel()) + .WaitConditionVariable(address, Common::AlignDown(cv_key, sizeof(u32)), tag, timeout); +} + +/// Signal process wide key +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); + + // Signal the condition variable. + return GetCurrentProcess(system.Kernel()) + .SignalConditionVariable(Common::AlignDown(cv_key, sizeof(u32)), count); +} + +Result WaitProcessWideKeyAtomic64(Core::System& system, uint64_t address, uint64_t cv_key, + uint32_t tag, int64_t timeout_ns) { + R_RETURN(WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns)); +} + +void SignalProcessWideKey64(Core::System& system, uint64_t cv_key, int32_t count) { + SignalProcessWideKey(system, cv_key, count); +} + +Result WaitProcessWideKeyAtomic64From32(Core::System& system, uint32_t address, uint32_t cv_key, + uint32_t tag, int64_t timeout_ns) { + R_RETURN(WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns)); +} + +void SignalProcessWideKey64From32(Core::System& system, uint32_t cv_key, int32_t count) { + SignalProcessWideKey(system, cv_key, count); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_debug.cpp b/src/core/hle/kernel/svc/svc_debug.cpp new file mode 100644 index 000000000..a14050fa7 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_debug.cpp @@ -0,0 +1,194 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result DebugActiveProcess(Core::System& system, Handle* out_handle, uint64_t process_id) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result BreakDebugProcess(Core::System& system, Handle debug_handle) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result TerminateDebugProcess(Core::System& system, Handle debug_handle) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result GetDebugEvent(Core::System& system, uint64_t out_info, Handle debug_handle) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result ContinueDebugEvent(Core::System& system, Handle debug_handle, uint32_t flags, + uint64_t user_thread_ids, int32_t num_thread_ids) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result GetDebugThreadContext(Core::System& system, uint64_t out_context, Handle debug_handle, + uint64_t thread_id, uint32_t context_flags) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SetDebugThreadContext(Core::System& system, Handle debug_handle, uint64_t thread_id, + uint64_t user_context, uint32_t context_flags) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result QueryDebugProcessMemory(Core::System& system, uint64_t out_memory_info, + PageInfo* out_page_info, Handle debug_handle, uintptr_t address) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result ReadDebugProcessMemory(Core::System& system, uintptr_t buffer, Handle debug_handle, + uintptr_t address, size_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result WriteDebugProcessMemory(Core::System& system, Handle debug_handle, uintptr_t buffer, + uintptr_t address, size_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SetHardwareBreakPoint(Core::System& system, HardwareBreakPointRegisterName name, + uint64_t flags, uint64_t value) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result GetDebugThreadParam(Core::System& system, uint64_t* out_64, uint32_t* out_32, + Handle debug_handle, uint64_t thread_id, DebugThreadParam param) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result DebugActiveProcess64(Core::System& system, Handle* out_handle, uint64_t process_id) { + R_RETURN(DebugActiveProcess(system, out_handle, process_id)); +} + +Result BreakDebugProcess64(Core::System& system, Handle debug_handle) { + R_RETURN(BreakDebugProcess(system, debug_handle)); +} + +Result TerminateDebugProcess64(Core::System& system, Handle debug_handle) { + R_RETURN(TerminateDebugProcess(system, debug_handle)); +} + +Result GetDebugEvent64(Core::System& system, uint64_t out_info, Handle debug_handle) { + R_RETURN(GetDebugEvent(system, out_info, debug_handle)); +} + +Result ContinueDebugEvent64(Core::System& system, Handle debug_handle, uint32_t flags, + uint64_t thread_ids, int32_t num_thread_ids) { + R_RETURN(ContinueDebugEvent(system, debug_handle, flags, thread_ids, num_thread_ids)); +} + +Result GetDebugThreadContext64(Core::System& system, uint64_t out_context, Handle debug_handle, + uint64_t thread_id, uint32_t context_flags) { + R_RETURN(GetDebugThreadContext(system, out_context, debug_handle, thread_id, context_flags)); +} + +Result SetDebugThreadContext64(Core::System& system, Handle debug_handle, uint64_t thread_id, + uint64_t context, uint32_t context_flags) { + R_RETURN(SetDebugThreadContext(system, debug_handle, thread_id, context, context_flags)); +} + +Result QueryDebugProcessMemory64(Core::System& system, uint64_t out_memory_info, + PageInfo* out_page_info, Handle debug_handle, uint64_t address) { + R_RETURN( + QueryDebugProcessMemory(system, out_memory_info, out_page_info, debug_handle, address)); +} + +Result ReadDebugProcessMemory64(Core::System& system, uint64_t buffer, Handle debug_handle, + uint64_t address, uint64_t size) { + R_RETURN(ReadDebugProcessMemory(system, buffer, debug_handle, address, size)); +} + +Result WriteDebugProcessMemory64(Core::System& system, Handle debug_handle, uint64_t buffer, + uint64_t address, uint64_t size) { + R_RETURN(WriteDebugProcessMemory(system, debug_handle, buffer, address, size)); +} + +Result SetHardwareBreakPoint64(Core::System& system, HardwareBreakPointRegisterName name, + uint64_t flags, uint64_t value) { + R_RETURN(SetHardwareBreakPoint(system, name, flags, value)); +} + +Result GetDebugThreadParam64(Core::System& system, uint64_t* out_64, uint32_t* out_32, + Handle debug_handle, uint64_t thread_id, DebugThreadParam param) { + R_RETURN(GetDebugThreadParam(system, out_64, out_32, debug_handle, thread_id, param)); +} + +Result DebugActiveProcess64From32(Core::System& system, Handle* out_handle, uint64_t process_id) { + R_RETURN(DebugActiveProcess(system, out_handle, process_id)); +} + +Result BreakDebugProcess64From32(Core::System& system, Handle debug_handle) { + R_RETURN(BreakDebugProcess(system, debug_handle)); +} + +Result TerminateDebugProcess64From32(Core::System& system, Handle debug_handle) { + R_RETURN(TerminateDebugProcess(system, debug_handle)); +} + +Result GetDebugEvent64From32(Core::System& system, uint32_t out_info, Handle debug_handle) { + R_RETURN(GetDebugEvent(system, out_info, debug_handle)); +} + +Result ContinueDebugEvent64From32(Core::System& system, Handle debug_handle, uint32_t flags, + uint32_t thread_ids, int32_t num_thread_ids) { + R_RETURN(ContinueDebugEvent(system, debug_handle, flags, thread_ids, num_thread_ids)); +} + +Result GetDebugThreadContext64From32(Core::System& system, uint32_t out_context, + Handle debug_handle, uint64_t thread_id, + uint32_t context_flags) { + R_RETURN(GetDebugThreadContext(system, out_context, debug_handle, thread_id, context_flags)); +} + +Result SetDebugThreadContext64From32(Core::System& system, Handle debug_handle, uint64_t thread_id, + uint32_t context, uint32_t context_flags) { + R_RETURN(SetDebugThreadContext(system, debug_handle, thread_id, context, context_flags)); +} + +Result QueryDebugProcessMemory64From32(Core::System& system, uint32_t out_memory_info, + PageInfo* out_page_info, Handle debug_handle, + uint32_t address) { + R_RETURN( + QueryDebugProcessMemory(system, out_memory_info, out_page_info, debug_handle, address)); +} + +Result ReadDebugProcessMemory64From32(Core::System& system, uint32_t buffer, Handle debug_handle, + uint32_t address, uint32_t size) { + R_RETURN(ReadDebugProcessMemory(system, buffer, debug_handle, address, size)); +} + +Result WriteDebugProcessMemory64From32(Core::System& system, Handle debug_handle, uint32_t buffer, + uint32_t address, uint32_t size) { + R_RETURN(WriteDebugProcessMemory(system, debug_handle, buffer, address, size)); +} + +Result SetHardwareBreakPoint64From32(Core::System& system, HardwareBreakPointRegisterName name, + uint64_t flags, uint64_t value) { + R_RETURN(SetHardwareBreakPoint(system, name, flags, value)); +} + +Result GetDebugThreadParam64From32(Core::System& system, uint64_t* out_64, uint32_t* out_32, + Handle debug_handle, uint64_t thread_id, + DebugThreadParam param) { + R_RETURN(GetDebugThreadParam(system, out_64, out_32, debug_handle, thread_id, param)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_debug_string.cpp b/src/core/hle/kernel/svc/svc_debug_string.cpp new file mode 100644 index 000000000..d4bf062d1 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_debug_string.cpp @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/svc.h" +#include "core/memory.h" + +namespace Kernel::Svc { + +/// Used to output a message on a debug hardware unit - does nothing on a retail unit +Result OutputDebugString(Core::System& system, VAddr address, u64 len) { + R_SUCCEED_IF(len == 0); + + std::string str(len, '\0'); + system.Memory().ReadBlock(address, str.data(), str.size()); + LOG_DEBUG(Debug_Emulated, "{}", str); + + R_SUCCEED(); +} + +Result OutputDebugString64(Core::System& system, uint64_t debug_str, uint64_t len) { + R_RETURN(OutputDebugString(system, debug_str, len)); +} + +Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint32_t len) { + R_RETURN(OutputDebugString(system, debug_str, len)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp new file mode 100644 index 000000000..f68c0e6a9 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp @@ -0,0 +1,258 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/alignment.h" +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_device_address_space.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +constexpr inline u64 DeviceAddressSpaceAlignMask = (1ULL << 22) - 1; + +constexpr bool IsProcessAndDeviceAligned(uint64_t process_address, uint64_t device_address) { + return (process_address & DeviceAddressSpaceAlignMask) == + (device_address & DeviceAddressSpaceAlignMask); +} + +Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_address, + uint64_t das_size) { + // Validate input. + R_UNLESS(Common::IsAligned(das_address, PageSize), ResultInvalidMemoryRegion); + R_UNLESS(Common::IsAligned(das_size, PageSize), ResultInvalidMemoryRegion); + R_UNLESS(das_size > 0, ResultInvalidMemoryRegion); + R_UNLESS((das_address < das_address + das_size), ResultInvalidMemoryRegion); + + // Create the device address space. + KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel()); + R_UNLESS(das != nullptr, ResultOutOfResource); + SCOPE_EXIT({ das->Close(); }); + + // Initialize the device address space. + R_TRY(das->Initialize(das_address, das_size)); + + // Register the device address space. + KDeviceAddressSpace::Register(system.Kernel(), das); + + // Add to the handle table. + R_TRY(GetCurrentProcess(system.Kernel()).GetHandleTable().Add(out, das)); + + R_SUCCEED(); +} + +Result AttachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle) { + // Get the device address space. + KScopedAutoObject das = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KDeviceAddressSpace>(das_handle); + R_UNLESS(das.IsNotNull(), ResultInvalidHandle); + + // Attach. + R_RETURN(das->Attach(device_name)); +} + +Result DetachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle) { + // Get the device address space. + KScopedAutoObject das = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KDeviceAddressSpace>(das_handle); + R_UNLESS(das.IsNotNull(), ResultInvalidHandle); + + // Detach. + R_RETURN(das->Detach(device_name)); +} + +constexpr bool IsValidDeviceMemoryPermission(MemoryPermission device_perm) { + switch (device_perm) { + case MemoryPermission::Read: + case MemoryPermission::Write: + case MemoryPermission::ReadWrite: + return true; + default: + return false; + } +} + +Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Handle process_handle, + uint64_t process_address, size_t size, uint64_t device_address, + u32 option) { + // Decode the option. + const MapDeviceAddressSpaceOption option_pack{option}; + const auto device_perm = option_pack.permission; + const auto reserved = option_pack.reserved; + + // Validate input. + R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory); + R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion); + R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), + ResultInvalidCurrentMemory); + R_UNLESS(IsValidDeviceMemoryPermission(device_perm), ResultInvalidNewMemoryPermission); + R_UNLESS(reserved == 0, ResultInvalidEnumValue); + + // Get the device address space. + KScopedAutoObject das = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KDeviceAddressSpace>(das_handle); + R_UNLESS(das.IsNotNull(), ResultInvalidHandle); + + // Get the process. + KScopedAutoObject process = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Validate that the process address is within range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); + + // Map. + R_RETURN( + das->MapByForce(std::addressof(page_table), process_address, size, device_address, option)); +} + +Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Handle process_handle, + uint64_t process_address, size_t size, uint64_t device_address, + u32 option) { + // Decode the option. + const MapDeviceAddressSpaceOption option_pack{option}; + const auto device_perm = option_pack.permission; + const auto reserved = option_pack.reserved; + + // Validate input. + R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress); + R_UNLESS(IsProcessAndDeviceAligned(process_address, device_address), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory); + R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion); + R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), + ResultInvalidCurrentMemory); + R_UNLESS(IsValidDeviceMemoryPermission(device_perm), ResultInvalidNewMemoryPermission); + R_UNLESS(reserved == 0, ResultInvalidEnumValue); + + // Get the device address space. + KScopedAutoObject das = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KDeviceAddressSpace>(das_handle); + R_UNLESS(das.IsNotNull(), ResultInvalidHandle); + + // Get the process. + KScopedAutoObject process = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Validate that the process address is within range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); + + // Map. + R_RETURN( + das->MapAligned(std::addressof(page_table), process_address, size, device_address, option)); +} + +Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle process_handle, + uint64_t process_address, size_t size, uint64_t device_address) { + // Validate input. + R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory); + R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion); + R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), + ResultInvalidCurrentMemory); + + // Get the device address space. + KScopedAutoObject das = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KDeviceAddressSpace>(das_handle); + R_UNLESS(das.IsNotNull(), ResultInvalidHandle); + + // Get the process. + KScopedAutoObject process = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Validate that the process address is within range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); + + R_RETURN(das->Unmap(std::addressof(page_table), process_address, size, device_address)); +} + +Result CreateDeviceAddressSpace64(Core::System& system, Handle* out_handle, uint64_t das_address, + uint64_t das_size) { + R_RETURN(CreateDeviceAddressSpace(system, out_handle, das_address, das_size)); +} + +Result AttachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle) { + R_RETURN(AttachDeviceAddressSpace(system, device_name, das_handle)); +} + +Result DetachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle) { + R_RETURN(DetachDeviceAddressSpace(system, device_name, das_handle)); +} + +Result MapDeviceAddressSpaceByForce64(Core::System& system, Handle das_handle, + Handle process_handle, uint64_t process_address, + uint64_t size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceByForce(system, das_handle, process_handle, process_address, size, + device_address, option)); +} + +Result MapDeviceAddressSpaceAligned64(Core::System& system, Handle das_handle, + Handle process_handle, uint64_t process_address, + uint64_t size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceAligned(system, das_handle, process_handle, process_address, size, + device_address, option)); +} + +Result UnmapDeviceAddressSpace64(Core::System& system, Handle das_handle, Handle process_handle, + uint64_t process_address, uint64_t size, uint64_t device_address) { + R_RETURN(UnmapDeviceAddressSpace(system, das_handle, process_handle, process_address, size, + device_address)); +} + +Result CreateDeviceAddressSpace64From32(Core::System& system, Handle* out_handle, + uint64_t das_address, uint64_t das_size) { + R_RETURN(CreateDeviceAddressSpace(system, out_handle, das_address, das_size)); +} + +Result AttachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, + Handle das_handle) { + R_RETURN(AttachDeviceAddressSpace(system, device_name, das_handle)); +} + +Result DetachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, + Handle das_handle) { + R_RETURN(DetachDeviceAddressSpace(system, device_name, das_handle)); +} + +Result MapDeviceAddressSpaceByForce64From32(Core::System& system, Handle das_handle, + Handle process_handle, uint64_t process_address, + uint32_t size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceByForce(system, das_handle, process_handle, process_address, size, + device_address, option)); +} + +Result MapDeviceAddressSpaceAligned64From32(Core::System& system, Handle das_handle, + Handle process_handle, uint64_t process_address, + uint32_t size, uint64_t device_address, u32 option) { + R_RETURN(MapDeviceAddressSpaceAligned(system, das_handle, process_handle, process_address, size, + device_address, option)); +} + +Result UnmapDeviceAddressSpace64From32(Core::System& system, Handle das_handle, + Handle process_handle, uint64_t process_address, + uint32_t size, uint64_t device_address) { + R_RETURN(UnmapDeviceAddressSpace(system, das_handle, process_handle, process_address, size, + device_address)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_event.cpp b/src/core/hle/kernel/svc/svc_event.cpp new file mode 100644 index 000000000..a948493e8 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_event.cpp @@ -0,0 +1,124 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +Result SignalEvent(Core::System& system, Handle event_handle) { + LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); + + // Get the current handle table. + const KHandleTable& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); + + // Get the event. + KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle); + R_UNLESS(event.IsNotNull(), ResultInvalidHandle); + + return event->Signal(); +} + +Result ClearEvent(Core::System& system, Handle event_handle) { + LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); + + // Get the current handle table. + const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); + + // Try to clear the writable event. + { + KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle); + if (event.IsNotNull()) { + return event->Clear(); + } + } + + // Try to clear the readable event. + { + KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle); + if (readable_event.IsNotNull()) { + return readable_event->Clear(); + } + } + + LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle); + + return ResultInvalidHandle; +} + +Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) { + LOG_DEBUG(Kernel_SVC, "called"); + + // Get the kernel reference and handle table. + auto& kernel = system.Kernel(); + auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); + + // Reserve a new event from the process resource limit + KScopedResourceReservation event_reservation(GetCurrentProcessPointer(kernel), + LimitableResource::EventCountMax); + R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); + + // Create a new event. + KEvent* event = KEvent::Create(kernel); + R_UNLESS(event != nullptr, ResultOutOfResource); + + // Initialize the event. + event->Initialize(GetCurrentProcessPointer(kernel)); + + // Commit the thread reservation. + event_reservation.Commit(); + + // Ensure that we clean up the event (and its only references are handle table) on function end. + SCOPE_EXIT({ + event->GetReadableEvent().Close(); + event->Close(); + }); + + // Register the event. + KEvent::Register(kernel, event); + + // Add the event to the handle table. + R_TRY(handle_table.Add(out_write, event)); + + // Ensure that we maintaing a clean handle state on exit. + auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); }); + + // Add the readable event to the handle table. + R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); + + // We succeeded. + handle_guard.Cancel(); + return ResultSuccess; +} + +Result SignalEvent64(Core::System& system, Handle event_handle) { + R_RETURN(SignalEvent(system, event_handle)); +} + +Result ClearEvent64(Core::System& system, Handle event_handle) { + R_RETURN(ClearEvent(system, event_handle)); +} + +Result CreateEvent64(Core::System& system, Handle* out_write_handle, Handle* out_read_handle) { + R_RETURN(CreateEvent(system, out_write_handle, out_read_handle)); +} + +Result SignalEvent64From32(Core::System& system, Handle event_handle) { + R_RETURN(SignalEvent(system, event_handle)); +} + +Result ClearEvent64From32(Core::System& system, Handle event_handle) { + R_RETURN(ClearEvent(system, event_handle)); +} + +Result CreateEvent64From32(Core::System& system, Handle* out_write_handle, + Handle* out_read_handle) { + R_RETURN(CreateEvent(system, out_write_handle, out_read_handle)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_exception.cpp b/src/core/hle/kernel/svc/svc_exception.cpp new file mode 100644 index 000000000..c2782908d --- /dev/null +++ b/src/core/hle/kernel/svc/svc_exception.cpp @@ -0,0 +1,137 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/debugger/debugger.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_types.h" +#include "core/memory.h" +#include "core/reporter.h" + +namespace Kernel::Svc { + +/// Break program execution +void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) { + BreakReason break_reason = + reason & static_cast<BreakReason>(~BreakReason::NotificationOnlyFlag); + bool notification_only = True(reason & BreakReason::NotificationOnlyFlag); + + 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; + } + + system.GetReporter().SaveSvcBreakReport( + static_cast<u32>(reason), notification_only, info1, info2, + has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); + + if (!notification_only) { + LOG_CRITICAL( + Debug_Emulated, + "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", + reason, info1, info2); + + handle_debug_buffer(info1, info2); + + 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(); + } + + if (system.DebuggerEnabled()) { + auto* thread = system.Kernel().GetCurrentEmuThread(); + system.GetDebugger().NotifyThreadStopped(thread); + thread->RequestSuspend(Kernel::SuspendType::Debug); + } +} + +void ReturnFromException(Core::System& system, Result result) { + UNIMPLEMENTED(); +} + +void Break64(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size) { + Break(system, break_reason, arg, size); +} + +void Break64From32(Core::System& system, BreakReason break_reason, uint32_t arg, uint32_t size) { + Break(system, break_reason, arg, size); +} + +void ReturnFromException64(Core::System& system, Result result) { + ReturnFromException(system, result); +} + +void ReturnFromException64From32(Core::System& system, Result result) { + ReturnFromException(system, result); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp new file mode 100644 index 000000000..58dc47508 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_info.cpp @@ -0,0 +1,297 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Gets system/memory information for the current process +Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, 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_type, info_sub_id, handle); + + u32 info_id = static_cast<u32>(info_id_type); + + 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 = GetCurrentProcess(system.Kernel()).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; + } + + 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 = GetCurrentProcessPointer(system.Kernel()); + 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; + } + + 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 = GetCurrentProcess(system.Kernel()).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 = GetCurrentProcess(system.Kernel()) + .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); + + // Verify the sub-type is valid. + R_UNLESS(info_sub_id == 0, ResultInvalidCombination); + + // Get the handle table. + KProcess* current_process = GetCurrentProcessPointer(system.Kernel()); + KHandleTable& handle_table = current_process->GetHandleTable(); + + // Get a new handle for the current process. + Handle tmp; + R_TRY(handle_table.Add(&tmp, current_process)); + + // Set the output. + *result = tmp; + + // We succeeded. + return ResultSuccess; + } + default: + LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id); + return ResultInvalidEnumValue; + } +} + +Result GetSystemInfo(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, + uint64_t info_subtype) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result GetInfo64(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, + uint64_t info_subtype) { + R_RETURN(GetInfo(system, out, info_type, handle, info_subtype)); +} + +Result GetSystemInfo64(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, + uint64_t info_subtype) { + R_RETURN(GetSystemInfo(system, out, info_type, handle, info_subtype)); +} + +Result GetInfo64From32(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, + uint64_t info_subtype) { + R_RETURN(GetInfo(system, out, info_type, handle, info_subtype)); +} + +Result GetSystemInfo64From32(Core::System& system, uint64_t* out, SystemInfoType info_type, + Handle handle, uint64_t info_subtype) { + R_RETURN(GetSystemInfo(system, out, info_type, handle, info_subtype)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_insecure_memory.cpp b/src/core/hle/kernel/svc/svc_insecure_memory.cpp new file mode 100644 index 000000000..79882685d --- /dev/null +++ b/src/core/hle/kernel/svc/svc_insecure_memory.cpp @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result MapInsecureMemory(Core::System& system, uintptr_t address, size_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result UnmapInsecureMemory(Core::System& system, uintptr_t address, size_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result MapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(MapInsecureMemory(system, address, size)); +} + +Result UnmapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(UnmapInsecureMemory(system, address, size)); +} + +Result MapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(MapInsecureMemory(system, address, size)); +} + +Result UnmapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(UnmapInsecureMemory(system, address, size)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_interrupt_event.cpp b/src/core/hle/kernel/svc/svc_interrupt_event.cpp new file mode 100644 index 000000000..768b30a1f --- /dev/null +++ b/src/core/hle/kernel/svc/svc_interrupt_event.cpp @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result CreateInterruptEvent(Core::System& system, Handle* out, int32_t interrupt_id, + InterruptType type) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result CreateInterruptEvent64(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, + InterruptType interrupt_type) { + R_RETURN(CreateInterruptEvent(system, out_read_handle, interrupt_id, interrupt_type)); +} + +Result CreateInterruptEvent64From32(Core::System& system, Handle* out_read_handle, + int32_t interrupt_id, InterruptType interrupt_type) { + R_RETURN(CreateInterruptEvent(system, out_read_handle, interrupt_id, interrupt_type)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_io_pool.cpp b/src/core/hle/kernel/svc/svc_io_pool.cpp new file mode 100644 index 000000000..33f3d69bf --- /dev/null +++ b/src/core/hle/kernel/svc/svc_io_pool.cpp @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result CreateIoPool(Core::System& system, Handle* out, IoPoolType pool_type) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result CreateIoRegion(Core::System& system, Handle* out, Handle io_pool_handle, uint64_t phys_addr, + size_t size, MemoryMapping mapping, MemoryPermission perm) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result MapIoRegion(Core::System& system, Handle io_region_handle, uintptr_t address, size_t size, + MemoryPermission map_perm) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result UnmapIoRegion(Core::System& system, Handle io_region_handle, uintptr_t address, + size_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result CreateIoPool64(Core::System& system, Handle* out_handle, IoPoolType pool_type) { + R_RETURN(CreateIoPool(system, out_handle, pool_type)); +} + +Result CreateIoRegion64(Core::System& system, Handle* out_handle, Handle io_pool, + uint64_t physical_address, uint64_t size, MemoryMapping mapping, + MemoryPermission perm) { + R_RETURN(CreateIoRegion(system, out_handle, io_pool, physical_address, size, mapping, perm)); +} + +Result MapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size, + MemoryPermission perm) { + R_RETURN(MapIoRegion(system, io_region, address, size, perm)); +} + +Result UnmapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size) { + R_RETURN(UnmapIoRegion(system, io_region, address, size)); +} + +Result CreateIoPool64From32(Core::System& system, Handle* out_handle, IoPoolType pool_type) { + R_RETURN(CreateIoPool(system, out_handle, pool_type)); +} + +Result CreateIoRegion64From32(Core::System& system, Handle* out_handle, Handle io_pool, + uint64_t physical_address, uint32_t size, MemoryMapping mapping, + MemoryPermission perm) { + R_RETURN(CreateIoRegion(system, out_handle, io_pool, physical_address, size, mapping, perm)); +} + +Result MapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size, + MemoryPermission perm) { + R_RETURN(MapIoRegion(system, io_region, address, size, perm)); +} + +Result UnmapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, + uint32_t size) { + R_RETURN(UnmapIoRegion(system, io_region, address, size)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp new file mode 100644 index 000000000..a7a2c3b92 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_ipc.cpp @@ -0,0 +1,172 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Makes a blocking IPC call to a service. +Result SendSyncRequest(Core::System& system, Handle handle) { + // Get the client session from its handle. + KScopedAutoObject session = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KClientSession>(handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + + LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + + return session->SendSyncRequest(); +} + +Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer, + uint64_t message_buffer_size, Handle session_handle) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, + uint64_t message_buffer, uint64_t message_buffer_size, + Handle session_handle) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles, + Handle reply_target, s64 timeout_ns) { + auto& kernel = system.Kernel(); + auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); + + R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); + R_UNLESS(system.Memory().IsValidVirtualAddressRange( + handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)), + ResultInvalidPointer); + + std::vector<Handle> handles(num_handles); + system.Memory().ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles); + + // Convert handle list to object table. + std::vector<KSynchronizationObject*> objs(num_handles); + R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(), + 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()); + } + + // 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; + } +} + +Result ReplyAndReceiveWithUserBuffer(Core::System& system, 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) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SendSyncRequest64(Core::System& system, Handle session_handle) { + R_RETURN(SendSyncRequest(system, session_handle)); +} + +Result SendSyncRequestWithUserBuffer64(Core::System& system, uint64_t message_buffer, + uint64_t message_buffer_size, Handle session_handle) { + R_RETURN( + SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle)); +} + +Result SendAsyncRequestWithUserBuffer64(Core::System& system, Handle* out_event_handle, + uint64_t message_buffer, uint64_t message_buffer_size, + Handle session_handle) { + R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer, + message_buffer_size, session_handle)); +} + +Result ReplyAndReceive64(Core::System& system, int32_t* out_index, uint64_t handles, + int32_t num_handles, Handle reply_target, int64_t timeout_ns) { + R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns)); +} + +Result ReplyAndReceiveWithUserBuffer64(Core::System& system, 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) { + R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size, + handles, num_handles, reply_target, timeout_ns)); +} + +Result SendSyncRequest64From32(Core::System& system, Handle session_handle) { + R_RETURN(SendSyncRequest(system, session_handle)); +} + +Result SendSyncRequestWithUserBuffer64From32(Core::System& system, uint32_t message_buffer, + uint32_t message_buffer_size, Handle session_handle) { + R_RETURN( + SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle)); +} + +Result SendAsyncRequestWithUserBuffer64From32(Core::System& system, Handle* out_event_handle, + uint32_t message_buffer, uint32_t message_buffer_size, + Handle session_handle) { + R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer, + message_buffer_size, session_handle)); +} + +Result ReplyAndReceive64From32(Core::System& system, int32_t* out_index, uint32_t handles, + int32_t num_handles, Handle reply_target, int64_t timeout_ns) { + R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns)); +} + +Result ReplyAndReceiveWithUserBuffer64From32(Core::System& system, 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) { + R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size, + handles, num_handles, reply_target, timeout_ns)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_kernel_debug.cpp b/src/core/hle/kernel/svc/svc_kernel_debug.cpp new file mode 100644 index 000000000..cee048279 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_kernel_debug.cpp @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +void KernelDebug(Core::System& system, KernelDebugType kernel_debug_type, u64 arg0, u64 arg1, + u64 arg2) { + // Intentionally do nothing, as this does nothing in released kernel binaries. +} + +void ChangeKernelTraceState(Core::System& system, KernelTraceState trace_state) { + // Intentionally do nothing, as this does nothing in released kernel binaries. +} + +void KernelDebug64(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, + uint64_t arg1, uint64_t arg2) { + KernelDebug(system, kern_debug_type, arg0, arg1, arg2); +} + +void ChangeKernelTraceState64(Core::System& system, KernelTraceState kern_trace_state) { + ChangeKernelTraceState(system, kern_trace_state); +} + +void KernelDebug64From32(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, + uint64_t arg1, uint64_t arg2) { + KernelDebug(system, kern_debug_type, arg0, arg1, arg2); +} + +void ChangeKernelTraceState64From32(Core::System& system, KernelTraceState kern_trace_state) { + ChangeKernelTraceState(system, kern_trace_state); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_light_ipc.cpp b/src/core/hle/kernel/svc/svc_light_ipc.cpp new file mode 100644 index 000000000..b76ce984c --- /dev/null +++ b/src/core/hle/kernel/svc/svc_light_ipc.cpp @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/arm/arm_interface.h" +#include "core/core.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) { + R_RETURN(SendSyncRequestLight(system, session_handle, args)); +} + +Result ReplyAndReceiveLight64(Core::System& system, Handle session_handle, u32* args) { + R_RETURN(ReplyAndReceiveLight(system, session_handle, args)); +} + +Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, u32* args) { + R_RETURN(SendSyncRequestLight(system, session_handle, args)); +} + +Result ReplyAndReceiveLight64From32(Core::System& system, Handle session_handle, u32* args) { + R_RETURN(ReplyAndReceiveLight(system, session_handle, args)); +} + +// Custom ABI implementation for light IPC. + +template <typename F> +static void SvcWrap_LightIpc(Core::System& system, F&& cb) { + auto& core = system.CurrentArmInterface(); + std::array<u32, 7> arguments{}; + + Handle session_handle = static_cast<Handle>(core.GetReg(0)); + for (int i = 0; i < 7; i++) { + arguments[i] = static_cast<u32>(core.GetReg(i + 1)); + } + + Result ret = cb(system, session_handle, arguments.data()); + + core.SetReg(0, ret.raw); + for (int i = 0; i < 7; i++) { + core.SetReg(i + 1, arguments[i]); + } +} + +void SvcWrap_SendSyncRequestLight64(Core::System& system) { + SvcWrap_LightIpc(system, SendSyncRequestLight64); +} + +void SvcWrap_ReplyAndReceiveLight64(Core::System& system) { + SvcWrap_LightIpc(system, ReplyAndReceiveLight64); +} + +void SvcWrap_SendSyncRequestLight64From32(Core::System& system) { + SvcWrap_LightIpc(system, SendSyncRequestLight64From32); +} + +void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system) { + SvcWrap_LightIpc(system, ReplyAndReceiveLight64From32); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_lock.cpp b/src/core/hle/kernel/svc/svc_lock.cpp new file mode 100644 index 000000000..f3d3e140b --- /dev/null +++ b/src/core/hle/kernel/svc/svc_lock.cpp @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Attempts to locks a mutex +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); + + // 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; + } + + return GetCurrentProcess(system.Kernel()).WaitForAddress(thread_handle, address, tag); +} + +/// Unlock a mutex +Result ArbitrateUnlock(Core::System& system, VAddr address) { + LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); + + // 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; + } + + return GetCurrentProcess(system.Kernel()).SignalToAddress(address); +} + +Result ArbitrateLock64(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag) { + R_RETURN(ArbitrateLock(system, thread_handle, address, tag)); +} + +Result ArbitrateUnlock64(Core::System& system, uint64_t address) { + R_RETURN(ArbitrateUnlock(system, address)); +} + +Result ArbitrateLock64From32(Core::System& system, Handle thread_handle, uint32_t address, + uint32_t tag) { + R_RETURN(ArbitrateLock(system, thread_handle, address, tag)); +} + +Result ArbitrateUnlock64From32(Core::System& system, uint32_t address) { + R_RETURN(ArbitrateUnlock(system, address)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp new file mode 100644 index 000000000..214bcd073 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_memory.cpp @@ -0,0 +1,217 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { +namespace { + +constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) { + switch (perm) { + case MemoryPermission::None: + case MemoryPermission::Read: + case MemoryPermission::ReadWrite: + return true; + default: + return false; + } +} + +// 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; + } + + if (size == 0) { + LOG_ERROR(Kernel_SVC, "Size is 0"); + return ResultInvalidSize; + } + + if (!Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size); + return ResultInvalidSize; + } + + 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; + } + + 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; + } + + 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 (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; + } + + 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; + } + + 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; + } + + return ResultSuccess; +} + +} // namespace + +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); + + // 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); + + // Validate the permission. + R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Validate that the region is in range for the current process. + auto& page_table = GetCurrentProcess(system.Kernel()).PageTable(); + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + + // Set the memory attribute. + return page_table.SetMemoryPermission(address, size, perm); +} + +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); + + // 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); + + // 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); + + // Validate that the region is in range for the current process. + auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + + // Set the memory attribute. + return page_table.SetMemoryAttribute(address, size, mask, attr); +} + +/// Maps a memory range into a different range. +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); + + auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; + + if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; + result.IsError()) { + return result; + } + + return page_table.MapMemory(dst_addr, src_addr, size); +} + +/// Unmaps a region that was previously mapped with svcMapMemory +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); + + auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; + + if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; + result.IsError()) { + return result; + } + + return page_table.UnmapMemory(dst_addr, src_addr, size); +} + +Result SetMemoryPermission64(Core::System& system, uint64_t address, uint64_t size, + MemoryPermission perm) { + R_RETURN(SetMemoryPermission(system, address, size, perm)); +} + +Result SetMemoryAttribute64(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, + uint32_t attr) { + R_RETURN(SetMemoryAttribute(system, address, size, mask, attr)); +} + +Result MapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, + uint64_t size) { + R_RETURN(MapMemory(system, dst_address, src_address, size)); +} + +Result UnmapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, + uint64_t size) { + R_RETURN(UnmapMemory(system, dst_address, src_address, size)); +} + +Result SetMemoryPermission64From32(Core::System& system, uint32_t address, uint32_t size, + MemoryPermission perm) { + R_RETURN(SetMemoryPermission(system, address, size, perm)); +} + +Result SetMemoryAttribute64From32(Core::System& system, uint32_t address, uint32_t size, + uint32_t mask, uint32_t attr) { + R_RETURN(SetMemoryAttribute(system, address, size, mask, attr)); +} + +Result MapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, + uint32_t size) { + R_RETURN(MapMemory(system, dst_address, src_address, size)); +} + +Result UnmapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, + uint32_t size) { + R_RETURN(UnmapMemory(system, dst_address, src_address, size)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_physical_memory.cpp b/src/core/hle/kernel/svc/svc_physical_memory.cpp new file mode 100644 index 000000000..a1f534454 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_physical_memory.cpp @@ -0,0 +1,185 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Set the process heap to a given Size. It can both extend and shrink the heap. +Result SetHeapSize(Core::System& system, VAddr* out_address, u64 size) { + LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); + + // Validate size. + R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); + R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); + + // Set the heap size. + R_TRY(GetCurrentProcess(system.Kernel()).PageTable().SetHeapSize(out_address, size)); + + return ResultSuccess; +} + +/// Maps memory at a desired address +Result MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + + if (!Common::Is4KBAligned(addr)) { + LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); + return ResultInvalidAddress; + } + + if (!Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + return ResultInvalidSize; + } + + if (size == 0) { + LOG_ERROR(Kernel_SVC, "Size is zero"); + return ResultInvalidSize; + } + + if (!(addr < addr + size)) { + LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); + return ResultInvalidMemoryRegion; + } + + KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; + auto& page_table{current_process->PageTable()}; + + if (current_process->GetSystemResourceSize() == 0) { + LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); + return ResultInvalidState; + } + + 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; + } + + 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; + } + + return page_table.MapPhysicalMemory(addr, size); +} + +/// Unmaps memory previously mapped via MapPhysicalMemory +Result UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + + if (!Common::Is4KBAligned(addr)) { + LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); + return ResultInvalidAddress; + } + + if (!Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + return ResultInvalidSize; + } + + if (size == 0) { + LOG_ERROR(Kernel_SVC, "Size is zero"); + return ResultInvalidSize; + } + + if (!(addr < addr + size)) { + LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); + return ResultInvalidMemoryRegion; + } + + KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; + auto& page_table{current_process->PageTable()}; + + if (current_process->GetSystemResourceSize() == 0) { + LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); + return ResultInvalidState; + } + + 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; + } + + 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; + } + + return page_table.UnmapPhysicalMemory(addr, size); +} + +Result MapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result UnmapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SetUnsafeLimit(Core::System& system, uint64_t limit) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SetHeapSize64(Core::System& system, uint64_t* out_address, uint64_t size) { + R_RETURN(SetHeapSize(system, out_address, size)); +} + +Result MapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(MapPhysicalMemory(system, address, size)); +} + +Result UnmapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(UnmapPhysicalMemory(system, address, size)); +} + +Result MapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(MapPhysicalMemoryUnsafe(system, address, size)); +} + +Result UnmapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size)); +} + +Result SetUnsafeLimit64(Core::System& system, uint64_t limit) { + R_RETURN(SetUnsafeLimit(system, limit)); +} + +Result SetHeapSize64From32(Core::System& system, uintptr_t* out_address, uint32_t size) { + R_RETURN(SetHeapSize(system, out_address, size)); +} + +Result MapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(MapPhysicalMemory(system, address, size)); +} + +Result UnmapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(UnmapPhysicalMemory(system, address, size)); +} + +Result MapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(MapPhysicalMemoryUnsafe(system, address, size)); +} + +Result UnmapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size)); +} + +Result SetUnsafeLimit64From32(Core::System& system, uint32_t limit) { + R_RETURN(SetUnsafeLimit(system, limit)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp new file mode 100644 index 000000000..2f9bfcb52 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_port.cpp @@ -0,0 +1,170 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_object_name.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Connect to an OS service given the port name, returns the handle to the port to out +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 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; + } + + LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); + + // Get the current handle table. + auto& kernel = system.Kernel(); + auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); + + // 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; + } + + // 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); }); + + // Create a session. + KClientSession* session{}; + R_TRY(port->CreateSession(std::addressof(session))); + + kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort()); + + // Register the session in the table, close the extra reference. + handle_table.Register(*out, session); + session->Close(); + + // We succeeded. + handle_guard.Cancel(); + return ResultSuccess; +} + +Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, + int32_t max_sessions, bool is_light, uintptr_t name) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, + int32_t max_sessions) { + // Copy the provided name from user memory to kernel memory. + std::array<char, KObjectName::NameLengthMax> name{}; + system.Memory().ReadBlock(user_name, name.data(), sizeof(name)); + + // Validate that sessions and name are valid. + R_UNLESS(max_sessions >= 0, ResultOutOfRange); + R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange); + + if (max_sessions > 0) { + // Get the current handle table. + auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); + + // Create a new port. + KPort* port = KPort::Create(system.Kernel()); + R_UNLESS(port != nullptr, ResultOutOfResource); + + // Initialize the new port. + port->Initialize(max_sessions, false, ""); + + // Register the port. + KPort::Register(system.Kernel(), port); + + // Ensure that our only reference to the port is in the handle table when we're done. + SCOPE_EXIT({ + port->GetClientPort().Close(); + port->GetServerPort().Close(); + }); + + // Register the handle in the table. + R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); + ON_RESULT_FAILURE { + handle_table.Remove(*out_server_handle); + }; + + // Create a new object name. + R_TRY(KObjectName::NewFromName(system.Kernel(), std::addressof(port->GetClientPort()), + name.data())); + } else /* if (max_sessions == 0) */ { + // Ensure that this else case is correct. + ASSERT(max_sessions == 0); + + // If we're closing, there's no server handle. + *out_server_handle = InvalidHandle; + + // Delete the object. + R_TRY(KObjectName::Delete<KClientPort>(system.Kernel(), name.data())); + } + + R_SUCCEED(); +} + +Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) { + R_RETURN(ConnectToNamedPort(system, out_handle, name)); +} + +Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, + int32_t max_sessions, bool is_light, uint64_t name) { + R_RETURN( + CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name)); +} + +Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name, + int32_t max_sessions) { + R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions)); +} + +Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port) { + R_RETURN(ConnectToPort(system, out_handle, port)); +} + +Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name) { + R_RETURN(ConnectToNamedPort(system, out_handle, name)); +} + +Result CreatePort64From32(Core::System& system, Handle* out_server_handle, + Handle* out_client_handle, int32_t max_sessions, bool is_light, + uint32_t name) { + R_RETURN( + CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name)); +} + +Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name, + int32_t max_sessions) { + R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions)); +} + +Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port) { + R_RETURN(ConnectToPort(system, out_handle, port)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_power_management.cpp b/src/core/hle/kernel/svc/svc_power_management.cpp new file mode 100644 index 000000000..f605a0317 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_power_management.cpp @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +void SleepSystem(Core::System& system) { + UNIMPLEMENTED(); +} + +void SleepSystem64(Core::System& system) { + return SleepSystem(system); +} + +void SleepSystem64From32(Core::System& system) { + return SleepSystem(system); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp new file mode 100644 index 000000000..c35d2be76 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_process.cpp @@ -0,0 +1,194 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Exits the current process +void ExitProcess(Core::System& system) { + auto* current_process = GetCurrentProcessPointer(system.Kernel()); + + LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); + ASSERT_MSG(current_process->GetState() == KProcess::State::Running, + "Process has already exited"); + + system.Exit(); +} + +/// Gets the ID of the specified process or a specified thread's owning process. +Result GetProcessId(Core::System& system, u64* out_process_id, Handle handle) { + LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); + + // Get the object from the handle table. + KScopedAutoObject obj = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KAutoObject>(static_cast<Handle>(handle)); + R_UNLESS(obj.IsNotNull(), ResultInvalidHandle); + + // 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"); + } + + // Make sure the target process exists. + R_UNLESS(process != nullptr, ResultInvalidHandle); + + // Get the process id. + *out_process_id = process->GetId(); + + return ResultSuccess; +} + +Result GetProcessList(Core::System& system, s32* out_num_processes, VAddr out_process_ids, + int32_t out_process_ids_size) { + LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}", + out_process_ids, out_process_ids_size); + + // If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail. + if ((out_process_ids_size & 0xF0000000) != 0) { + LOG_ERROR(Kernel_SVC, + "Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}", + out_process_ids_size); + return ResultOutOfRange; + } + + auto& kernel = system.Kernel(); + const auto total_copy_size = out_process_ids_size * sizeof(u64); + + if (out_process_ids_size > 0 && !GetCurrentProcess(kernel).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; + } + + auto& memory = system.Memory(); + const auto& process_list = kernel.GetProcessList(); + const auto num_processes = process_list.size(); + const auto copy_amount = + std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); + + for (std::size_t i = 0; i < copy_amount; ++i) { + memory.Write64(out_process_ids, process_list[i]->GetProcessID()); + out_process_ids += sizeof(u64); + } + + *out_num_processes = static_cast<u32>(num_processes); + return ResultSuccess; +} + +Result GetProcessInfo(Core::System& system, s64* out, Handle process_handle, + ProcessInfoType info_type) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, info_type); + + const auto& handle_table = GetCurrentProcess(system.Kernel()).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; + } + + if (info_type != ProcessInfoType::ProcessState) { + LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead", + info_type); + return ResultInvalidEnumValue; + } + + *out = static_cast<s64>(process->GetState()); + return ResultSuccess; +} + +Result CreateProcess(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, + int32_t num_caps) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result StartProcess(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, + uint64_t main_thread_stack_size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result TerminateProcess(Core::System& system, Handle process_handle) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +void ExitProcess64(Core::System& system) { + ExitProcess(system); +} + +Result GetProcessId64(Core::System& system, uint64_t* out_process_id, Handle process_handle) { + R_RETURN(GetProcessId(system, out_process_id, process_handle)); +} + +Result GetProcessList64(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids, + int32_t max_out_count) { + R_RETURN(GetProcessList(system, out_num_processes, out_process_ids, max_out_count)); +} + +Result CreateProcess64(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, + int32_t num_caps) { + R_RETURN(CreateProcess(system, out_handle, parameters, caps, num_caps)); +} + +Result StartProcess64(Core::System& system, Handle process_handle, int32_t priority, + int32_t core_id, uint64_t main_thread_stack_size) { + R_RETURN(StartProcess(system, process_handle, priority, core_id, main_thread_stack_size)); +} + +Result TerminateProcess64(Core::System& system, Handle process_handle) { + R_RETURN(TerminateProcess(system, process_handle)); +} + +Result GetProcessInfo64(Core::System& system, int64_t* out_info, Handle process_handle, + ProcessInfoType info_type) { + R_RETURN(GetProcessInfo(system, out_info, process_handle, info_type)); +} + +void ExitProcess64From32(Core::System& system) { + ExitProcess(system); +} + +Result GetProcessId64From32(Core::System& system, uint64_t* out_process_id, Handle process_handle) { + R_RETURN(GetProcessId(system, out_process_id, process_handle)); +} + +Result GetProcessList64From32(Core::System& system, int32_t* out_num_processes, + uint32_t out_process_ids, int32_t max_out_count) { + R_RETURN(GetProcessList(system, out_num_processes, out_process_ids, max_out_count)); +} + +Result CreateProcess64From32(Core::System& system, Handle* out_handle, uint32_t parameters, + uint32_t caps, int32_t num_caps) { + R_RETURN(CreateProcess(system, out_handle, parameters, caps, num_caps)); +} + +Result StartProcess64From32(Core::System& system, Handle process_handle, int32_t priority, + int32_t core_id, uint64_t main_thread_stack_size) { + R_RETURN(StartProcess(system, process_handle, priority, core_id, main_thread_stack_size)); +} + +Result TerminateProcess64From32(Core::System& system, Handle process_handle) { + R_RETURN(TerminateProcess(system, process_handle)); +} + +Result GetProcessInfo64From32(Core::System& system, int64_t* out_info, Handle process_handle, + ProcessInfoType info_type) { + R_RETURN(GetProcessInfo(system, out_info, process_handle, info_type)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_process_memory.cpp b/src/core/hle/kernel/svc/svc_process_memory.cpp new file mode 100644 index 000000000..4dfd9e5bb --- /dev/null +++ b/src/core/hle/kernel/svc/svc_process_memory.cpp @@ -0,0 +1,324 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { +namespace { + +constexpr bool IsValidAddressRange(VAddr address, u64 size) { + return address + size > address; +} + +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; + } +} + +} // namespace + +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); + + // 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); + + // Validate the memory permission. + R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); + + // Get the process from its handle. + KScopedAutoObject process = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Validate that the address is in range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + + // Set the memory permission. + return page_table.SetProcessMemoryPermission(address, size, perm); +} + +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); + + // 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); + + // Get the processes. + KProcess* dst_process = GetCurrentProcessPointer(system.Kernel()); + 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); + + // Create a new page group. + KPageGroup pg{system.Kernel(), dst_pt.GetBlockInfoManager()}; + R_TRY(src_pt.MakeAndOpenPageGroup( + std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess, + KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::All, KMemoryAttribute::None)); + + // Map the group. + R_TRY(dst_pt.MapPageGroup(dst_address, pg, KMemoryState::SharedCode, + KMemoryPermission::UserReadWrite)); + + return ResultSuccess; +} + +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); + + // 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); + + // Get the processes. + KProcess* dst_process = GetCurrentProcessPointer(system.Kernel()); + 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; +} + +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); + + if (!Common::Is4KBAligned(src_address)) { + LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", + src_address); + return ResultInvalidAddress; + } + + if (!Common::Is4KBAligned(dst_address)) { + LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", + dst_address); + return ResultInvalidAddress; + } + + if (size == 0 || !Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size); + return ResultInvalidSize; + } + + 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; + } + + 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; + } + + const auto& handle_table = GetCurrentProcess(system.Kernel()).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; + } + + 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; + } + + 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; + } + + return page_table.MapCodeMemory(dst_address, src_address, size); +} + +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); + + if (!Common::Is4KBAligned(dst_address)) { + LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).", + dst_address); + return ResultInvalidAddress; + } + + if (!Common::Is4KBAligned(src_address)) { + LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).", + src_address); + return ResultInvalidAddress; + } + + if (size == 0 || !Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size); + return ResultInvalidSize; + } + + 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; + } + + 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; + } + + const auto& handle_table = GetCurrentProcess(system.Kernel()).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; + } + + 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; + } + + 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; + } + + return page_table.UnmapCodeMemory(dst_address, src_address, size, + KPageTable::ICacheInvalidationStrategy::InvalidateAll); +} + +Result SetProcessMemoryPermission64(Core::System& system, Handle process_handle, uint64_t address, + uint64_t size, MemoryPermission perm) { + R_RETURN(SetProcessMemoryPermission(system, process_handle, address, size, perm)); +} + +Result MapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, + uint64_t src_address, uint64_t size) { + R_RETURN(MapProcessMemory(system, dst_address, process_handle, src_address, size)); +} + +Result UnmapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, + uint64_t src_address, uint64_t size) { + R_RETURN(UnmapProcessMemory(system, dst_address, process_handle, src_address, size)); +} + +Result MapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, + uint64_t src_address, uint64_t size) { + R_RETURN(MapProcessCodeMemory(system, process_handle, dst_address, src_address, size)); +} + +Result UnmapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, + uint64_t src_address, uint64_t size) { + R_RETURN(UnmapProcessCodeMemory(system, process_handle, dst_address, src_address, size)); +} + +Result SetProcessMemoryPermission64From32(Core::System& system, Handle process_handle, + uint64_t address, uint64_t size, MemoryPermission perm) { + R_RETURN(SetProcessMemoryPermission(system, process_handle, address, size, perm)); +} + +Result MapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, + uint64_t src_address, uint32_t size) { + R_RETURN(MapProcessMemory(system, dst_address, process_handle, src_address, size)); +} + +Result UnmapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, + uint64_t src_address, uint32_t size) { + R_RETURN(UnmapProcessMemory(system, dst_address, process_handle, src_address, size)); +} + +Result MapProcessCodeMemory64From32(Core::System& system, Handle process_handle, + uint64_t dst_address, uint64_t src_address, uint64_t size) { + R_RETURN(MapProcessCodeMemory(system, process_handle, dst_address, src_address, size)); +} + +Result UnmapProcessCodeMemory64From32(Core::System& system, Handle process_handle, + uint64_t dst_address, uint64_t src_address, uint64_t size) { + R_RETURN(UnmapProcessCodeMemory(system, process_handle, dst_address, src_address, size)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_processor.cpp b/src/core/hle/kernel/svc/svc_processor.cpp new file mode 100644 index 000000000..7602ce6c0 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_processor.cpp @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hle/kernel/physical_core.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Get which CPU core is executing the current thread +int32_t GetCurrentProcessorNumber(Core::System& system) { + LOG_TRACE(Kernel_SVC, "called"); + return static_cast<int32_t>(system.CurrentPhysicalCore().CoreIndex()); +} + +int32_t GetCurrentProcessorNumber64(Core::System& system) { + return GetCurrentProcessorNumber(system); +} + +int32_t GetCurrentProcessorNumber64From32(Core::System& system) { + return GetCurrentProcessorNumber(system); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_query_memory.cpp b/src/core/hle/kernel/svc/svc_query_memory.cpp new file mode 100644 index 000000000..ee75ad370 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_query_memory.cpp @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +Result QueryMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, + VAddr query_address) { + LOG_TRACE(Kernel_SVC, + "called, out_memory_info=0x{:016X}, " + "query_address=0x{:016X}", + out_memory_info, query_address); + + // Query memory is just QueryProcessMemory on the current process. + return QueryProcessMemory(system, out_memory_info, out_page_info, CurrentProcess, + query_address); +} + +Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, + Handle process_handle, uint64_t address) { + LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); + const auto& handle_table = GetCurrentProcess(system.Kernel()).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; + } + + auto& memory{system.Memory()}; + const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()}; + + memory.WriteBlock(out_memory_info, &memory_info, sizeof(memory_info)); + + //! This is supposed to be part of the QueryInfo call. + *out_page_info = {}; + + R_SUCCEED(); +} + +Result QueryMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, + uint64_t address) { + R_RETURN(QueryMemory(system, out_memory_info, out_page_info, address)); +} + +Result QueryProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, + Handle process_handle, uint64_t address) { + R_RETURN(QueryProcessMemory(system, out_memory_info, out_page_info, process_handle, address)); +} + +Result QueryMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, + uint32_t address) { + R_RETURN(QueryMemory(system, out_memory_info, out_page_info, address)); +} + +Result QueryProcessMemory64From32(Core::System& system, uint32_t out_memory_info, + PageInfo* out_page_info, Handle process_handle, + uint64_t address) { + R_RETURN(QueryProcessMemory(system, out_memory_info, out_page_info, process_handle, address)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_register.cpp b/src/core/hle/kernel/svc/svc_register.cpp new file mode 100644 index 000000000..b883e6618 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_register.cpp @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result ReadWriteRegister(Core::System& system, uint32_t* out, uint64_t address, uint32_t mask, + uint32_t value) { + *out = 0; + + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result ReadWriteRegister64(Core::System& system, uint32_t* out_value, uint64_t address, + uint32_t mask, uint32_t value) { + R_RETURN(ReadWriteRegister(system, out_value, address, mask, value)); +} + +Result ReadWriteRegister64From32(Core::System& system, uint32_t* out_value, uint64_t address, + uint32_t mask, uint32_t value) { + R_RETURN(ReadWriteRegister(system, out_value, address, mask, value)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_resource_limit.cpp b/src/core/hle/kernel/svc/svc_resource_limit.cpp new file mode 100644 index 000000000..88166299e --- /dev/null +++ b/src/core/hle/kernel/svc/svc_resource_limit.cpp @@ -0,0 +1,149 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +Result CreateResourceLimit(Core::System& system, Handle* out_handle) { + LOG_DEBUG(Kernel_SVC, "called"); + + // Create a new resource limit. + auto& kernel = system.Kernel(); + KResourceLimit* resource_limit = KResourceLimit::Create(kernel); + R_UNLESS(resource_limit != nullptr, ResultOutOfResource); + + // Ensure we don't leak a reference to the limit. + SCOPE_EXIT({ resource_limit->Close(); }); + + // Initialize the resource limit. + resource_limit->Initialize(&system.CoreTiming()); + + // Register the limit. + KResourceLimit::Register(kernel, resource_limit); + + // Add the limit to the handle table. + R_TRY(GetCurrentProcess(kernel).GetHandleTable().Add(out_handle, resource_limit)); + + return ResultSuccess; +} + +Result GetResourceLimitLimitValue(Core::System& system, s64* out_limit_value, + Handle resource_limit_handle, LimitableResource which) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, + which); + + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + + // Get the resource limit. + KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KResourceLimit>(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + + // Get the limit value. + *out_limit_value = resource_limit->GetLimitValue(which); + + return ResultSuccess; +} + +Result GetResourceLimitCurrentValue(Core::System& system, s64* out_current_value, + Handle resource_limit_handle, LimitableResource which) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, + which); + + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + + // Get the resource limit. + KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KResourceLimit>(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + + // Get the current value. + *out_current_value = resource_limit->GetCurrentValue(which); + + return ResultSuccess; +} + +Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, + LimitableResource which, s64 limit_value) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}", + resource_limit_handle, which, limit_value); + + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + + // Get the resource limit. + KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KResourceLimit>(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + + // Set the limit value. + R_TRY(resource_limit->SetLimitValue(which, limit_value)); + + return ResultSuccess; +} + +Result GetResourceLimitPeakValue(Core::System& system, int64_t* out_peak_value, + Handle resource_limit_handle, LimitableResource which) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result GetResourceLimitLimitValue64(Core::System& system, int64_t* out_limit_value, + Handle resource_limit_handle, LimitableResource which) { + R_RETURN(GetResourceLimitLimitValue(system, out_limit_value, resource_limit_handle, which)); +} + +Result GetResourceLimitCurrentValue64(Core::System& system, int64_t* out_current_value, + Handle resource_limit_handle, LimitableResource which) { + R_RETURN(GetResourceLimitCurrentValue(system, out_current_value, resource_limit_handle, which)); +} + +Result GetResourceLimitPeakValue64(Core::System& system, int64_t* out_peak_value, + Handle resource_limit_handle, LimitableResource which) { + R_RETURN(GetResourceLimitPeakValue(system, out_peak_value, resource_limit_handle, which)); +} + +Result CreateResourceLimit64(Core::System& system, Handle* out_handle) { + R_RETURN(CreateResourceLimit(system, out_handle)); +} + +Result SetResourceLimitLimitValue64(Core::System& system, Handle resource_limit_handle, + LimitableResource which, int64_t limit_value) { + R_RETURN(SetResourceLimitLimitValue(system, resource_limit_handle, which, limit_value)); +} + +Result GetResourceLimitLimitValue64From32(Core::System& system, int64_t* out_limit_value, + Handle resource_limit_handle, LimitableResource which) { + R_RETURN(GetResourceLimitLimitValue(system, out_limit_value, resource_limit_handle, which)); +} + +Result GetResourceLimitCurrentValue64From32(Core::System& system, int64_t* out_current_value, + Handle resource_limit_handle, LimitableResource which) { + R_RETURN(GetResourceLimitCurrentValue(system, out_current_value, resource_limit_handle, which)); +} + +Result GetResourceLimitPeakValue64From32(Core::System& system, int64_t* out_peak_value, + Handle resource_limit_handle, LimitableResource which) { + R_RETURN(GetResourceLimitPeakValue(system, out_peak_value, resource_limit_handle, which)); +} + +Result CreateResourceLimit64From32(Core::System& system, Handle* out_handle) { + R_RETURN(CreateResourceLimit(system, out_handle)); +} + +Result SetResourceLimitLimitValue64From32(Core::System& system, Handle resource_limit_handle, + LimitableResource which, int64_t limit_value) { + R_RETURN(SetResourceLimitLimitValue(system, resource_limit_handle, which, limit_value)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp b/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp new file mode 100644 index 000000000..20f6ec643 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/physical_core.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args) { + UNIMPLEMENTED(); +} + +void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args) { + CallSecureMonitor(system, args); +} + +void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args) { + // CallSecureMonitor64From32 is not supported. + UNIMPLEMENTED_MSG("CallSecureMonitor64From32"); +} + +// Custom ABI for CallSecureMonitor. + +void SvcWrap_CallSecureMonitor64(Core::System& system) { + auto& core = system.CurrentPhysicalCore().ArmInterface(); + lp64::SecureMonitorArguments args{}; + for (int i = 0; i < 8; i++) { + args.r[i] = core.GetReg(i); + } + + CallSecureMonitor64(system, &args); + + for (int i = 0; i < 8; i++) { + core.SetReg(i, args.r[i]); + } +} + +void SvcWrap_CallSecureMonitor64From32(Core::System& system) { + auto& core = system.CurrentPhysicalCore().ArmInterface(); + ilp32::SecureMonitorArguments args{}; + for (int i = 0; i < 8; i++) { + args.r[i] = static_cast<u32>(core.GetReg(i)); + } + + CallSecureMonitor64From32(system, &args); + + for (int i = 0; i < 8; i++) { + core.SetReg(i, args.r[i]); + } +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp new file mode 100644 index 000000000..00fd1605e --- /dev/null +++ b/src/core/hle/kernel/svc/svc_session.cpp @@ -0,0 +1,128 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { +namespace { + +template <typename T> +Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, u64 name) { + auto& process = GetCurrentProcess(system.Kernel()); + auto& handle_table = process.GetHandleTable(); + + // Declare the session we're going to allocate. + T* session; + + // 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); + } + + // Check that we successfully created a session. + R_UNLESS(session != nullptr, ResultOutOfResource); + + // Initialize the session. + session->Initialize(nullptr, fmt::format("{}", name)); + + // Commit the session reservation. + session_reservation.Commit(); + + // 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(); + }); + + // Register the session. + T::Register(system.Kernel(), session); + + // Add the server session to the handle table. + R_TRY(handle_table.Add(out_server, &session->GetServerSession())); + + // Add the client session to the handle table. + const auto result = handle_table.Add(out_client, &session->GetClientSession()); + + if (!R_SUCCEEDED(result)) { + // Ensure that we maintaing a clean handle state on exit. + handle_table.Remove(*out_server); + } + + return result; +} + +} // namespace + +Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light, + u64 name) { + if (is_light) { + // return CreateSession<KLightSession>(system, out_server, out_client, name); + return ResultNotImplemented; + } else { + return CreateSession<KSession>(system, out_server, out_client, name); + } +} + +Result AcceptSession(Core::System& system, Handle* out_handle, Handle port_handle) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result CreateSession64(Core::System& system, Handle* out_server_session_handle, + Handle* out_client_session_handle, bool is_light, uint64_t name) { + R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light, + name)); +} + +Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port) { + R_RETURN(AcceptSession(system, out_handle, port)); +} + +Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle, + Handle* out_client_session_handle, bool is_light, uint32_t name) { + R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light, + name)); +} + +Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port) { + R_RETURN(AcceptSession(system, out_handle, port)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_shared_memory.cpp b/src/core/hle/kernel/svc/svc_shared_memory.cpp new file mode 100644 index 000000000..18e0dc904 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_shared_memory.cpp @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { +namespace { + +constexpr bool IsValidSharedMemoryPermission(MemoryPermission perm) { + switch (perm) { + case MemoryPermission::Read: + case MemoryPermission::ReadWrite: + return true; + default: + return false; + } +} + +[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(MemoryPermission perm) { + return IsValidSharedMemoryPermission(perm) || perm == MemoryPermission::DontCare; +} + +} // namespace + +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); + + // 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); + + // Validate the permission. + R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); + + // Get the current process. + auto& process = GetCurrentProcess(system.Kernel()); + auto& page_table = process.PageTable(); + + // Get the shared memory. + KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); + R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); + + // Verify that the mapping is in range. + R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); + + // Add the shared memory to the process. + R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size)); + + // Ensure that we clean up the shared memory if we fail to map it. + auto guard = + SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); }); + + // Map the shared memory. + R_TRY(shmem->Map(process, address, size, map_perm)); + + // We succeeded. + guard.Cancel(); + return ResultSuccess; +} + +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); + + // Get the current process. + auto& process = GetCurrentProcess(system.Kernel()); + auto& page_table = process.PageTable(); + + // Get the shared memory. + KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); + R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); + + // Verify that the mapping is in range. + R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); + + // Unmap the shared memory. + R_TRY(shmem->Unmap(process, address, size)); + + // Remove the shared memory from the process. + process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); + + return ResultSuccess; +} + +Result CreateSharedMemory(Core::System& system, Handle* out_handle, uint64_t size, + MemoryPermission owner_perm, MemoryPermission remote_perm) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result MapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size, + MemoryPermission map_perm) { + R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm)); +} + +Result UnmapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, + uint64_t size) { + R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size)); +} + +Result CreateSharedMemory64(Core::System& system, Handle* out_handle, uint64_t size, + MemoryPermission owner_perm, MemoryPermission remote_perm) { + R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm)); +} + +Result MapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, + uint32_t size, MemoryPermission map_perm) { + R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm)); +} + +Result UnmapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, + uint32_t size) { + R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size)); +} + +Result CreateSharedMemory64From32(Core::System& system, Handle* out_handle, uint32_t size, + MemoryPermission owner_perm, MemoryPermission remote_perm) { + R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp new file mode 100644 index 000000000..1a8f7e191 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp @@ -0,0 +1,163 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Close a handle +Result CloseHandle(Core::System& system, Handle handle) { + LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); + + // Remove the handle. + R_UNLESS(GetCurrentProcess(system.Kernel()).GetHandleTable().Remove(handle), + ResultInvalidHandle); + + return ResultSuccess; +} + +/// Clears the signaled state of an event or process. +Result ResetSignal(Core::System& system, Handle handle) { + LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); + + // Get the current handle table. + const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); + + // Try to reset as readable event. + { + KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle); + if (readable_event.IsNotNull()) { + return readable_event->Reset(); + } + } + + // Try to reset as process. + { + KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); + if (process.IsNotNull()) { + return process->Reset(); + } + } + + LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle); + + return ResultInvalidHandle; +} + +/// Wait for the given handles to synchronize, timeout after the specified nanoseconds +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); + + // Ensure number of handles is valid. + R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); + + auto& kernel = system.Kernel(); + std::vector<KSynchronizationObject*> objs(num_handles); + const auto& handle_table = GetCurrentProcess(kernel).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); + } + } + + // 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(); + } + }); + + return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()), + nano_seconds); +} + +/// Resumes a thread waiting on WaitSynchronization +Result CancelSynchronization(Core::System& system, Handle handle) { + LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); + + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Cancel the thread's wait. + thread->WaitCancel(); + return ResultSuccess; +} + +void SynchronizePreemptionState(Core::System& system) { + auto& kernel = system.Kernel(); + + // Lock the scheduler. + KScopedSchedulerLock sl{kernel}; + + // If the current thread is pinned, unpin it. + KProcess* cur_process = GetCurrentProcessPointer(kernel); + const auto core_id = GetCurrentCoreId(kernel); + + if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) { + // Clear the current thread's interrupt flag. + GetCurrentThread(kernel).ClearInterruptFlag(); + + // Unpin the current thread. + cur_process->UnpinCurrentThread(core_id); + } +} + +Result CloseHandle64(Core::System& system, Handle handle) { + R_RETURN(CloseHandle(system, handle)); +} + +Result ResetSignal64(Core::System& system, Handle handle) { + R_RETURN(ResetSignal(system, handle)); +} + +Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles, + int32_t num_handles, int64_t timeout_ns) { + R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns)); +} + +Result CancelSynchronization64(Core::System& system, Handle handle) { + R_RETURN(CancelSynchronization(system, handle)); +} + +void SynchronizePreemptionState64(Core::System& system) { + SynchronizePreemptionState(system); +} + +Result CloseHandle64From32(Core::System& system, Handle handle) { + R_RETURN(CloseHandle(system, handle)); +} + +Result ResetSignal64From32(Core::System& system, Handle handle) { + R_RETURN(ResetSignal(system, handle)); +} + +Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles, + int32_t num_handles, int64_t timeout_ns) { + R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns)); +} + +Result CancelSynchronization64From32(Core::System& system, Handle handle) { + R_RETURN(CancelSynchronization(system, handle)); +} + +void SynchronizePreemptionState64From32(Core::System& system) { + SynchronizePreemptionState(system); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp new file mode 100644 index 000000000..b39807841 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_thread.cpp @@ -0,0 +1,437 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { +namespace { + +constexpr bool IsValidVirtualCoreId(int32_t core_id) { + return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); +} + +} // Anonymous namespace + +/// Creates a new thread +Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, + VAddr stack_bottom, s32 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); + + // Adjust core id, if it's the default magic. + auto& kernel = system.Kernel(); + auto& process = GetCurrentProcess(kernel); + if (core_id == IdealCoreUseProcessValue) { + core_id = process.GetIdealCoreId(); + } + + // 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; + } + + 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; + } + + // Reserve a new thread from the process resource limit (waiting up to 100ms). + KScopedResourceReservation thread_reservation(&process, LimitableResource::ThreadCountMax, 1, + system.CoreTiming().GetGlobalTimeNs().count() + + 100000000); + if (!thread_reservation.Succeeded()) { + LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); + return ResultLimitReached; + } + + // 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(); }); + + // Initialize the thread. + { + KScopedLightLock lk{process.GetStateLock()}; + R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom, + priority, core_id, &process)); + } + + // Set the thread name for debugging purposes. + thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle)); + + // Commit the thread reservation. + thread_reservation.Commit(); + + // Register the new thread. + KThread::Register(kernel, thread); + + // Add the thread to the handle table. + R_TRY(process.GetHandleTable().Add(out_handle, thread)); + + return ResultSuccess; +} + +/// Starts the thread for the provided handle +Result StartThread(Core::System& system, Handle thread_handle) { + LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); + + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Try to start the thread. + R_TRY(thread->Run()); + + // If we succeeded, persist a reference to the thread. + thread->Open(); + system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe()); + + return ResultSuccess; +} + +/// Called when a thread exits +void ExitThread(Core::System& system) { + LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); + + auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); + system.GlobalSchedulerContext().RemoveThread(current_thread); + current_thread->Exit(); + system.Kernel().UnregisterInUseObject(current_thread); +} + +/// Sleep the current thread +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); + } +} + +/// Gets the thread context +Result GetThreadContext3(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); + + auto& kernel = system.Kernel(); + + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(kernel).GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Require the handle be to a non-current thread in the current process. + const auto* current_process = GetCurrentProcessPointer(kernel); + R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId); + + // Verify that the thread isn't terminated. + R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested); + + /// 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); + + // Try to get the thread context until the thread isn't current on any core. + while (true) { + KScopedSchedulerLock sl{kernel}; + + // TODO(bunnei): Enforce that thread is suspended for debug here. + + // 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; + } + } + + // If the thread is current, retry until it isn't. + if (current) { + continue; + } + } + + // Get the thread context. + std::vector<u8> context; + R_TRY(thread->GetThreadContext3(context)); + + // Copy the thread context to user space. + system.Memory().WriteBlock(out_context, context.data(), context.size()); + + return ResultSuccess; + } + + return ResultSuccess; +} + +/// Gets the priority for the specified thread +Result GetThreadPriority(Core::System& system, s32* out_priority, Handle handle) { + LOG_TRACE(Kernel_SVC, "called"); + + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Get the thread's priority. + *out_priority = thread->GetPriority(); + return ResultSuccess; +} + +/// Sets the priority for the specified thread +Result SetThreadPriority(Core::System& system, Handle thread_handle, s32 priority) { + // Get the current process. + KProcess& process = GetCurrentProcess(system.Kernel()); + + // Validate the priority. + R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority, + ResultInvalidPriority); + R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority); + + // Get the thread from its handle. + KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Set the thread priority. + thread->SetBasePriority(priority); + return ResultSuccess; +} + +Result GetThreadList(Core::System& system, s32* out_num_threads, VAddr out_thread_ids, + s32 out_thread_ids_size, Handle debug_handle) { + // TODO: Handle this case when debug events are supported. + UNIMPLEMENTED_IF(debug_handle != InvalidHandle); + + LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}", + out_thread_ids, out_thread_ids_size); + + // If the size is negative or larger than INT32_MAX / sizeof(u64) + if ((out_thread_ids_size & 0xF0000000) != 0) { + LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}", + out_thread_ids_size); + return ResultOutOfRange; + } + + auto* const current_process = GetCurrentProcessPointer(system.Kernel()); + const auto total_copy_size = out_thread_ids_size * sizeof(u64); + + 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; + } + + auto& memory = system.Memory(); + const auto& thread_list = current_process->GetThreadList(); + const auto num_threads = thread_list.size(); + const auto copy_amount = std::min(static_cast<std::size_t>(out_thread_ids_size), num_threads); + + auto list_iter = thread_list.cbegin(); + for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { + memory.Write64(out_thread_ids, (*list_iter)->GetThreadID()); + out_thread_ids += sizeof(u64); + } + + *out_num_threads = static_cast<u32>(num_threads); + return ResultSuccess; +} + +Result GetThreadCoreMask(Core::System& system, s32* out_core_id, u64* out_affinity_mask, + Handle thread_handle) { + LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); + + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Get the core mask. + R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); + + return ResultSuccess; +} + +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 = GetCurrentProcess(system.Kernel()).GetIdealCoreId(); + affinity_mask = (1ULL << core_id); + } else { + // Validate the affinity mask. + const u64 process_core_mask = GetCurrentProcess(system.Kernel()).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); + } + } + + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Set the core mask. + R_TRY(thread->SetCoreMask(core_id, affinity_mask)); + + return ResultSuccess; +} + +/// Get the ID for the specified thread. +Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { + // Get the thread from its handle. + KScopedAutoObject thread = + GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Get the thread's id. + *out_thread_id = thread->GetId(); + return ResultSuccess; +} + +Result CreateThread64(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg, + uint64_t stack_bottom, int32_t priority, int32_t core_id) { + R_RETURN(CreateThread(system, out_handle, func, arg, stack_bottom, priority, core_id)); +} + +Result StartThread64(Core::System& system, Handle thread_handle) { + R_RETURN(StartThread(system, thread_handle)); +} + +void ExitThread64(Core::System& system) { + return ExitThread(system); +} + +void SleepThread64(Core::System& system, int64_t ns) { + return SleepThread(system, ns); +} + +Result GetThreadPriority64(Core::System& system, int32_t* out_priority, Handle thread_handle) { + R_RETURN(GetThreadPriority(system, out_priority, thread_handle)); +} + +Result SetThreadPriority64(Core::System& system, Handle thread_handle, int32_t priority) { + R_RETURN(SetThreadPriority(system, thread_handle, priority)); +} + +Result GetThreadCoreMask64(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, + Handle thread_handle) { + R_RETURN(GetThreadCoreMask(system, out_core_id, out_affinity_mask, thread_handle)); +} + +Result SetThreadCoreMask64(Core::System& system, Handle thread_handle, int32_t core_id, + uint64_t affinity_mask) { + R_RETURN(SetThreadCoreMask(system, thread_handle, core_id, affinity_mask)); +} + +Result GetThreadId64(Core::System& system, uint64_t* out_thread_id, Handle thread_handle) { + R_RETURN(GetThreadId(system, out_thread_id, thread_handle)); +} + +Result GetThreadContext364(Core::System& system, uint64_t out_context, Handle thread_handle) { + R_RETURN(GetThreadContext3(system, out_context, thread_handle)); +} + +Result GetThreadList64(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids, + int32_t max_out_count, Handle debug_handle) { + R_RETURN(GetThreadList(system, out_num_threads, out_thread_ids, max_out_count, debug_handle)); +} + +Result CreateThread64From32(Core::System& system, Handle* out_handle, uint32_t func, uint32_t arg, + uint32_t stack_bottom, int32_t priority, int32_t core_id) { + R_RETURN(CreateThread(system, out_handle, func, arg, stack_bottom, priority, core_id)); +} + +Result StartThread64From32(Core::System& system, Handle thread_handle) { + R_RETURN(StartThread(system, thread_handle)); +} + +void ExitThread64From32(Core::System& system) { + return ExitThread(system); +} + +void SleepThread64From32(Core::System& system, int64_t ns) { + return SleepThread(system, ns); +} + +Result GetThreadPriority64From32(Core::System& system, int32_t* out_priority, + Handle thread_handle) { + R_RETURN(GetThreadPriority(system, out_priority, thread_handle)); +} + +Result SetThreadPriority64From32(Core::System& system, Handle thread_handle, int32_t priority) { + R_RETURN(SetThreadPriority(system, thread_handle, priority)); +} + +Result GetThreadCoreMask64From32(Core::System& system, int32_t* out_core_id, + uint64_t* out_affinity_mask, Handle thread_handle) { + R_RETURN(GetThreadCoreMask(system, out_core_id, out_affinity_mask, thread_handle)); +} + +Result SetThreadCoreMask64From32(Core::System& system, Handle thread_handle, int32_t core_id, + uint64_t affinity_mask) { + R_RETURN(SetThreadCoreMask(system, thread_handle, core_id, affinity_mask)); +} + +Result GetThreadId64From32(Core::System& system, uint64_t* out_thread_id, Handle thread_handle) { + R_RETURN(GetThreadId(system, out_thread_id, thread_handle)); +} + +Result GetThreadContext364From32(Core::System& system, uint32_t out_context, Handle thread_handle) { + R_RETURN(GetThreadContext3(system, out_context, thread_handle)); +} + +Result GetThreadList64From32(Core::System& system, int32_t* out_num_threads, + uint32_t out_thread_ids, int32_t max_out_count, Handle debug_handle) { + R_RETURN(GetThreadList(system, out_num_threads, out_thread_ids, max_out_count, debug_handle)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_thread_profiler.cpp b/src/core/hle/kernel/svc/svc_thread_profiler.cpp new file mode 100644 index 000000000..40de7708b --- /dev/null +++ b/src/core/hle/kernel/svc/svc_thread_profiler.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel::Svc { + +Result GetDebugFutureThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, + uint64_t* out_thread_id, Handle debug_handle, int64_t ns) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result GetLastThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, + uint64_t* out_tls_address, uint32_t* out_flags) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result GetDebugFutureThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, + uint64_t* out_thread_id, Handle debug_handle, int64_t ns) { + R_RETURN(GetDebugFutureThreadInfo(system, out_context, out_thread_id, debug_handle, ns)); +} + +Result GetLastThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, + uint64_t* out_tls_address, uint32_t* out_flags) { + R_RETURN(GetLastThreadInfo(system, out_context, out_tls_address, out_flags)); +} + +Result GetDebugFutureThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, + uint64_t* out_thread_id, Handle debug_handle, int64_t ns) { + lp64::LastThreadContext context{}; + R_TRY( + GetDebugFutureThreadInfo(system, std::addressof(context), out_thread_id, debug_handle, ns)); + + *out_context = { + .fp = static_cast<u32>(context.fp), + .sp = static_cast<u32>(context.sp), + .lr = static_cast<u32>(context.lr), + .pc = static_cast<u32>(context.pc), + }; + R_SUCCEED(); +} + +Result GetLastThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, + uint64_t* out_tls_address, uint32_t* out_flags) { + lp64::LastThreadContext context{}; + R_TRY(GetLastThreadInfo(system, std::addressof(context), out_tls_address, out_flags)); + + *out_context = { + .fp = static_cast<u32>(context.fp), + .sp = static_cast<u32>(context.sp), + .lr = static_cast<u32>(context.lr), + .pc = static_cast<u32>(context.pc), + }; + R_SUCCEED(); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_tick.cpp b/src/core/hle/kernel/svc/svc_tick.cpp new file mode 100644 index 000000000..561336482 --- /dev/null +++ b/src/core/hle/kernel/svc/svc_tick.cpp @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// This returns the total CPU ticks elapsed since the CPU was powered-on +int64_t GetSystemTick(Core::System& system) { + LOG_TRACE(Kernel_SVC, "called"); + + auto& core_timing = system.CoreTiming(); + + // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) + const u64 result{core_timing.GetClockTicks()}; + + if (!system.Kernel().IsMulticore()) { + core_timing.AddTicks(400U); + } + + return static_cast<int64_t>(result); +} + +int64_t GetSystemTick64(Core::System& system) { + return GetSystemTick(system); +} + +int64_t GetSystemTick64From32(Core::System& system) { + return GetSystemTick(system); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp new file mode 100644 index 000000000..7ffc24adf --- /dev/null +++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp @@ -0,0 +1,117 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { +namespace { + +constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { + switch (perm) { + case MemoryPermission::None: + case MemoryPermission::Read: + case MemoryPermission::ReadWrite: + return true; + default: + return false; + } +} + +} // Anonymous namespace + +/// Creates a TransferMemory object +Result CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, + MemoryPermission map_perm) { + auto& kernel = system.Kernel(); + + // 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); + + // Validate the permissions. + R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); + + // Get the current process and handle table. + auto& process = GetCurrentProcess(kernel); + auto& handle_table = process.GetHandleTable(); + + // Reserve a new transfer memory from the process resource limit. + KScopedResourceReservation trmem_reservation(&process, + LimitableResource::TransferMemoryCountMax); + R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached); + + // Create the transfer memory. + KTransferMemory* trmem = KTransferMemory::Create(kernel); + R_UNLESS(trmem != nullptr, ResultOutOfResource); + + // Ensure the only reference is in the handle table when we're done. + SCOPE_EXIT({ trmem->Close(); }); + + // Ensure that the region is in range. + R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory); + + // Initialize the transfer memory. + R_TRY(trmem->Initialize(address, size, map_perm)); + + // Commit the reservation. + trmem_reservation.Commit(); + + // Register the transfer memory. + KTransferMemory::Register(kernel, trmem); + + // Add the transfer memory to the handle table. + R_TRY(handle_table.Add(out, trmem)); + + return ResultSuccess; +} + +Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, + MemoryPermission owner_perm) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, + uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, + uint64_t size, MemoryPermission owner_perm) { + R_RETURN(MapTransferMemory(system, trmem_handle, address, size, owner_perm)); +} + +Result UnmapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, + uint64_t size) { + R_RETURN(UnmapTransferMemory(system, trmem_handle, address, size)); +} + +Result CreateTransferMemory64(Core::System& system, Handle* out_handle, uint64_t address, + uint64_t size, MemoryPermission map_perm) { + R_RETURN(CreateTransferMemory(system, out_handle, address, size, map_perm)); +} + +Result MapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, + uint32_t size, MemoryPermission owner_perm) { + R_RETURN(MapTransferMemory(system, trmem_handle, address, size, owner_perm)); +} + +Result UnmapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, + uint32_t size) { + R_RETURN(UnmapTransferMemory(system, trmem_handle, address, size)); +} + +Result CreateTransferMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, + uint32_t size, MemoryPermission map_perm) { + R_RETURN(CreateTransferMemory(system, out_handle, address, size, map_perm)); +} + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc_generator.py b/src/core/hle/kernel/svc_generator.py new file mode 100644 index 000000000..34d2ac659 --- /dev/null +++ b/src/core/hle/kernel/svc_generator.py @@ -0,0 +1,716 @@ +# SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +# Raw SVC definitions from the kernel. +# +# Avoid modifying the prototypes; see below for how to customize generation +# for a given typename. +SVCS = [ + [0x01, "Result SetHeapSize(Address* out_address, Size size);"], + [0x02, "Result SetMemoryPermission(Address address, Size size, MemoryPermission perm);"], + [0x03, "Result SetMemoryAttribute(Address address, Size size, uint32_t mask, uint32_t attr);"], + [0x04, "Result MapMemory(Address dst_address, Address src_address, Size size);"], + [0x05, "Result UnmapMemory(Address dst_address, Address src_address, Size size);"], + [0x06, "Result QueryMemory(Address out_memory_info, PageInfo* out_page_info, Address address);"], + [0x07, "void ExitProcess();"], + [0x08, "Result CreateThread(Handle* out_handle, ThreadFunc func, Address arg, Address stack_bottom, int32_t priority, int32_t core_id);"], + [0x09, "Result StartThread(Handle thread_handle);"], + [0x0A, "void ExitThread();"], + [0x0B, "void SleepThread(int64_t ns);"], + [0x0C, "Result GetThreadPriority(int32_t* out_priority, Handle thread_handle);"], + [0x0D, "Result SetThreadPriority(Handle thread_handle, int32_t priority);"], + [0x0E, "Result GetThreadCoreMask(int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);"], + [0x0F, "Result SetThreadCoreMask(Handle thread_handle, int32_t core_id, uint64_t affinity_mask);"], + [0x10, "int32_t GetCurrentProcessorNumber();"], + [0x11, "Result SignalEvent(Handle event_handle);"], + [0x12, "Result ClearEvent(Handle event_handle);"], + [0x13, "Result MapSharedMemory(Handle shmem_handle, Address address, Size size, MemoryPermission map_perm);"], + [0x14, "Result UnmapSharedMemory(Handle shmem_handle, Address address, Size size);"], + [0x15, "Result CreateTransferMemory(Handle* out_handle, Address address, Size size, MemoryPermission map_perm);"], + [0x16, "Result CloseHandle(Handle handle);"], + [0x17, "Result ResetSignal(Handle handle);"], + [0x18, "Result WaitSynchronization(int32_t* out_index, Address handles, int32_t num_handles, int64_t timeout_ns);"], + [0x19, "Result CancelSynchronization(Handle handle);"], + [0x1A, "Result ArbitrateLock(Handle thread_handle, Address address, uint32_t tag);"], + [0x1B, "Result ArbitrateUnlock(Address address);"], + [0x1C, "Result WaitProcessWideKeyAtomic(Address address, Address cv_key, uint32_t tag, int64_t timeout_ns);"], + [0x1D, "void SignalProcessWideKey(Address cv_key, int32_t count);"], + [0x1E, "int64_t GetSystemTick();"], + [0x1F, "Result ConnectToNamedPort(Handle* out_handle, Address name);"], + [0x20, "Result SendSyncRequestLight(Handle session_handle);"], + [0x21, "Result SendSyncRequest(Handle session_handle);"], + [0x22, "Result SendSyncRequestWithUserBuffer(Address message_buffer, Size message_buffer_size, Handle session_handle);"], + [0x23, "Result SendAsyncRequestWithUserBuffer(Handle* out_event_handle, Address message_buffer, Size message_buffer_size, Handle session_handle);"], + [0x24, "Result GetProcessId(uint64_t* out_process_id, Handle process_handle);"], + [0x25, "Result GetThreadId(uint64_t* out_thread_id, Handle thread_handle);"], + [0x26, "void Break(BreakReason break_reason, Address arg, Size size);"], + [0x27, "Result OutputDebugString(Address debug_str, Size len);"], + [0x28, "void ReturnFromException(Result result);"], + [0x29, "Result GetInfo(uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);"], + [0x2A, "void FlushEntireDataCache();"], + [0x2B, "Result FlushDataCache(Address address, Size size);"], + [0x2C, "Result MapPhysicalMemory(Address address, Size size);"], + [0x2D, "Result UnmapPhysicalMemory(Address address, Size size);"], + [0x2E, "Result GetDebugFutureThreadInfo(LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);"], + [0x2F, "Result GetLastThreadInfo(LastThreadContext* out_context, Address* out_tls_address, uint32_t* out_flags);"], + [0x30, "Result GetResourceLimitLimitValue(int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);"], + [0x31, "Result GetResourceLimitCurrentValue(int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);"], + [0x32, "Result SetThreadActivity(Handle thread_handle, ThreadActivity thread_activity);"], + [0x33, "Result GetThreadContext3(Address out_context, Handle thread_handle);"], + [0x34, "Result WaitForAddress(Address address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);"], + [0x35, "Result SignalToAddress(Address address, SignalType signal_type, int32_t value, int32_t count);"], + [0x36, "void SynchronizePreemptionState();"], + [0x37, "Result GetResourceLimitPeakValue(int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);"], + + [0x39, "Result CreateIoPool(Handle* out_handle, IoPoolType which);"], + [0x3A, "Result CreateIoRegion(Handle* out_handle, Handle io_pool, PhysicalAddress physical_address, Size size, MemoryMapping mapping, MemoryPermission perm);"], + + [0x3C, "void KernelDebug(KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);"], + [0x3D, "void ChangeKernelTraceState(KernelTraceState kern_trace_state);"], + + [0x40, "Result CreateSession(Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, Address name);"], + [0x41, "Result AcceptSession(Handle* out_handle, Handle port);"], + [0x42, "Result ReplyAndReceiveLight(Handle handle);"], + [0x43, "Result ReplyAndReceive(int32_t* out_index, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"], + [0x44, "Result ReplyAndReceiveWithUserBuffer(int32_t* out_index, Address message_buffer, Size message_buffer_size, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"], + [0x45, "Result CreateEvent(Handle* out_write_handle, Handle* out_read_handle);"], + [0x46, "Result MapIoRegion(Handle io_region, Address address, Size size, MemoryPermission perm);"], + [0x47, "Result UnmapIoRegion(Handle io_region, Address address, Size size);"], + [0x48, "Result MapPhysicalMemoryUnsafe(Address address, Size size);"], + [0x49, "Result UnmapPhysicalMemoryUnsafe(Address address, Size size);"], + [0x4A, "Result SetUnsafeLimit(Size limit);"], + [0x4B, "Result CreateCodeMemory(Handle* out_handle, Address address, Size size);"], + [0x4C, "Result ControlCodeMemory(Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);"], + [0x4D, "void SleepSystem();"], + [0x4E, "Result ReadWriteRegister(uint32_t* out_value, PhysicalAddress address, uint32_t mask, uint32_t value);"], + [0x4F, "Result SetProcessActivity(Handle process_handle, ProcessActivity process_activity);"], + [0x50, "Result CreateSharedMemory(Handle* out_handle, Size size, MemoryPermission owner_perm, MemoryPermission remote_perm);"], + [0x51, "Result MapTransferMemory(Handle trmem_handle, Address address, Size size, MemoryPermission owner_perm);"], + [0x52, "Result UnmapTransferMemory(Handle trmem_handle, Address address, Size size);"], + [0x53, "Result CreateInterruptEvent(Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);"], + [0x54, "Result QueryPhysicalAddress(PhysicalMemoryInfo* out_info, Address address);"], + [0x55, "Result QueryIoMapping(Address* out_address, Size* out_size, PhysicalAddress physical_address, Size size);"], + [0x56, "Result CreateDeviceAddressSpace(Handle* out_handle, uint64_t das_address, uint64_t das_size);"], + [0x57, "Result AttachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"], + [0x58, "Result DetachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"], + [0x59, "Result MapDeviceAddressSpaceByForce(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"], + [0x5A, "Result MapDeviceAddressSpaceAligned(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"], + [0x5C, "Result UnmapDeviceAddressSpace(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address);"], + [0x5D, "Result InvalidateProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"], + [0x5E, "Result StoreProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"], + [0x5F, "Result FlushProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"], + [0x60, "Result DebugActiveProcess(Handle* out_handle, uint64_t process_id);"], + [0x61, "Result BreakDebugProcess(Handle debug_handle);"], + [0x62, "Result TerminateDebugProcess(Handle debug_handle);"], + [0x63, "Result GetDebugEvent(Address out_info, Handle debug_handle);"], + [0x64, "Result ContinueDebugEvent(Handle debug_handle, uint32_t flags, Address thread_ids, int32_t num_thread_ids);"], + [0x65, "Result GetProcessList(int32_t* out_num_processes, Address out_process_ids, int32_t max_out_count);"], + [0x66, "Result GetThreadList(int32_t* out_num_threads, Address out_thread_ids, int32_t max_out_count, Handle debug_handle);"], + [0x67, "Result GetDebugThreadContext(Address out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);"], + [0x68, "Result SetDebugThreadContext(Handle debug_handle, uint64_t thread_id, Address context, uint32_t context_flags);"], + [0x69, "Result QueryDebugProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, Address address);"], + [0x6A, "Result ReadDebugProcessMemory(Address buffer, Handle debug_handle, Address address, Size size);"], + [0x6B, "Result WriteDebugProcessMemory(Handle debug_handle, Address buffer, Address address, Size size);"], + [0x6C, "Result SetHardwareBreakPoint(HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);"], + [0x6D, "Result GetDebugThreadParam(uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);"], + + [0x6F, "Result GetSystemInfo(uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);"], + [0x70, "Result CreatePort(Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, Address name);"], + [0x71, "Result ManageNamedPort(Handle* out_server_handle, Address name, int32_t max_sessions);"], + [0x72, "Result ConnectToPort(Handle* out_handle, Handle port);"], + [0x73, "Result SetProcessMemoryPermission(Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);"], + [0x74, "Result MapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"], + [0x75, "Result UnmapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"], + [0x76, "Result QueryProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);"], + [0x77, "Result MapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"], + [0x78, "Result UnmapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"], + [0x79, "Result CreateProcess(Handle* out_handle, Address parameters, Address caps, int32_t num_caps);"], + [0x7A, "Result StartProcess(Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);"], + [0x7B, "Result TerminateProcess(Handle process_handle);"], + [0x7C, "Result GetProcessInfo(int64_t* out_info, Handle process_handle, ProcessInfoType info_type);"], + [0x7D, "Result CreateResourceLimit(Handle* out_handle);"], + [0x7E, "Result SetResourceLimitLimitValue(Handle resource_limit_handle, LimitableResource which, int64_t limit_value);"], + [0x7F, "void CallSecureMonitor(SecureMonitorArguments args);"], + + [0x90, "Result MapInsecureMemory(Address address, Size size);"], + [0x91, "Result UnmapInsecureMemory(Address address, Size size);"], +] + +# These use a custom ABI, and therefore require custom wrappers +SKIP_WRAPPERS = { + 0x20: "SendSyncRequestLight", + 0x42: "ReplyAndReceiveLight", + 0x7F: "CallSecureMonitor", +} + +BIT_32 = 0 +BIT_64 = 1 + +REG_SIZES = [4, 8] +SUFFIX_NAMES = ["64From32", "64"] +TYPE_SIZES = { + # SVC types + "ArbitrationType": 4, + "BreakReason": 4, + "CodeMemoryOperation": 4, + "DebugThreadParam": 4, + "DeviceName": 4, + "HardwareBreakPointRegisterName": 4, + "Handle": 4, + "InfoType": 4, + "InterruptType": 4, + "IoPoolType": 4, + "KernelDebugType": 4, + "KernelTraceState": 4, + "LimitableResource": 4, + "MemoryMapping": 4, + "MemoryPermission": 4, + "PageInfo": 4, + "ProcessActivity": 4, + "ProcessInfoType": 4, + "Result": 4, + "SignalType": 4, + "SystemInfoType": 4, + "ThreadActivity": 4, + + # Arch-specific types + "ilp32::LastThreadContext": 16, + "ilp32::PhysicalMemoryInfo": 16, + "ilp32::SecureMonitorArguments": 32, + "lp64::LastThreadContext": 32, + "lp64::PhysicalMemoryInfo": 24, + "lp64::SecureMonitorArguments": 64, + + # Generic types + "bool": 1, + "int32_t": 4, + "int64_t": 8, + "uint32_t": 4, + "uint64_t": 8, + "void": 0, +} + +TYPE_REPLACEMENTS = { + "Address": ["uint32_t", "uint64_t"], + "LastThreadContext": ["ilp32::LastThreadContext", "lp64::LastThreadContext"], + "PhysicalAddress": ["uint64_t", "uint64_t"], + "PhysicalMemoryInfo": ["ilp32::PhysicalMemoryInfo", "lp64::PhysicalMemoryInfo"], + "SecureMonitorArguments": ["ilp32::SecureMonitorArguments", "lp64::SecureMonitorArguments"], + "Size": ["uint32_t", "uint64_t"], + "ThreadFunc": ["uint32_t", "uint64_t"], +} + +# Statically verify that the hardcoded sizes match the intended +# sizes in C++. +def emit_size_check(): + lines = [] + + for type, size in TYPE_SIZES.items(): + if type != "void": + lines.append(f"static_assert(sizeof({type}) == {size});") + + return "\n".join(lines) + + +# Replaces a type with an arch-specific one, if it exists. +def substitute_type(name, bitness): + if name in TYPE_REPLACEMENTS: + return TYPE_REPLACEMENTS[name][bitness] + else: + return name + + +class Argument: + def __init__(self, type_name, var_name, is_output, is_outptr, is_address): + self.type_name = type_name + self.var_name = var_name + self.is_output = is_output + self.is_outptr = is_outptr + self.is_address = is_address + + +# Parses C-style string declarations for SVCs. +def parse_declaration(declaration, bitness): + return_type, rest = declaration.split(" ", 1) + func_name, rest = rest.split("(", 1) + arg_names, rest = rest.split(")", 1) + argument_types = [] + + return_type = substitute_type(return_type, bitness) + assert return_type in TYPE_SIZES, f"Unknown type '{return_type}'" + + if arg_names: + for arg_name in arg_names.split(", "): + type_name, var_name = arg_name.replace("*", "").split(" ", 1) + + # All outputs must contain out_ in the name. + is_output = var_name == "out" or var_name.find("out_") != -1 + + # User-pointer outputs are not written to registers. + is_outptr = is_output and arg_name.find("*") == -1 + + # Special handling is performed for output addresses to avoid awkwardness + # in conversion for the 32-bit equivalents. + is_address = is_output and not is_outptr and \ + type_name in ["Address", "Size"] + type_name = substitute_type(type_name, bitness) + + assert type_name in TYPE_SIZES, f"Unknown type '{type_name}'" + + argument_types.append( + Argument(type_name, var_name, is_output, is_outptr, is_address)) + + return (return_type, func_name, argument_types) + + +class RegisterAllocator: + def __init__(self, num_regs, byte_size, parameter_count): + self.registers = {} + self.num_regs = num_regs + self.byte_size = byte_size + self.parameter_count = parameter_count + + # Mark the given register as allocated, for use in layout + # calculation if the NGRN exceeds the ABI parameter count. + def allocate(self, i): + assert i not in self.registers, f"Register R{i} already allocated" + self.registers[i] = True + return i + + # Calculate the next available location for a register; + # the NGRN has exceeded the ABI parameter count. + def allocate_first_free(self): + for i in range(0, self.num_regs): + if i in self.registers: + continue + + self.allocate(i) + return i + + assert False, "No registers available" + + # Add a single register at the given NGRN. + # If the index exceeds the ABI parameter count, try to find a + # location to add it. Returns the output location and increment. + def add_single(self, ngrn): + if ngrn >= self.parameter_count: + return (self.allocate_first_free(), 0) + else: + return (self.allocate(ngrn), 1) + + # Add registers at the given NGRN for a data type of + # the given size. Returns the output locations and increment. + def add(self, ngrn, data_size, align=True): + if data_size <= self.byte_size: + r, i = self.add_single(ngrn) + return ([r], i) + + regs = [] + inc = ngrn % 2 if align else 0 + remaining_size = data_size + while remaining_size > 0: + r, i = self.add_single(ngrn + inc) + regs.append(r) + inc += i + remaining_size -= self.byte_size + + return (regs, inc) + + +def reg_alloc(bitness): + if bitness == 0: + # aapcs32: 4 4-byte registers + return RegisterAllocator(8, 4, 4) + elif bitness == 1: + # aapcs64: 8 8-byte registers + return RegisterAllocator(8, 8, 8) + + +# Converts a parsed SVC declaration into register lists for +# the return value, outputs, and inputs. +def get_registers(parse_result, bitness): + output_alloc = reg_alloc(bitness) + input_alloc = reg_alloc(bitness) + return_type, _, arguments = parse_result + + return_write = [] + output_writes = [] + input_reads = [] + + input_ngrn = 0 + output_ngrn = 0 + + # Run the input calculation. + for arg in arguments: + if arg.is_output and not arg.is_outptr: + input_ngrn += 1 + continue + + regs, increment = input_alloc.add( + input_ngrn, TYPE_SIZES[arg.type_name], align=True) + input_reads.append([arg.type_name, arg.var_name, regs]) + input_ngrn += increment + + # Include the return value if this SVC returns a value. + if return_type != "void": + regs, increment = output_alloc.add( + output_ngrn, TYPE_SIZES[return_type], align=False) + return_write.append([return_type, regs]) + output_ngrn += increment + + # Run the output calculation. + for arg in arguments: + if not arg.is_output or arg.is_outptr: + continue + + regs, increment = output_alloc.add( + output_ngrn, TYPE_SIZES[arg.type_name], align=False) + output_writes.append( + [arg.type_name, arg.var_name, regs, arg.is_address]) + output_ngrn += increment + + return (return_write, output_writes, input_reads) + + +# Collects possibly multiple source registers into the named C++ value. +def emit_gather(sources, name, type_name, reg_size): + get_fn = f"GetReg{reg_size*8}" + + if len(sources) == 1: + s, = sources + line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));" + return [line] + + var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>" + lines = [ + f"{var_type} {name}_gather{{}};" + ] + for i in range(0, len(sources)): + lines.append( + f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});") + + lines.append(f"{name} = Convert<{type_name}>({name}_gather);") + return lines + + +# Produces one or more statements which assign the named C++ value +# into possibly multiple registers. +def emit_scatter(destinations, name, reg_size): + set_fn = f"SetReg{reg_size*8}" + reg_type = f"uint{reg_size*8}_t" + + if len(destinations) == 1: + d, = destinations + line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));" + return [line] + + var_type = f"std::array<{reg_type}, {len(destinations)}>" + lines = [ + f"auto {name}_scatter = Convert<{var_type}>({name});" + ] + + for i in range(0, len(destinations)): + lines.append( + f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);") + + return lines + + +def emit_lines(lines, indent=' '): + output_lines = [] + first = True + for line in lines: + if line and not first: + output_lines.append(indent + line) + else: + output_lines.append(line) + first = False + + return "\n".join(output_lines) + + +# Emit a C++ function to wrap a guest SVC. +def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size): + return_write, output_writes, input_reads = register_info + lines = [ + f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{" + ] + + # Get everything ready. + for return_type, _ in return_write: + lines.append(f"{return_type} ret{{}};") + if return_write: + lines.append("") + + for output_type, var_name, _, is_address in output_writes: + output_type = "uintptr_t" if is_address else output_type + lines.append(f"{output_type} {var_name}{{}};") + for input_type, var_name, _ in input_reads: + lines.append(f"{input_type} {var_name}{{}};") + + if output_writes or input_reads: + lines.append("") + + for input_type, var_name, sources in input_reads: + lines += emit_gather(sources, var_name, input_type, byte_size) + if input_reads: + lines.append("") + + # Build the call. + call_arguments = ["system"] + for arg in arguments: + if arg.is_output and not arg.is_outptr: + call_arguments.append(f"&{arg.var_name}") + else: + call_arguments.append(arg.var_name) + + line = "" + if return_write: + line += "ret = " + + line += f"{wrapped_fn}{suffix}({', '.join(call_arguments)});" + lines.append(line) + + if return_write or output_writes: + lines.append("") + + # Write back the return value and outputs. + for _, destinations in return_write: + lines += emit_scatter(destinations, "ret", byte_size) + for _, var_name, destinations, _ in output_writes: + lines += emit_scatter(destinations, var_name, byte_size) + + # Finish. + return emit_lines(lines) + "\n}" + + +COPYRIGHT = """\ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// This file is automatically generated using svc_generator.py. +""" + +PROLOGUE_H = """ +#pragma once + +namespace Core { +class System; +} + +#include "common/common_types.h" +#include "core/hle/kernel/svc_types.h" +#include "core/hle/result.h" + +namespace Kernel::Svc { + +// clang-format off +""" + +EPILOGUE_H = """ +// clang-format on + +// Custom ABI. +Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args); +Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args); +Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args); + +Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args); +Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args); +Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args); + +void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args); +void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args); +void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args); + +// Defined in svc_light_ipc.cpp. +void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system); +void SvcWrap_ReplyAndReceiveLight64(Core::System& system); + +void SvcWrap_SendSyncRequestLight64From32(Core::System& system); +void SvcWrap_SendSyncRequestLight64(Core::System& system); + +// Defined in svc_secure_monitor_call.cpp. +void SvcWrap_CallSecureMonitor64From32(Core::System& system); +void SvcWrap_CallSecureMonitor64(Core::System& system); + +// Perform a supervisor call by index. +void Call(Core::System& system, u32 imm); + +} // namespace Kernel::Svc +""" + +PROLOGUE_CPP = """ +#include <type_traits> + +#include "core/arm/arm_interface.h" +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +static uint32_t GetReg32(Core::System& system, int n) { + return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n)); +} + +static void SetReg32(Core::System& system, int n, uint32_t result) { + system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result)); +} + +static uint64_t GetReg64(Core::System& system, int n) { + return system.CurrentArmInterface().GetReg(n); +} + +static void SetReg64(Core::System& system, int n, uint64_t result) { + system.CurrentArmInterface().SetReg(n, result); +} + +// 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 constexpr (sizeof(To) >= sizeof(From)) { + std::memcpy(&to, &from, sizeof(From)); + } else { + std::memcpy(&to, &from, sizeof(To)); + } + + return to; +} + +// clang-format off +""" + +EPILOGUE_CPP = """ +// clang-format on + +void Call(Core::System& system, u32 imm) { + auto& kernel = system.Kernel(); + kernel.EnterSVCProfile(); + + if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) { + Call64(system, imm); + } else { + Call32(system, imm); + } + + kernel.ExitSVCProfile(); +} + +} // namespace Kernel::Svc +""" + + +def emit_call(bitness, names, suffix): + bit_size = REG_SIZES[bitness]*8 + indent = " " + lines = [ + f"static void Call{bit_size}(Core::System& system, u32 imm) {{", + f"{indent}switch (static_cast<SvcId>(imm)) {{" + ] + + for _, name in names: + lines.append(f"{indent}case SvcId::{name}:") + lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);") + + lines.append(f"{indent}default:") + lines.append( + f"{indent*2}LOG_CRITICAL(Kernel_SVC, \"Unknown SVC {{:x}}!\", imm);") + lines.append(f"{indent*2}break;") + lines.append(f"{indent}}}") + lines.append("}") + + return "\n".join(lines) + + +def build_fn_declaration(return_type, name, arguments): + arg_list = ["Core::System& system"] + for arg in arguments: + type_name = "uintptr_t" if arg.is_address else arg.type_name + pointer = "*" if arg.is_output and not arg.is_outptr else "" + arg_list.append(f"{type_name}{pointer} {arg.var_name}") + + return f"{return_type} {name}({', '.join(arg_list)});" + + +def build_enum_declarations(): + lines = ["enum class SvcId : u32 {"] + indent = " " + + for imm, decl in SVCS: + _, name, _ = parse_declaration(decl, BIT_64) + lines.append(f"{indent}{name} = {hex(imm)},") + + lines.append("};") + return "\n".join(lines) + + +def main(): + arch_fw_declarations = [[], []] + svc_fw_declarations = [] + wrapper_fns = [] + names = [] + + for imm, decl in SVCS: + return_type, name, arguments = parse_declaration(decl, BIT_64) + + if imm not in SKIP_WRAPPERS: + svc_fw_declarations.append( + build_fn_declaration(return_type, name, arguments)) + + names.append([imm, name]) + + for bitness in range(2): + byte_size = REG_SIZES[bitness] + suffix = SUFFIX_NAMES[bitness] + + for imm, decl in SVCS: + if imm in SKIP_WRAPPERS: + continue + + parse_result = parse_declaration(decl, bitness) + return_type, name, arguments = parse_result + + register_info = get_registers(parse_result, bitness) + wrapper_fns.append( + emit_wrapper(name, suffix, register_info, arguments, byte_size)) + arch_fw_declarations[bitness].append( + build_fn_declaration(return_type, name + suffix, arguments)) + + call_32 = emit_call(BIT_32, names, SUFFIX_NAMES[BIT_32]) + call_64 = emit_call(BIT_64, names, SUFFIX_NAMES[BIT_64]) + enum_decls = build_enum_declarations() + + with open("svc.h", "w") as f: + f.write(COPYRIGHT) + f.write(PROLOGUE_H) + f.write("\n".join(svc_fw_declarations)) + f.write("\n\n") + f.write("\n".join(arch_fw_declarations[BIT_32])) + f.write("\n\n") + f.write("\n".join(arch_fw_declarations[BIT_64])) + f.write("\n\n") + f.write(enum_decls) + f.write(EPILOGUE_H) + + with open("svc.cpp", "w") as f: + f.write(COPYRIGHT) + f.write(PROLOGUE_CPP) + f.write(emit_size_check()) + f.write("\n\n") + f.write("\n\n".join(wrapper_fns)) + f.write("\n\n") + f.write(call_32) + f.write("\n\n") + f.write(call_64) + f.write(EPILOGUE_CPP) + + print(f"Done (emitted {len(names)} definitions)") + + +if __name__ == "__main__": + main() diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index b7ca53085..e1ad78607 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h @@ -11,6 +11,7 @@ namespace Kernel { constexpr Result ResultOutOfSessions{ErrorModule::Kernel, 7}; constexpr Result ResultInvalidArgument{ErrorModule::Kernel, 14}; +constexpr Result ResultNotImplemented{ErrorModule::Kernel, 33}; constexpr Result ResultNoSynchronizationObject{ErrorModule::Kernel, 57}; constexpr Result ResultTerminationRequested{ErrorModule::Kernel, 59}; constexpr Result ResultInvalidSize{ErrorModule::Kernel, 101}; diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 33eebcef6..542c13461 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h @@ -3,6 +3,9 @@ #pragma once +#include <bitset> + +#include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" @@ -165,6 +168,7 @@ enum class BreakReason : u32 { NotificationOnlyFlag = 0x80000000, }; +DECLARE_ENUM_FLAG_OPERATORS(BreakReason); enum class DebugEvent : u32 { CreateProcess = 0, @@ -496,6 +500,19 @@ enum class MemoryMapping : u32 { Memory = 2, }; +enum class MapDeviceAddressSpaceFlag : u32 { + None = (0U << 0), + NotIoRegister = (1U << 0), +}; +DECLARE_ENUM_FLAG_OPERATORS(MapDeviceAddressSpaceFlag); + +union MapDeviceAddressSpaceOption { + u32 raw; + BitField<0, 16, MemoryPermission> permission; + BitField<16, 1, MapDeviceAddressSpaceFlag> flags; + BitField<17, 15, u32> reserved; +}; + enum class KernelDebugType : u32 { Thread = 0, ThreadCallStack = 1, @@ -580,6 +597,11 @@ enum class ProcessInfoType : u32 { ProcessState = 0, }; +enum class ProcessActivity : u32 { + Runnable, + Paused, +}; + struct CreateProcessParameter { std::array<char, 12> name; u32 version; @@ -592,4 +614,12 @@ struct CreateProcessParameter { }; static_assert(sizeof(CreateProcessParameter) == 0x30); +constexpr size_t NumSupervisorCalls = 0xC0; +using SvcAccessFlagSet = std::bitset<NumSupervisorCalls>; + +enum class InitialProcessIdRangeInfo : u64 { + Minimum = 0, + Maximum = 1, +}; + } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc_version.h b/src/core/hle/kernel/svc_version.h new file mode 100644 index 000000000..3eb95aa7b --- /dev/null +++ b/src/core/hle/kernel/svc_version.h @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/literals.h" + +namespace Kernel::Svc { + +constexpr inline u32 ConvertToSvcMajorVersion(u32 sdk) { + return sdk + 4; +} +constexpr inline u32 ConvertToSdkMajorVersion(u32 svc) { + return svc - 4; +} + +constexpr inline u32 ConvertToSvcMinorVersion(u32 sdk) { + return sdk; +} +constexpr inline u32 ConvertToSdkMinorVersion(u32 svc) { + return svc; +} + +union KernelVersion { + u32 value; + BitField<0, 4, u32> minor_version; + BitField<4, 13, u32> major_version; +}; + +constexpr inline u32 EncodeKernelVersion(u32 major, u32 minor) { + return decltype(KernelVersion::minor_version)::FormatValue(minor) | + decltype(KernelVersion::major_version)::FormatValue(major); +} + +constexpr inline u32 GetKernelMajorVersion(u32 encoded) { + return decltype(KernelVersion::major_version)::ExtractValue(encoded); +} + +constexpr inline u32 GetKernelMinorVersion(u32 encoded) { + return decltype(KernelVersion::minor_version)::ExtractValue(encoded); +} + +// Nintendo doesn't support programs targeting SVC versions < 3.0. +constexpr inline u32 RequiredKernelMajorVersion = 3; +constexpr inline u32 RequiredKernelMinorVersion = 0; +constexpr inline u32 RequiredKernelVersion = + EncodeKernelVersion(RequiredKernelMajorVersion, RequiredKernelMinorVersion); + +// This is the highest SVC version supported, to be updated on new kernel releases. +// NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. +constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(15); +constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(3); +constexpr inline u32 SupportedKernelVersion = + EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion); + +} // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h deleted file mode 100644 index 1ea8c7fbc..000000000 --- a/src/core/hle/kernel/svc_wrap.h +++ /dev/null @@ -1,733 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/arm/arm_interface.h" -#include "core/core.h" -#include "core/hle/kernel/svc_types.h" -#include "core/hle/result.h" -#include "core/memory.h" - -namespace Kernel { - -static inline u64 Param(const Core::System& system, int n) { - return system.CurrentArmInterface().GetReg(n); -} - -static inline u32 Param32(const Core::System& system, int n) { - return static_cast<u32>(system.CurrentArmInterface().GetReg(n)); -} - -/** - * HLE a function return from the current ARM userland process - * @param system System context - * @param result Result to return - */ -static inline void FuncReturn(Core::System& system, u64 result) { - system.CurrentArmInterface().SetReg(0, result); -} - -static inline void FuncReturn32(Core::System& system, u32 result) { - system.CurrentArmInterface().SetReg(0, (u64)result); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Function wrappers that return type Result - -template <Result func(Core::System&, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0)).raw); -} - -template <Result func(Core::System&, u64, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), Param(system, 1)).raw); -} - -template <Result func(Core::System&, u32)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw); -} - -template <Result func(Core::System&, u32, u32)> -void SvcWrap64(Core::System& system) { - FuncReturn( - system, - func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw); -} - -// Used by SetThreadActivity -template <Result func(Core::System&, Handle, Svc::ThreadActivity)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), - static_cast<Svc::ThreadActivity>(Param(system, 1))) - .raw); -} - -template <Result func(Core::System&, u32, u64, u64, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), - Param(system, 2), Param(system, 3)) - .raw); -} - -// Used by MapProcessMemory and UnmapProcessMemory -template <Result func(Core::System&, u64, u32, u64, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)), - Param(system, 2), Param(system, 3)) - .raw); -} - -// Used by ControlCodeMemory -template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), - static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3), - static_cast<Svc::MemoryPermission>(Param(system, 4))) - .raw); -} - -template <Result func(Core::System&, u32*)> -void SvcWrap64(Core::System& system) { - u32 param = 0; - const u32 retval = func(system, ¶m).raw; - system.CurrentArmInterface().SetReg(1, param); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u32*, u32)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1))).raw; - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u32*, u32*)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - u32 param_2 = 0; - const u32 retval = func(system, ¶m_1, ¶m_2).raw; - - auto& arm_interface = system.CurrentArmInterface(); - arm_interface.SetReg(1, param_1); - arm_interface.SetReg(2, param_2); - - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u32*, u64)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1)).raw; - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u32*, u64, u32)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - const u32 retval = - func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2))).raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u64*, u32)> -void SvcWrap64(Core::System& system) { - u64 param_1 = 0; - const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1))).raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u64, u32)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1))).raw); -} - -template <Result func(Core::System&, u64*, u64)> -void SvcWrap64(Core::System& system) { - u64 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1)).raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u64*, u32, u32)> -void SvcWrap64(Core::System& system) { - u64 param_1 = 0; - const u32 retval = func(system, ¶m_1, static_cast<u32>(Param(system, 1)), - static_cast<u32>(Param(system, 2))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by GetResourceLimitLimitValue. -template <Result func(Core::System&, u64*, Handle, LimitableResource)> -void SvcWrap64(Core::System& system) { - u64 param_1 = 0; - const u32 retval = func(system, ¶m_1, static_cast<Handle>(Param(system, 1)), - static_cast<LimitableResource>(Param(system, 2))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u32, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw); -} - -// Used by SetResourceLimitLimitValue -template <Result func(Core::System&, Handle, LimitableResource, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), - static_cast<LimitableResource>(Param(system, 1)), Param(system, 2)) - .raw); -} - -// Used by SetThreadCoreMask -template <Result func(Core::System&, Handle, s32, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), - static_cast<s32>(Param(system, 1)), Param(system, 2)) - .raw); -} - -// Used by GetThreadCoreMask -template <Result func(Core::System&, Handle, s32*, u64*)> -void SvcWrap64(Core::System& system) { - s32 param_1 = 0; - u64 param_2 = 0; - const Result retval = func(system, static_cast<u32>(Param(system, 2)), ¶m_1, ¶m_2); - - system.CurrentArmInterface().SetReg(1, param_1); - system.CurrentArmInterface().SetReg(2, param_2); - FuncReturn(system, retval.raw); -} - -template <Result func(Core::System&, u64, u64, u32, u32)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), Param(system, 1), - static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3))) - .raw); -} - -template <Result func(Core::System&, u64, u64, u32, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), Param(system, 1), - static_cast<u32>(Param(system, 2)), Param(system, 3)) - .raw); -} - -template <Result func(Core::System&, u32, u64, u32)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), - static_cast<u32>(Param(system, 2))) - .raw); -} - -template <Result func(Core::System&, u64, u64, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw); -} - -template <Result func(Core::System&, u64, u64, u32)> -void SvcWrap64(Core::System& system) { - FuncReturn( - system, - func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); -} - -// Used by SetMemoryPermission -template <Result func(Core::System&, u64, u64, Svc::MemoryPermission)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), Param(system, 1), - static_cast<Svc::MemoryPermission>(Param(system, 2))) - .raw); -} - -// Used by MapSharedMemory -template <Result func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), Param(system, 1), - Param(system, 2), static_cast<Svc::MemoryPermission>(Param(system, 3))) - .raw); -} - -template <Result func(Core::System&, u32, u64, u64)> -void SvcWrap64(Core::System& system) { - FuncReturn( - system, - func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw); -} - -// Used by WaitSynchronization -template <Result func(Core::System&, s32*, u64, s32, s64)> -void SvcWrap64(Core::System& system) { - s32 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<s32>(Param(system, 2)), - static_cast<s64>(Param(system, 3))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u64, u64, u32, s64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, Param(system, 0), Param(system, 1), - static_cast<u32>(Param(system, 2)), static_cast<s64>(Param(system, 3))) - .raw); -} - -// Used by GetInfo -template <Result func(Core::System&, u64*, u64, Handle, u64)> -void SvcWrap64(Core::System& system) { - u64 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1), - static_cast<Handle>(Param(system, 2)), Param(system, 3)) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, u32*, u64, u64, u64, u32, s32)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3), - static_cast<u32>(Param(system, 4)), static_cast<s32>(Param(system, 5))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by CreateTransferMemory -template <Result func(Core::System&, Handle*, u64, u64, Svc::MemoryPermission)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), - static_cast<Svc::MemoryPermission>(Param(system, 3))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by CreateCodeMemory -template <Result func(Core::System&, Handle*, VAddr, size_t)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -template <Result func(Core::System&, Handle*, u64, u32, u32)> -void SvcWrap64(Core::System& system) { - u32 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param(system, 1), static_cast<u32>(Param(system, 2)), - static_cast<u32>(Param(system, 3))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by CreateSession -template <Result func(Core::System&, Handle*, Handle*, u32, u64)> -void SvcWrap64(Core::System& system) { - Handle param_1 = 0; - Handle param_2 = 0; - const u32 retval = func(system, ¶m_1, ¶m_2, static_cast<u32>(Param(system, 2)), - static_cast<u32>(Param(system, 3))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - system.CurrentArmInterface().SetReg(2, param_2); - FuncReturn(system, retval); -} - -// Used by ReplyAndReceive -template <Result func(Core::System&, s32*, Handle*, s32, Handle, s64)> -void SvcWrap64(Core::System& system) { - s32 param_1 = 0; - s32 num_handles = static_cast<s32>(Param(system, 2)); - - std::vector<Handle> handles(num_handles); - system.Memory().ReadBlock(Param(system, 1), handles.data(), num_handles * sizeof(Handle)); - - const u32 retval = func(system, ¶m_1, handles.data(), num_handles, - static_cast<s32>(Param(system, 3)), static_cast<s64>(Param(system, 4))) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by WaitForAddress -template <Result func(Core::System&, u64, Svc::ArbitrationType, s32, s64)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, - func(system, Param(system, 0), static_cast<Svc::ArbitrationType>(Param(system, 1)), - static_cast<s32>(Param(system, 2)), static_cast<s64>(Param(system, 3))) - .raw); -} - -// Used by SignalToAddress -template <Result func(Core::System&, u64, Svc::SignalType, s32, s32)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, - func(system, Param(system, 0), static_cast<Svc::SignalType>(Param(system, 1)), - static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3))) - .raw); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Function wrappers that return type u32 - -template <u32 func(Core::System&)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Function wrappers that return type u64 - -template <u64 func(Core::System&)> -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -/// Function wrappers that return type void - -template <void func(Core::System&)> -void SvcWrap64(Core::System& system) { - func(system); -} - -template <void func(Core::System&, u32)> -void SvcWrap64(Core::System& system) { - func(system, static_cast<u32>(Param(system, 0))); -} - -template <void func(Core::System&, u32, u64, u64, u64)> -void SvcWrap64(Core::System& system) { - func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2), - Param(system, 3)); -} - -template <void func(Core::System&, s64)> -void SvcWrap64(Core::System& system) { - func(system, static_cast<s64>(Param(system, 0))); -} - -template <void func(Core::System&, u64, s32)> -void SvcWrap64(Core::System& system) { - func(system, Param(system, 0), static_cast<s32>(Param(system, 1))); -} - -template <void func(Core::System&, u64, u64)> -void SvcWrap64(Core::System& system) { - func(system, Param(system, 0), Param(system, 1)); -} - -template <void func(Core::System&, u64, u64, u64)> -void SvcWrap64(Core::System& system) { - func(system, Param(system, 0), Param(system, 1), Param(system, 2)); -} - -template <void func(Core::System&, u32, u64, u64)> -void SvcWrap64(Core::System& system) { - func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)); -} - -// Used by QueryMemory32, ArbitrateLock32 -template <Result func(Core::System&, u32, u32, u32)> -void SvcWrap32(Core::System& system) { - FuncReturn32(system, - func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw); -} - -// Used by Break32 -template <void func(Core::System&, u32, u32, u32)> -void SvcWrap32(Core::System& system) { - func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)); -} - -// Used by ExitProcess32, ExitThread32 -template <void func(Core::System&)> -void SvcWrap32(Core::System& system) { - func(system); -} - -// Used by GetCurrentProcessorNumber32 -template <u32 func(Core::System&)> -void SvcWrap32(Core::System& system) { - FuncReturn32(system, func(system)); -} - -// Used by SleepThread32 -template <void func(Core::System&, u32, u32)> -void SvcWrap32(Core::System& system) { - func(system, Param32(system, 0), Param32(system, 1)); -} - -// Used by CreateThread32 -template <Result func(Core::System&, Handle*, u32, u32, u32, u32, s32)> -void SvcWrap32(Core::System& system) { - Handle param_1 = 0; - - const u32 retval = func(system, ¶m_1, Param32(system, 0), Param32(system, 1), - Param32(system, 2), Param32(system, 3), Param32(system, 4)) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by GetInfo32 -template <Result func(Core::System&, u32*, u32*, u32, u32, u32, u32)> -void SvcWrap32(Core::System& system) { - u32 param_1 = 0; - u32 param_2 = 0; - - const u32 retval = func(system, ¶m_1, ¶m_2, Param32(system, 0), Param32(system, 1), - Param32(system, 2), Param32(system, 3)) - .raw; - - system.CurrentArmInterface().SetReg(1, param_1); - system.CurrentArmInterface().SetReg(2, param_2); - FuncReturn(system, retval); -} - -// Used by GetThreadPriority32, ConnectToNamedPort32 -template <Result func(Core::System&, u32*, u32)> -void SvcWrap32(Core::System& system) { - u32 param_1 = 0; - const u32 retval = func(system, ¶m_1, Param32(system, 1)).raw; - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by GetThreadId32 -template <Result func(Core::System&, u32*, u32*, u32)> -void SvcWrap32(Core::System& system) { - u32 param_1 = 0; - u32 param_2 = 0; - - const u32 retval = func(system, ¶m_1, ¶m_2, Param32(system, 1)).raw; - system.CurrentArmInterface().SetReg(1, param_1); - system.CurrentArmInterface().SetReg(2, param_2); - FuncReturn(system, retval); -} - -// Used by GetSystemTick32 -template <void func(Core::System&, u32*, u32*)> -void SvcWrap32(Core::System& system) { - u32 param_1 = 0; - u32 param_2 = 0; - - func(system, ¶m_1, ¶m_2); - system.CurrentArmInterface().SetReg(0, param_1); - system.CurrentArmInterface().SetReg(1, param_2); -} - -// Used by CreateEvent32 -template <Result func(Core::System&, Handle*, Handle*)> -void SvcWrap32(Core::System& system) { - Handle param_1 = 0; - Handle param_2 = 0; - - const u32 retval = func(system, ¶m_1, ¶m_2).raw; - system.CurrentArmInterface().SetReg(1, param_1); - system.CurrentArmInterface().SetReg(2, param_2); - FuncReturn(system, retval); -} - -// Used by GetThreadId32 -template <Result func(Core::System&, Handle, u32*, u32*, u32*)> -void SvcWrap32(Core::System& system) { - u32 param_1 = 0; - u32 param_2 = 0; - u32 param_3 = 0; - - const u32 retval = func(system, Param32(system, 2), ¶m_1, ¶m_2, ¶m_3).raw; - system.CurrentArmInterface().SetReg(1, param_1); - system.CurrentArmInterface().SetReg(2, param_2); - system.CurrentArmInterface().SetReg(3, param_3); - FuncReturn(system, retval); -} - -// Used by GetThreadCoreMask32 -template <Result func(Core::System&, Handle, s32*, u32*, u32*)> -void SvcWrap32(Core::System& system) { - s32 param_1 = 0; - u32 param_2 = 0; - u32 param_3 = 0; - - const u32 retval = func(system, Param32(system, 2), ¶m_1, ¶m_2, ¶m_3).raw; - system.CurrentArmInterface().SetReg(1, param_1); - system.CurrentArmInterface().SetReg(2, param_2); - system.CurrentArmInterface().SetReg(3, param_3); - FuncReturn(system, retval); -} - -// Used by SignalProcessWideKey32 -template <void func(Core::System&, u32, s32)> -void SvcWrap32(Core::System& system) { - func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1))); -} - -// Used by SetThreadActivity32 -template <Result func(Core::System&, Handle, Svc::ThreadActivity)> -void SvcWrap32(Core::System& system) { - const u32 retval = func(system, static_cast<Handle>(Param(system, 0)), - static_cast<Svc::ThreadActivity>(Param(system, 1))) - .raw; - FuncReturn(system, retval); -} - -// Used by SetThreadPriority32 -template <Result func(Core::System&, Handle, u32)> -void SvcWrap32(Core::System& system) { - const u32 retval = - func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw; - FuncReturn(system, retval); -} - -// Used by SetMemoryAttribute32 -template <Result func(Core::System&, Handle, u32, u32, u32)> -void SvcWrap32(Core::System& system) { - const u32 retval = - func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1)), - static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3))) - .raw; - FuncReturn(system, retval); -} - -// Used by MapSharedMemory32 -template <Result func(Core::System&, Handle, u32, u32, Svc::MemoryPermission)> -void SvcWrap32(Core::System& system) { - const u32 retval = func(system, static_cast<Handle>(Param(system, 0)), - static_cast<u32>(Param(system, 1)), static_cast<u32>(Param(system, 2)), - static_cast<Svc::MemoryPermission>(Param(system, 3))) - .raw; - FuncReturn(system, retval); -} - -// Used by SetThreadCoreMask32 -template <Result func(Core::System&, Handle, s32, u32, u32)> -void SvcWrap32(Core::System& system) { - const u32 retval = - func(system, static_cast<Handle>(Param(system, 0)), static_cast<s32>(Param(system, 1)), - static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3))) - .raw; - FuncReturn(system, retval); -} - -// Used by WaitProcessWideKeyAtomic32 -template <Result func(Core::System&, u32, u32, Handle, u32, u32)> -void SvcWrap32(Core::System& system) { - const u32 retval = - func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1)), - static_cast<Handle>(Param(system, 2)), static_cast<u32>(Param(system, 3)), - static_cast<u32>(Param(system, 4))) - .raw; - FuncReturn(system, retval); -} - -// Used by WaitForAddress32 -template <Result func(Core::System&, u32, Svc::ArbitrationType, s32, u32, u32)> -void SvcWrap32(Core::System& system) { - const u32 retval = func(system, static_cast<u32>(Param(system, 0)), - static_cast<Svc::ArbitrationType>(Param(system, 1)), - static_cast<s32>(Param(system, 2)), static_cast<u32>(Param(system, 3)), - static_cast<u32>(Param(system, 4))) - .raw; - FuncReturn(system, retval); -} - -// Used by SignalToAddress32 -template <Result func(Core::System&, u32, Svc::SignalType, s32, s32)> -void SvcWrap32(Core::System& system) { - const u32 retval = func(system, static_cast<u32>(Param(system, 0)), - static_cast<Svc::SignalType>(Param(system, 1)), - static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3))) - .raw; - FuncReturn(system, retval); -} - -// Used by SendSyncRequest32, ArbitrateUnlock32 -template <Result func(Core::System&, u32)> -void SvcWrap32(Core::System& system) { - FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw); -} - -// Used by CreateTransferMemory32 -template <Result func(Core::System&, Handle*, u32, u32, Svc::MemoryPermission)> -void SvcWrap32(Core::System& system) { - Handle handle = 0; - const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2), - static_cast<Svc::MemoryPermission>(Param32(system, 3))) - .raw; - system.CurrentArmInterface().SetReg(1, handle); - FuncReturn(system, retval); -} - -// Used by WaitSynchronization32 -template <Result func(Core::System&, u32, u32, s32, u32, s32*)> -void SvcWrap32(Core::System& system) { - s32 param_1 = 0; - const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2), - Param32(system, 3), ¶m_1) - .raw; - system.CurrentArmInterface().SetReg(1, param_1); - FuncReturn(system, retval); -} - -// Used by CreateCodeMemory32 -template <Result func(Core::System&, Handle*, u32, u32)> -void SvcWrap32(Core::System& system) { - Handle handle = 0; - - const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2)).raw; - - system.CurrentArmInterface().SetReg(1, handle); - FuncReturn(system, retval); -} - -// Used by ControlCodeMemory32 -template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)> -void SvcWrap32(Core::System& system) { - const u32 retval = - func(system, Param32(system, 0), Param32(system, 1), Param(system, 2), Param(system, 4), - static_cast<Svc::MemoryPermission>(Param32(system, 6))) - .raw; - - FuncReturn(system, retval); -} - -// Used by Invalidate/Store/FlushProcessDataCache32 -template <Result func(Core::System&, Handle, u64, u64)> -void SvcWrap32(Core::System& system) { - const u64 address = (Param(system, 3) << 32) | Param(system, 2); - const u64 size = (Param(system, 4) << 32) | Param(system, 1); - FuncReturn32(system, func(system, Param32(system, 0), address, size).raw); -} - -} // namespace Kernel diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 6d1084fd1..1495d64de 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -762,7 +762,7 @@ Result Module::Interface::InitializeApplicationInfoBase() { // processes emulated. As we don't actually have pid support we should assume we're just using // our own process const auto launch_property = - system.GetARPManager().GetLaunchProperty(system.GetCurrentProcessProgramID()); + system.GetARPManager().GetLaunchProperty(system.GetApplicationProcessProgramID()); if (launch_property.Failed()) { LOG_ERROR(Service_ACC, "Failed to get launch property"); @@ -806,7 +806,7 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx bool is_locked = false; if (res != Loader::ResultStatus::Success) { - const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(), + const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(), system.GetFileSystemController(), system.GetContentProvider()}; const auto nacp_unique = pm.GetControlMetadata().first; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 22999c942..beb2da06e 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -24,7 +24,6 @@ #include "core/hle/service/am/idle.h" #include "core/hle/service/am/omm.h" #include "core/hle/service/am/spsm.h" -#include "core/hle/service/am/tcap.h" #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_interface.h" #include "core/hle/service/bcat/backend/backend.h" @@ -79,7 +78,7 @@ IWindowController::IWindowController(Core::System& system_) IWindowController::~IWindowController() = default; void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { - const u64 process_id = system.CurrentProcess()->GetProcessID(); + const u64 process_id = system.ApplicationProcess()->GetProcessID(); LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); @@ -1124,7 +1123,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - const std::vector<u8> data{ctx.ReadBuffer()}; + const auto data{ctx.ReadBuffer()}; const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)}; LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); @@ -1252,7 +1251,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex } auto transfer_mem = - system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); + system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); if (transfer_mem.IsNull()) { LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); @@ -1286,7 +1285,7 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) } auto transfer_mem = - system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); + system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); if (transfer_mem.IsNull()) { LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); @@ -1465,11 +1464,12 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) { return system.GetFileSystemController().GetBCATDirectory(tid); }); - const auto build_id_full = system.GetCurrentProcessBuildID(); + const auto build_id_full = system.GetApplicationProcessBuildID(); u64 build_id{}; std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); - auto data = backend->GetLaunchParameter({system.GetCurrentProcessProgramID(), build_id}); + auto data = + backend->GetLaunchParameter({system.GetApplicationProcessProgramID(), build_id}); if (data.has_value()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); @@ -1521,7 +1521,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); FileSys::SaveDataAttribute attribute{}; - attribute.title_id = system.GetCurrentProcessProgramID(); + attribute.title_id = system.GetApplicationProcessProgramID(); attribute.user_id = user_id; attribute.type = FileSys::SaveDataType::SaveData; const auto res = system.GetFileSystemController().CreateSaveData( @@ -1551,7 +1551,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { std::array<u8, 0x10> version_string{}; const auto res = [this] { - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), system.GetContentProvider()}; @@ -1570,7 +1570,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { const auto& version = res.first->GetVersionString(); std::copy(version.begin(), version.end(), version_string.begin()); } else { - constexpr char default_version[]{"1.0.0"}; + static constexpr char default_version[]{"1.0.0"}; std::memcpy(version_string.data(), default_version, sizeof(default_version)); } @@ -1588,7 +1588,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { u32 supported_languages = 0; const auto res = [this] { - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), system.GetContentProvider()}; @@ -1696,7 +1696,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); system.GetFileSystemController().WriteSaveDataSize( - type, system.GetCurrentProcessProgramID(), user_id, {new_normal_size, new_journal_size}); + type, system.GetApplicationProcessProgramID(), user_id, + {new_normal_size, new_journal_size}); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); @@ -1720,7 +1721,7 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { user_id[0]); const auto size = system.GetFileSystemController().ReadSaveDataSize( - type, system.GetCurrentProcessProgramID(), user_id); + type, system.GetApplicationProcessProgramID(), user_id); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); @@ -1838,7 +1839,6 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger std::make_shared<IdleSys>(system)->InstallAsService(service_manager); std::make_shared<OMM>(system)->InstallAsService(service_manager); std::make_shared<SPSM>(system)->InstallAsService(service_manager); - std::make_shared<TCAP>(system)->InstallAsService(service_manager); } IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index bae0d99a6..b013896b4 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -166,7 +166,7 @@ void Error::Execute() { } const auto callback = [this] { DisplayCompleted(); }; - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); const auto& reporter{system.GetReporter()}; switch (mode) { diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index e50acdaf6..1eefa85e3 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -186,7 +186,7 @@ void PhotoViewer::Execute() { const auto callback = [this] { ViewFinished(); }; switch (mode) { case PhotoViewerAppletMode::CurrentApp: - frontend.ShowPhotosForApplication(system.GetCurrentProcessProgramID(), callback); + frontend.ShowPhotosForApplication(system.GetApplicationProcessProgramID(), callback); break; case PhotoViewerAppletMode::AllApps: frontend.ShowAllPhotos(callback); diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 14aa6f69e..f061bae80 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -393,7 +393,7 @@ void WebBrowser::InitializeOffline() { switch (document_kind) { case DocumentKind::OfflineHtmlPage: default: - title_id = system.GetCurrentProcessProgramID(); + title_id = system.GetApplicationProcessProgramID(); nca_type = FileSys::ContentRecordType::HtmlDocument; additional_paths = "html-document"; break; diff --git a/src/core/hle/service/am/tcap.cpp b/src/core/hle/service/am/tcap.cpp deleted file mode 100644 index 818420e22..000000000 --- a/src/core/hle/service/am/tcap.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/am/tcap.h" - -namespace Service::AM { - -TCAP::TCAP(Core::System& system_) : ServiceFramework{system_, "tcap"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetContinuousHighSkinTemperatureEvent"}, - {1, nullptr, "SetOperationMode"}, - {2, nullptr, "LoadAndApplySettings"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -TCAP::~TCAP() = default; - -} // namespace Service::AM diff --git a/src/core/hle/service/am/tcap.h b/src/core/hle/service/am/tcap.h deleted file mode 100644 index 6b2148c29..000000000 --- a/src/core/hle/service/am/tcap.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::AM { - -class TCAP final : public ServiceFramework<TCAP> { -public: - explicit TCAP(Core::System& system_); - ~TCAP() override; -}; - -} // namespace Service::AM diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 368ccd52f..7264f23f9 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -155,7 +155,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - const auto current = system.GetCurrentProcessProgramID(); + const auto current = system.GetApplicationProcessProgramID(); const auto& disabled = Settings::values.disabled_addons[current]; if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) { @@ -182,7 +182,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, process_id); - const auto current = system.GetCurrentProcessProgramID(); + const auto current = system.GetApplicationProcessProgramID(); std::vector<u32> out; const auto& disabled = Settings::values.disabled_addons[current]; @@ -228,7 +228,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), system.GetContentProvider()}; diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index 8a338d9b1..44b2927a6 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -14,8 +14,6 @@ void InstallInterfaces(Core::System& system) { auto module_ = std::make_shared<Module>(); std::make_shared<APM>(system, module_, system.GetAPMController(), "apm") ->InstallAsService(system.ServiceManager()); - std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:p") - ->InstallAsService(system.ServiceManager()); std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:am") ->InstallAsService(system.ServiceManager()); std::make_shared<APM_Sys>(system, system.GetAPMController()) diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp index d6de84066..227fdd0cf 100644 --- a/src/core/hle/service/apm/apm_controller.cpp +++ b/src/core/hle/service/apm/apm_controller.cpp @@ -56,7 +56,7 @@ void Controller::SetPerformanceConfiguration(PerformanceMode mode, } void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { - constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{ + static constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{ PerformanceConfiguration::Config7, PerformanceConfiguration::Config13, PerformanceConfiguration::Config15, diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp deleted file mode 100644 index 5541af300..000000000 --- a/src/core/hle/service/audio/auddbg.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/audio/auddbg.h" - -namespace Service::Audio { - -AudDbg::AudDbg(Core::System& system_, const char* name) : ServiceFramework{system_, name} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RequestSuspendForDebug"}, - {1, nullptr, "RequestResumeForDebug"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -AudDbg::~AudDbg() = default; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h deleted file mode 100644 index 8f26be5dc..000000000 --- a/src/core/hle/service/audio/auddbg.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Audio { - -class AudDbg final : public ServiceFramework<AudDbg> { -public: - explicit AudDbg(Core::System& system_, const char* name); - ~AudDbg() override; -}; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp deleted file mode 100644 index 98f4a6048..000000000 --- a/src/core/hle/service/audio/audin_a.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/audio/audin_a.h" - -namespace Service::Audio { - -AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RequestSuspend"}, - {1, nullptr, "RequestResume"}, - {2, nullptr, "GetProcessMasterVolume"}, - {3, nullptr, "SetProcessMasterVolume"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -AudInA::~AudInA() = default; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h deleted file mode 100644 index 19a927de5..000000000 --- a/src/core/hle/service/audio/audin_a.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Audio { - -class AudInA final : public ServiceFramework<AudInA> { -public: - explicit AudInA(Core::System& system_); - ~AudInA() override; -}; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 97da71dfa..ed36e3448 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp @@ -2,17 +2,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/audio/audctl.h" -#include "core/hle/service/audio/auddbg.h" -#include "core/hle/service/audio/audin_a.h" #include "core/hle/service/audio/audin_u.h" #include "core/hle/service/audio/audio.h" -#include "core/hle/service/audio/audout_a.h" #include "core/hle/service/audio/audout_u.h" #include "core/hle/service/audio/audrec_a.h" #include "core/hle/service/audio/audrec_u.h" -#include "core/hle/service/audio/audren_a.h" #include "core/hle/service/audio/audren_u.h" -#include "core/hle/service/audio/codecctl.h" #include "core/hle/service/audio/hwopus.h" #include "core/hle/service/service.h" @@ -20,21 +15,12 @@ namespace Service::Audio { void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { std::make_shared<AudCtl>(system)->InstallAsService(service_manager); - std::make_shared<AudOutA>(system)->InstallAsService(service_manager); std::make_shared<AudOutU>(system)->InstallAsService(service_manager); - std::make_shared<AudInA>(system)->InstallAsService(service_manager); std::make_shared<AudInU>(system)->InstallAsService(service_manager); std::make_shared<AudRecA>(system)->InstallAsService(service_manager); std::make_shared<AudRecU>(system)->InstallAsService(service_manager); - std::make_shared<AudRenA>(system)->InstallAsService(service_manager); std::make_shared<AudRenU>(system)->InstallAsService(service_manager); - std::make_shared<CodecCtl>(system)->InstallAsService(service_manager); std::make_shared<HwOpus>(system)->InstallAsService(service_manager); - - std::make_shared<AudDbg>(system, "audin:d")->InstallAsService(service_manager); - std::make_shared<AudDbg>(system, "audout:d")->InstallAsService(service_manager); - std::make_shared<AudDbg>(system, "audrec:d")->InstallAsService(service_manager); - std::make_shared<AudDbg>(system, "audren:d")->InstallAsService(service_manager); } } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp deleted file mode 100644 index 5ecb99236..000000000 --- a/src/core/hle/service/audio/audout_a.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/audio/audout_a.h" - -namespace Service::Audio { - -AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RequestSuspend"}, - {1, nullptr, "RequestResume"}, - {2, nullptr, "GetProcessMasterVolume"}, - {3, nullptr, "SetProcessMasterVolume"}, - {4, nullptr, "GetProcessRecordVolume"}, - {5, nullptr, "SetProcessRecordVolume"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -AudOutA::~AudOutA() = default; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h deleted file mode 100644 index f641cffeb..000000000 --- a/src/core/hle/service/audio/audout_a.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Audio { - -class AudOutA final : public ServiceFramework<AudOutA> { -public: - explicit AudOutA(Core::System& system_); - ~AudOutA() override; -}; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp deleted file mode 100644 index e775ac3bf..000000000 --- a/src/core/hle/service/audio/audren_a.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/audio/audren_a.h" - -namespace Service::Audio { - -AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RequestSuspend"}, - {1, nullptr, "RequestResume"}, - {2, nullptr, "GetProcessMasterVolume"}, - {3, nullptr, "SetProcessMasterVolume"}, - {4, nullptr, "RegisterAppletResourceUserId"}, - {5, nullptr, "UnregisterAppletResourceUserId"}, - {6, nullptr, "GetProcessRecordVolume"}, - {7, nullptr, "SetProcessRecordVolume"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -AudRenA::~AudRenA() = default; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h deleted file mode 100644 index 9e08b4245..000000000 --- a/src/core/hle/service/audio/audren_a.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Audio { - -class AudRenA final : public ServiceFramework<AudRenA> { -public: - explicit AudRenA(Core::System& system_); - ~AudRenA() override; -}; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 3a1c231b6..7d730421d 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -112,7 +112,7 @@ private: void RequestUpdate(Kernel::HLERequestContext& ctx) { LOG_TRACE(Service_Audio, "called"); - std::vector<u8> input{ctx.ReadBuffer(0)}; + const auto input{ctx.ReadBuffer(0)}; // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for // checking size 0. Performance size is 0 for most games. @@ -455,7 +455,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { return; } - const auto& handle_table{system.CurrentProcess()->GetHandleTable()}; + const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; auto transfer_memory{ process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)}; diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp deleted file mode 100644 index 81b956d7e..000000000 --- a/src/core/hle/service/audio/codecctl.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/audio/codecctl.h" - -namespace Service::Audio { - -CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} { - static const FunctionInfo functions[] = { - {0, nullptr, "Initialize"}, - {1, nullptr, "Finalize"}, - {2, nullptr, "Sleep"}, - {3, nullptr, "Wake"}, - {4, nullptr, "SetVolume"}, - {5, nullptr, "GetVolumeMax"}, - {6, nullptr, "GetVolumeMin"}, - {7, nullptr, "SetActiveTarget"}, - {8, nullptr, "GetActiveTarget"}, - {9, nullptr, "BindHeadphoneMicJackInterrupt"}, - {10, nullptr, "IsHeadphoneMicJackInserted"}, - {11, nullptr, "ClearHeadphoneMicJackInterrupt"}, - {12, nullptr, "IsRequested"}, - }; - RegisterHandlers(functions); -} - -CodecCtl::~CodecCtl() = default; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h deleted file mode 100644 index 34da98212..000000000 --- a/src/core/hle/service/audio/codecctl.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Audio { - -class CodecCtl final : public ServiceFramework<CodecCtl> { -public: - explicit CodecCtl(Core::System& system_); - ~CodecCtl() override; -}; - -} // namespace Service::Audio diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 825fb8bcc..e01f87356 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -93,7 +93,7 @@ private: ctx.WriteBuffer(samples); } - bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input, + bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input, std::vector<opus_int16>& output, u64* out_performance_time) const { const auto start_time = std::chrono::steady_clock::now(); const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp index cbe690a5d..6e6fed227 100644 --- a/src/core/hle/service/bcat/bcat_module.cpp +++ b/src/core/hle/service/bcat/bcat_module.cpp @@ -176,8 +176,8 @@ private: void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_BCAT, "called"); - backend.Synchronize({system.GetCurrentProcessProgramID(), - GetCurrentBuildID(system.GetCurrentProcessBuildID())}, + backend.Synchronize({system.GetApplicationProcessProgramID(), + GetCurrentBuildID(system.GetApplicationProcessBuildID())}, GetProgressBackend(SyncType::Normal)); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -193,8 +193,8 @@ private: LOG_DEBUG(Service_BCAT, "called, name={}", name); - backend.SynchronizeDirectory({system.GetCurrentProcessProgramID(), - GetCurrentBuildID(system.GetCurrentProcessBuildID())}, + backend.SynchronizeDirectory({system.GetApplicationProcessProgramID(), + GetCurrentBuildID(system.GetApplicationProcessBuildID())}, name, GetProgressBackend(SyncType::Directory)); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -554,7 +554,7 @@ private: void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_BCAT, "called"); - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id)); diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index d183e5829..fb8686859 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -122,7 +122,7 @@ private: void ImportTicket(Kernel::HLERequestContext& ctx) { const auto ticket = ctx.ReadBuffer(); - const auto cert = ctx.ReadBuffer(1); + [[maybe_unused]] const auto cert = ctx.ReadBuffer(1); if (ticket.size() < sizeof(Core::Crypto::Ticket)) { LOG_ERROR(Service_ETicket, "The input buffer is not large enough!"); diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 27675615b..2e5919330 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -63,7 +63,7 @@ enum class FatalType : u32 { }; static void GenerateErrorReport(Core::System& system, Result error_code, const FatalInfo& info) { - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); std::string crash_report = fmt::format( "Yuzu {}-{} crash report\n" "Title ID: {:016x}\n" diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 11c604a0f..177447bc1 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -317,7 +317,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() return ResultUnknown; } - return romfs_factory->OpenCurrentProcess(system.GetCurrentProcessProgramID()); + return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID()); } ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS( @@ -502,7 +502,7 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy const auto res = system.GetAppLoader().ReadControlData(nacp); if (res != Loader::ResultStatus::Success) { - const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(), + const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(), system.GetFileSystemController(), system.GetContentProvider()}; const auto metadata = pm.GetControlMetadata(); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index fbb16a7da..e76346ca9 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -190,7 +190,7 @@ private: return; } - const std::vector<u8> data = ctx.ReadBuffer(); + const auto data = ctx.ReadBuffer(); ASSERT_MSG( static_cast<s64>(data.size()) <= length, @@ -401,11 +401,8 @@ public: } void RenameFile(Kernel::HLERequestContext& ctx) { - std::vector<u8> buffer = ctx.ReadBuffer(0); - const std::string src_name = Common::StringFromBuffer(buffer); - - buffer = ctx.ReadBuffer(1); - const std::string dst_name = Common::StringFromBuffer(buffer); + const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); + const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); @@ -1039,8 +1036,9 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "called, program_index={}", program_index); - auto patched_romfs = fsc.OpenPatchedRomFSWithProgramIndex( - system.GetCurrentProcessProgramID(), program_index, FileSys::ContentRecordType::Program); + auto patched_romfs = + fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index, + FileSys::ContentRecordType::Program); if (patched_romfs.Failed()) { // TODO: Find the right error code to use here @@ -1086,7 +1084,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { } void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) { - const auto raw = ctx.ReadBuffer(); + const auto raw = ctx.ReadBufferCopy(); auto log = Common::StringFromFixedZeroTerminatedBuffer( reinterpret_cast<const char*>(raw.data()), raw.size()); diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index 49b6d45fe..ce21b69e3 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp @@ -228,7 +228,8 @@ private: return; } - control = ctx.ReadBuffer(); + // TODO: Can this be a span? + control = ctx.ReadBufferCopy(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 2f871de31..ba6f04d8d 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -272,6 +272,8 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { } break; case Core::HID::NpadStyleIndex::JoyconLeft: + shared_memory->fullkey_color.attribute = ColorAttribute::Ok; + shared_memory->fullkey_color.fullkey = body_colors.left; shared_memory->joycon_color.attribute = ColorAttribute::Ok; shared_memory->joycon_color.left = body_colors.left; shared_memory->battery_level_dual = battery_level.left.battery_level; @@ -285,6 +287,8 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); break; case Core::HID::NpadStyleIndex::JoyconRight: + shared_memory->fullkey_color.attribute = ColorAttribute::Ok; + shared_memory->fullkey_color.fullkey = body_colors.right; shared_memory->joycon_color.attribute = ColorAttribute::Ok; shared_memory->joycon_color.right = body_colors.right; shared_memory->battery_level_right = battery_level.right.battery_level; @@ -332,6 +336,20 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { controller.is_connected = true; controller.device->Connect(); + controller.device->SetLedPattern(); + if (controller_type == Core::HID::NpadStyleIndex::JoyconDual) { + if (controller.is_dual_left_connected) { + controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::LeftIndex, + Common::Input::PollingMode::Active); + } + if (controller.is_dual_right_connected) { + controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active); + } + } else { + controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices, + Common::Input::PollingMode::Active); + } SignalStyleSetChangedEvent(npad_id); WriteEmptyEntry(controller.shared_memory); } @@ -410,6 +428,9 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { return; } + // This function is unique to yuzu for the turbo buttons to work properly + controller.device->TurboButtonUpdate(); + auto& pad_entry = controller.npad_pad_state; auto& trigger_entry = controller.npad_trigger_state; const auto button_state = controller.device->GetNpadButtons(); @@ -737,11 +758,20 @@ Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { return hid_core.GetSupportedStyleTag(); } -void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { +Result Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) { + constexpr std::size_t max_number_npad_ids = 0xa; + const auto length = data.size(); ASSERT(length > 0 && (length % sizeof(u32)) == 0); + const std::size_t elements = length / sizeof(u32); + + if (elements > max_number_npad_ids) { + return InvalidArraySize; + } + supported_npad_id_types.clear(); - supported_npad_id_types.resize(length / sizeof(u32)); - std::memcpy(supported_npad_id_types.data(), data, length); + supported_npad_id_types.resize(elements); + std::memcpy(supported_npad_id_types.data(), data.data(), length); + return ResultSuccess; } void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { @@ -1102,7 +1132,8 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { return ResultSuccess; } Result Controller_NPad::SetGyroscopeZeroDriftMode( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) { + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::GyroscopeZeroDriftMode drift_mode) { const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); if (is_valid.IsError()) { LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); @@ -1110,14 +1141,16 @@ Result Controller_NPad::SetGyroscopeZeroDriftMode( } auto& sixaxis = GetSixaxisState(sixaxis_handle); + auto& controller = GetControllerFromHandle(sixaxis_handle); sixaxis.gyroscope_zero_drift_mode = drift_mode; + controller.device->SetGyroscopeZeroDriftMode(drift_mode); return ResultSuccess; } Result Controller_NPad::GetGyroscopeZeroDriftMode( const Core::HID::SixAxisSensorHandle& sixaxis_handle, - GyroscopeZeroDriftMode& drift_mode) const { + Core::HID::GyroscopeZeroDriftMode& drift_mode) const { const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); if (is_valid.IsError()) { LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 1a589cca2..a5998c453 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -6,6 +6,7 @@ #include <array> #include <atomic> #include <mutex> +#include <span> #include "common/bit_field.h" #include "common/common_types.h" @@ -51,13 +52,6 @@ public: // When the controller is requesting a motion update for the shared memory void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override; - // This is nn::hid::GyroscopeZeroDriftMode - enum class GyroscopeZeroDriftMode : u32 { - Loose = 0, - Standard = 1, - Tight = 2, - }; - // This is nn::hid::NpadJoyHoldType enum class NpadJoyHoldType : u64 { Vertical = 0, @@ -95,7 +89,7 @@ public: void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); Core::HID::NpadStyleTag GetSupportedStyleSet() const; - void SetSupportedNpadIdTypes(u8* data, std::size_t length); + Result SetSupportedNpadIdTypes(std::span<const u8> data); void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); std::size_t GetSupportedNpadIdTypesSize() const; @@ -145,9 +139,9 @@ public: Result DisconnectNpad(Core::HID::NpadIdType npad_id); Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - GyroscopeZeroDriftMode drift_mode); + Core::HID::GyroscopeZeroDriftMode drift_mode); Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - GyroscopeZeroDriftMode& drift_mode) const; + Core::HID::GyroscopeZeroDriftMode& drift_mode) const; Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_at_rest) const; Result IsFirmwareUpdateAvailableForSixAxisSensor( @@ -488,7 +482,8 @@ private: Core::HID::SixAxisSensorFusionParameters fusion{}; Core::HID::SixAxisSensorCalibrationParameter calibration{}; Core::HID::SixAxisSensorIcInformation ic_information{}; - GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; + Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{ + Core::HID::GyroscopeZeroDriftMode::Standard}; }; struct NpadControllerData { diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index 76208e9a4..9585bdaf0 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h @@ -18,6 +18,7 @@ constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; constexpr Result NpadIsSameType{ErrorModule::HID, 602}; constexpr Result InvalidNpadId{ErrorModule::HID, 709}; constexpr Result NpadNotConnected{ErrorModule::HID, 710}; +constexpr Result InvalidArraySize{ErrorModule::HID, 715}; constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index bf28440c6..eb3c45a58 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -712,7 +712,7 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()}; - const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()}; + const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); @@ -739,7 +739,7 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; + auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); @@ -764,7 +764,7 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; + const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); @@ -1025,13 +1025,13 @@ void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); + const auto result = applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSupportedNpadIdTypes(ctx.ReadBuffer()); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) { @@ -1830,7 +1830,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); - auto t_mem_1 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( t_mem_1_handle); if (t_mem_1.IsNull()) { @@ -1840,7 +1840,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { return; } - auto t_mem_2 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( t_mem_2_handle); if (t_mem_2.IsNull()) { @@ -2104,7 +2104,7 @@ void Hid::WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx) { const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; const auto unknown{rp.Pop<u64>()}; - const auto buffer = ctx.ReadBuffer(); + [[maybe_unused]] const auto buffer = ctx.ReadBuffer(); LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}", connection_handle.npad_id, unknown); @@ -2127,8 +2127,8 @@ void Hid::WritePalmaWaveEntry(Kernel::HLERequestContext& ctx) { ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes"); - auto t_mem = - system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); + auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + t_mem_handle); if (t_mem.IsNull()) { LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); @@ -2734,25 +2734,11 @@ private: } }; -class HidTmp final : public ServiceFramework<HidTmp> { -public: - explicit HidTmp(Core::System& system_) : ServiceFramework{system_, "hid:tmp"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { std::make_shared<Hid>(system)->InstallAsService(service_manager); std::make_shared<HidBus>(system)->InstallAsService(service_manager); std::make_shared<HidDbg>(system)->InstallAsService(service_manager); std::make_shared<HidSys>(system)->InstallAsService(service_manager); - std::make_shared<HidTmp>(system)->InstallAsService(service_manager); std::make_shared<Service::IRS::IRS>(system)->InstallAsService(service_manager); std::make_shared<Service::IRS::IRS_SYS>(system)->InstallAsService(service_manager); diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index e5e50845f..bd94e8f3d 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp @@ -297,13 +297,13 @@ void HidBus::EnableExternalDevice(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - LOG_INFO(Service_HID, - "called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, " - "player_number={}, is_valid={}, inval={}, applet_resource_user_id{}", - parameters.enable, parameters.bus_handle.abstracted_pad_id, - parameters.bus_handle.bus_type, parameters.bus_handle.internal_index, - parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval, - parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, " + "player_number={}, is_valid={}, inval={}, applet_resource_user_id{}", + parameters.enable, parameters.bus_handle.abstracted_pad_id, + parameters.bus_handle.bus_type, parameters.bus_handle.internal_index, + parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval, + parameters.applet_resource_user_id); const auto device_index = GetDeviceIndexFromHandle(parameters.bus_handle); @@ -326,11 +326,11 @@ void HidBus::GetExternalDeviceId(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto bus_handle_{rp.PopRaw<BusHandle>()}; - LOG_INFO(Service_HID, - "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " - "is_valid={}", - bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index, - bus_handle_.player_number, bus_handle_.is_valid); + LOG_DEBUG(Service_HID, + "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " + "is_valid={}", + bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index, + bus_handle_.player_number, bus_handle_.is_valid); const auto device_index = GetDeviceIndexFromHandle(bus_handle_); @@ -449,8 +449,8 @@ void HidBus::EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) { ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); - auto t_mem = - system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); + auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + t_mem_handle); if (t_mem.IsNull()) { LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.h b/src/core/hle/service/hid/hidbus/hidbus_base.h index d3960f506..65e301137 100644 --- a/src/core/hle/service/hid/hidbus/hidbus_base.h +++ b/src/core/hle/service/hid/hidbus/hidbus_base.h @@ -4,6 +4,7 @@ #pragma once #include <array> +#include <span> #include "common/common_types.h" #include "core/hle/result.h" @@ -150,7 +151,7 @@ public: } // Assigns a command from data - virtual bool SetCommand(const std::vector<u8>& data) { + virtual bool SetCommand(std::span<const u8> data) { return {}; } diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp index 57f1a2a26..35847cbdd 100644 --- a/src/core/hle/service/hid/hidbus/ringcon.cpp +++ b/src/core/hle/service/hid/hidbus/ringcon.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/hid/emulated_devices.h" +#include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" @@ -12,16 +12,20 @@ namespace Service::HID { RingController::RingController(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) : HidbusBase(service_context_) { - input = hid_core_.GetEmulatedDevices(); + input = hid_core_.GetEmulatedController(Core::HID::NpadIdType::Player1); } RingController::~RingController() = default; void RingController::OnInit() { + input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Ring); return; } void RingController::OnRelease() { + input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active); return; }; @@ -112,7 +116,7 @@ std::vector<u8> RingController::GetReply() const { } } -bool RingController::SetCommand(const std::vector<u8>& data) { +bool RingController::SetCommand(std::span<const u8> data) { if (data.size() < 4) { LOG_ERROR(Service_HID, "Command size not supported {}", data.size()); command = RingConCommands::Error; diff --git a/src/core/hle/service/hid/hidbus/ringcon.h b/src/core/hle/service/hid/hidbus/ringcon.h index b37df50ac..c2fb386b1 100644 --- a/src/core/hle/service/hid/hidbus/ringcon.h +++ b/src/core/hle/service/hid/hidbus/ringcon.h @@ -4,12 +4,13 @@ #pragma once #include <array> +#include <span> #include "common/common_types.h" #include "core/hle/service/hid/hidbus/hidbus_base.h" namespace Core::HID { -class EmulatedDevices; +class EmulatedController; } // namespace Core::HID namespace Service::HID { @@ -31,7 +32,7 @@ public: u8 GetDeviceId() const override; // Assigns a command from data - bool SetCommand(const std::vector<u8>& data) override; + bool SetCommand(std::span<const u8> data) override; // Returns a reply from a command std::vector<u8> GetReply() const override; @@ -248,6 +249,6 @@ private: .zero = {.value = idle_value, .crc = 225}, }; - Core::HID::EmulatedDevices* input; + Core::HID::EmulatedController* input; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/starlink.cpp b/src/core/hle/service/hid/hidbus/starlink.cpp index dd439f60a..d0e760314 100644 --- a/src/core/hle/service/hid/hidbus/starlink.cpp +++ b/src/core/hle/service/hid/hidbus/starlink.cpp @@ -42,7 +42,7 @@ std::vector<u8> Starlink::GetReply() const { return {}; } -bool Starlink::SetCommand(const std::vector<u8>& data) { +bool Starlink::SetCommand(std::span<const u8> data) { LOG_ERROR(Service_HID, "Command not implemented"); return false; } diff --git a/src/core/hle/service/hid/hidbus/starlink.h b/src/core/hle/service/hid/hidbus/starlink.h index 0b1b7ba49..07c800e6e 100644 --- a/src/core/hle/service/hid/hidbus/starlink.h +++ b/src/core/hle/service/hid/hidbus/starlink.h @@ -29,7 +29,7 @@ public: u8 GetDeviceId() const override; // Assigns a command from data - bool SetCommand(const std::vector<u8>& data) override; + bool SetCommand(std::span<const u8> data) override; // Returns a reply from a command std::vector<u8> GetReply() const override; diff --git a/src/core/hle/service/hid/hidbus/stubbed.cpp b/src/core/hle/service/hid/hidbus/stubbed.cpp index e477443e3..07632c872 100644 --- a/src/core/hle/service/hid/hidbus/stubbed.cpp +++ b/src/core/hle/service/hid/hidbus/stubbed.cpp @@ -43,7 +43,7 @@ std::vector<u8> HidbusStubbed::GetReply() const { return {}; } -bool HidbusStubbed::SetCommand(const std::vector<u8>& data) { +bool HidbusStubbed::SetCommand(std::span<const u8> data) { LOG_ERROR(Service_HID, "Command not implemented"); return false; } diff --git a/src/core/hle/service/hid/hidbus/stubbed.h b/src/core/hle/service/hid/hidbus/stubbed.h index 91165ceff..38eaa0ecc 100644 --- a/src/core/hle/service/hid/hidbus/stubbed.h +++ b/src/core/hle/service/hid/hidbus/stubbed.h @@ -29,7 +29,7 @@ public: u8 GetDeviceId() const override; // Assigns a command from data - bool SetCommand(const std::vector<u8>& data) override; + bool SetCommand(std::span<const u8> data) override; // Returns a reply from a command std::vector<u8> GetReply() const override; diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 6a3453457..3bd418e92 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -108,6 +108,8 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { auto result = IsIrCameraHandleValid(parameters.camera_handle); if (result.IsSuccess()) { // TODO: Stop Image processor + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active); result = ResultSuccess; } @@ -139,6 +141,8 @@ void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { MakeProcessor<MomentProcessor>(parameters.camera_handle, device); auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -170,6 +174,8 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { auto& image_transfer_processor = GetProcessor<ClusteringProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -190,8 +196,8 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; const auto t_mem_handle{ctx.GetCopyHandle(0)}; - auto t_mem = - system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); + auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + t_mem_handle); if (t_mem.IsNull()) { LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); @@ -219,6 +225,8 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { GetProcessor<ImageTransferProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); image_transfer_processor.SetTransferMemoryPointer(transfer_memory); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -294,6 +302,8 @@ void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { auto& image_transfer_processor = GetProcessor<TeraPluginProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -343,6 +353,8 @@ void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { MakeProcessor<PointingProcessor>(camera_handle, device); auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle); image_transfer_processor.SetConfig(processor_config); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -433,8 +445,8 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; const auto t_mem_handle{ctx.GetCopyHandle(0)}; - auto t_mem = - system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); + auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( + t_mem_handle); u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress()); @@ -453,6 +465,8 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { GetProcessor<ImageTransferProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); image_transfer_processor.SetTransferMemoryPointer(transfer_memory); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -479,6 +493,8 @@ void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { MakeProcessor<IrLedProcessor>(camera_handle, device); auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle); image_transfer_processor.SetConfig(processor_config); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -504,6 +520,8 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { auto result = IsIrCameraHandleValid(parameters.camera_handle); if (result.IsSuccess()) { // TODO: Stop image processor async + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active); result = ResultSuccess; } diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 8f2920c51..47a1277ea 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp @@ -62,7 +62,7 @@ public: const auto parameters{rp.PopRaw<InputParameters>()}; // Optional input/output buffers - std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()}; + const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()}; std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); // Function call prototype: @@ -132,7 +132,7 @@ public: const auto command{rp.PopRaw<u64>()}; // Optional input/output buffers - std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()}; + const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()}; std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); // Function call prototype: @@ -353,9 +353,9 @@ public: return; } - // Fetch using the handle table for the current process here, + // Fetch using the handle table for the application process here, // since we are not multiprocess yet. - const auto& handle_table{system.CurrentProcess()->GetHandleTable()}; + const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; if (process.IsNull()) { diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index c49c61cff..e5099d61f 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -412,7 +412,7 @@ public: } void SetAdvertiseData(Kernel::HLERequestContext& ctx) { - std::vector<u8> read_buffer = ctx.ReadBuffer(); + const auto read_buffer = ctx.ReadBuffer(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(lan_discovery.SetAdvertiseData(read_buffer)); @@ -464,7 +464,7 @@ public: parameters.security_config.passphrase_size, parameters.security_config.security_mode, parameters.local_communication_version); - const std::vector<u8> read_buffer = ctx.ReadBuffer(); + const auto read_buffer = ctx.ReadBuffer(); if (read_buffer.size() != sizeof(NetworkInfo)) { LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 652441bc2..2d4d6fe3e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -246,7 +246,7 @@ public: return; } - if (system.GetCurrentProcessProgramID() != header.application_id) { + if (system.GetApplicationProcessProgramID() != header.application_id) { LOG_ERROR(Service_LDR, "Attempting to load NRR with title ID other than current process. (actual " "{:016X})!", @@ -542,15 +542,16 @@ public: } // Map memory for the NRO - const auto map_result{MapNro(system.CurrentProcess(), nro_address, nro_size, bss_address, - bss_size, nro_size + bss_size)}; + const auto map_result{MapNro(system.ApplicationProcess(), nro_address, nro_size, + bss_address, bss_size, nro_size + bss_size)}; if (map_result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(map_result.Code()); } // Load the NRO into the mapped memory - if (const auto result{LoadNro(system.CurrentProcess(), header, nro_address, *map_result)}; + if (const auto result{ + LoadNro(system.ApplicationProcess(), header, nro_address, *map_result)}; result.IsError()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(map_result.Code()); @@ -570,7 +571,7 @@ public: Result UnmapNro(const NROInfo& info) { // Each region must be unmapped separately to validate memory state - auto& page_table{system.CurrentProcess()->PageTable()}; + auto& page_table{system.ApplicationProcess()->PageTable()}; if (info.bss_size != 0) { CASCADE_CODE(page_table.UnmapCodeMemory( @@ -641,7 +642,7 @@ public: LOG_WARNING(Service_LDR, "(STUBBED) called"); initialized = true; - current_map_addr = system.CurrentProcess()->PageTable().GetAliasCodeRegionStart(); + current_map_addr = system.ApplicationProcess()->PageTable().GetAliasCodeRegionStart(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp index 78578f723..9a3234e8c 100644 --- a/src/core/hle/service/nfc/nfc_device.cpp +++ b/src/core/hle/service/nfc/nfc_device.cpp @@ -130,7 +130,9 @@ Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) { return WrongDeviceState; } - if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) { + if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::NFC) != + Common::Input::DriverResult::Success) { LOG_ERROR(Service_NFC, "Nfc not supported"); return NfcDisabled; } @@ -141,7 +143,8 @@ Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) { } Result NfcDevice::StopDetection() { - npad_device->SetPollingMode(Common::Input::PollingMode::Active); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active); if (device_state == NFP::DeviceState::Initialized) { return ResultSuccess; diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index c860fd1a1..7a6bbbba7 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -152,7 +152,9 @@ Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { return WrongDeviceState; } - if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) { + if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::NFC) != + Common::Input::DriverResult::Success) { LOG_ERROR(Service_NFP, "Nfc not supported"); return NfcDisabled; } @@ -163,7 +165,8 @@ Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { } Result NfpDevice::StopDetection() { - npad_device->SetPollingMode(Common::Input::PollingMode::Active); + npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, + Common::Input::PollingMode::Active); if (device_state == DeviceState::Initialized) { return ResultSuccess; @@ -615,7 +618,7 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat sizeof(ApplicationArea) - data.size()); // TODO: Investigate why the title id needs to be moddified - tag_data.title_id = system.GetCurrentProcessProgramID(); + tag_data.title_id = system.GetApplicationProcessProgramID(); tag_data.title_id = tag_data.title_id | 0x30000000ULL; tag_data.settings.settings.appdata_initialized.Assign(1); tag_data.application_area_id = access_id; diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index 4f2cefae5..7728ff596 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -124,7 +124,7 @@ private: //!< value }; - constexpr static std::size_t SyncpointCount{192}; + static constexpr std::size_t SyncpointCount{192}; std::array<SyncpointInfo, SyncpointCount> syncpoints{}; std::mutex reservation_lock; diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 204b0e757..c562e04d2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -3,7 +3,9 @@ #pragma once +#include <span> #include <vector> + #include "common/common_types.h" #include "core/hle/service/nvdrv/nvdata.h" @@ -31,7 +33,7 @@ public: * @param output A buffer where the output data will be written to. * @returns The result code of the ioctl. */ - virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) = 0; /** @@ -42,8 +44,8 @@ public: * @param output A buffer where the output data will be written to. * @returns The result code of the ioctl. */ - virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; + virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) = 0; /** * Handles an ioctl3 request. @@ -53,7 +55,7 @@ public: * @param inline_output A buffer where the inlined output data will be written to. * @returns The result code of the ioctl. */ - virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) = 0; /** diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 4122fc98d..5a5b2e305 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -17,19 +17,19 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core) : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {} nvdisp_disp0::~nvdisp_disp0() = default; -NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 04217ab12..81bd7960a 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -25,12 +25,12 @@ public: explicit nvdisp_disp0(Core::System& system_, NvCore::Container& core); ~nvdisp_disp0() override; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index b635e6ed1..681bd0867 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -27,7 +27,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Con nvhost_as_gpu::~nvhost_as_gpu() = default; -NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 'A': @@ -60,13 +60,13 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8> return NvResult::NotImplemented; } -NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { switch (command.group) { case 'A': @@ -87,7 +87,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8> void nvhost_as_gpu::OnOpen(DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::vector<u8>& output) { IoctlAllocAsEx params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -141,7 +141,7 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>& return NvResult::Success; } -NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::vector<u8>& output) { IoctlAllocSpace params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -220,7 +220,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { mapping_map.erase(offset); } -NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::vector<u8>& output) { IoctlFreeSpace params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -266,7 +266,7 @@ NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& return NvResult::Success; } -NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::vector<u8>& output) { const auto num_entries = input.size() / sizeof(IoctlRemapEntry); LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); @@ -320,7 +320,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& out return NvResult::Success; } -NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::vector<u8>& output) { IoctlMapBufferEx params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -424,7 +424,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8 return NvResult::Success; } -NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) { IoctlUnmapBuffer params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -463,7 +463,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8 return NvResult::Success; } -NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::vector<u8>& output) { IoctlBindChannel params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); @@ -492,7 +492,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) { }; } -NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output) { IoctlGetVaRegions params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -511,7 +511,7 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u return NvResult::Success; } -NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, +NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { IoctlGetVaRegions params{}; std::memcpy(¶ms, input.data(), input.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 86fe71c75..1aba8d579 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -47,12 +47,12 @@ public: explicit nvhost_as_gpu(Core::System& system_, Module& module, NvCore::Container& core); ~nvhost_as_gpu() override; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -138,17 +138,17 @@ private: static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, "IoctlGetVaRegions is incorrect size"); - NvResult AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output); - NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); - NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); - NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); - NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); - NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); - NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output); + NvResult AllocAsEx(std::span<const u8> input, std::vector<u8>& output); + NvResult AllocateSpace(std::span<const u8> input, std::vector<u8>& output); + NvResult Remap(std::span<const u8> input, std::vector<u8>& output); + NvResult MapBufferEx(std::span<const u8> input, std::vector<u8>& output); + NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output); + NvResult FreeSpace(std::span<const u8> input, std::vector<u8>& output); + NvResult BindChannel(std::span<const u8> input, std::vector<u8>& output); void GetVARegionsImpl(IoctlGetVaRegions& params); - NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); - NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, + NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output); + NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output); void FreeMappingLocked(u64 offset); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index eee11fab8..e12025560 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -34,7 +34,7 @@ nvhost_ctrl::~nvhost_ctrl() { } } -NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 0x0: @@ -63,13 +63,13 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& return NvResult::NotImplemented; } -NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_outpu) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; @@ -79,7 +79,7 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {} void nvhost_ctrl::OnClose(DeviceFD fd) {} -NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output) { IocGetConfigParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), @@ -87,7 +87,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector return NvResult::ConfigVarNotFound; // Returns error on production mode } -NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, +NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output, bool is_allocation) { IocCtrlEventWaitParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -150,9 +150,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector const auto check_failing = [&]() { if (events[slot].fails > 2) { { - auto lk = system.StallProcesses(); + auto lk = system.StallApplication(); host1x_syncpoint_manager.WaitHost(fence_id, target_value); - system.UnstallProcesses(); + system.UnstallApplication(); } params.value.raw = target_value; return true; @@ -231,7 +231,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) { return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output) { IocCtrlEventRegisterParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); const u32 event_id = params.user_event_id; @@ -252,8 +252,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, - std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output) { IocCtrlEventUnregisterParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); const u32 event_id = params.user_event_id & 0x00FF; @@ -263,7 +262,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, return FreeEvent(event_id); } -NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input, +NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::vector<u8>& output) { IocCtrlEventUnregisterBatchParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -282,7 +281,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input, return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output) { IocCtrlEventClearParams params{}; std::memcpy(¶ms, input.data(), sizeof(params)); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 0b56d7070..dd2e7888a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -25,12 +25,12 @@ public: NvCore::Container& core); ~nvhost_ctrl() override; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -186,13 +186,13 @@ private: static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, "IocCtrlEventKill is incorrect size"); - NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, + NvResult NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output); + NvResult IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output, bool is_allocation); - NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocCtrlEventUnregisterBatch(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); + NvResult IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output); + NvResult IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output); + NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::vector<u8>& output); + NvResult IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output); NvResult FreeEvent(u32 slot); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index b97813fbc..be3c083db 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -21,7 +21,7 @@ nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { events_interface.FreeEvent(unknown_event); } -NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 'G': @@ -53,13 +53,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u return NvResult::NotImplemented; } -NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { switch (command.group) { case 'G': @@ -82,8 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, - std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlCharacteristics params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -128,7 +127,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, +NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlCharacteristics params{}; @@ -176,7 +175,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std:: return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output) { IoctlGpuGetTpcMasksArgs params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); @@ -187,7 +186,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector< return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, +NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { IoctlGpuGetTpcMasksArgs params{}; std::memcpy(¶ms, input.data(), input.size()); @@ -200,7 +199,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector< return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlActiveSlotMask params{}; @@ -213,7 +212,7 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::v return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlZcullGetCtxSize params{}; @@ -225,7 +224,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vec return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlNvgpuGpuZcullGetInfoArgs params{}; @@ -248,7 +247,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::vector<u8>& output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IoctlZbcSetTable params{}; @@ -264,7 +263,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector< return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IoctlZbcQueryTable params{}; @@ -274,7 +273,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vecto return NvResult::Success; } -NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::vector<u8>& output) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IoctlFlushL2 params{}; @@ -284,7 +283,7 @@ NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlGetGpuTime params{}; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 1e8f254e2..b9333d9d3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -21,12 +21,12 @@ public: explicit nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_); ~nvhost_ctrl_gpu() override; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -151,21 +151,21 @@ private: }; static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); - NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); - NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, + NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output); + NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output); - NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); - NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, + NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output); + NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output); - NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); - NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); - NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); - NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); - NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); - NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output); - NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); + NvResult GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output); + NvResult ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output); + NvResult ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output); + NvResult ZBCSetTable(std::span<const u8> input, std::vector<u8>& output); + NvResult ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output); + NvResult FlushL2(std::span<const u8> input, std::vector<u8>& output); + NvResult GetGpuTime(std::span<const u8> input, std::vector<u8>& output); EventInterface& events_interface; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index e123564c6..d2308fffc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -46,7 +46,7 @@ nvhost_gpu::~nvhost_gpu() { syncpoint_manager.FreeSyncpoint(channel_syncpoint); } -NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 0x0: @@ -98,8 +98,8 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i return NvResult::NotImplemented; }; -NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { switch (command.group) { case 'H': switch (command.cmd) { @@ -112,7 +112,7 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& i return NvResult::NotImplemented; } -NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; @@ -121,7 +121,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& i void nvhost_gpu::OnOpen(DeviceFD fd) {} void nvhost_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) { IoctlSetNvmapFD params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); @@ -130,7 +130,7 @@ NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& o return NvResult::Success; } -NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlClientData params{}; @@ -139,7 +139,7 @@ NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8> return NvResult::Success; } -NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called"); IoctlClientData params{}; @@ -149,7 +149,7 @@ NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8> return NvResult::Success; } -NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::vector<u8>& output) { std::memcpy(&zcull_params, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, zcull_params.mode); @@ -158,7 +158,7 @@ NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& ou return NvResult::Success; } -NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output) { IoctlSetErrorNotifier params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, @@ -168,14 +168,14 @@ NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector< return NvResult::Success; } -NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::vector<u8>& output) { std::memcpy(&channel_priority, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); return NvResult::Success; } -NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output) { IoctlAllocGpfifoEx2 params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_WARNING(Service_NVDRV, @@ -197,7 +197,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8 return NvResult::Success; } -NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output) { IoctlAllocObjCtx params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, @@ -293,7 +293,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8> return NvResult::Success; } -NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, +NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output, bool kickoff) { if (input.size() < sizeof(IoctlSubmitGpfifo)) { UNIMPLEMENTED(); @@ -314,8 +314,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector< return SubmitGPFIFOImpl(params, output, std::move(entries)); } -NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, - const std::vector<u8>& input_inline, +NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, std::vector<u8>& output) { if (input.size() < sizeof(IoctlSubmitGpfifo)) { UNIMPLEMENTED(); @@ -328,7 +327,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, return SubmitGPFIFOImpl(params, output, std::move(entries)); } -NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) { IoctlGetWaitbase params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); @@ -338,7 +337,7 @@ NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& return NvResult::Success; } -NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output) { IoctlChannelSetTimeout params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); @@ -346,7 +345,7 @@ NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector return NvResult::Success; } -NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output) { IoctlSetTimeslice params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 1e4ecd55b..3ca58202d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -40,12 +40,12 @@ public: NvCore::Container& core); ~nvhost_gpu() override; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -186,23 +186,23 @@ private: u32_le channel_priority{}; u32_le channel_timeslice{}; - NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); - NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output); - NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output); - NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); - NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); - NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); - NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); - NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); + NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output); + NvResult SetClientData(std::span<const u8> input, std::vector<u8>& output); + NvResult GetClientData(std::span<const u8> input, std::vector<u8>& output); + NvResult ZCullBind(std::span<const u8> input, std::vector<u8>& output); + NvResult SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output); + NvResult SetChannelPriority(std::span<const u8> input, std::vector<u8>& output); + NvResult AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output); + NvResult AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output); NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, Tegra::CommandList&& entries); - NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, + NvResult SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output, bool kickoff = false); - NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline, + NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, std::vector<u8>& output); - NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); - NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); - NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); + NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output); + NvResult ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output); + NvResult ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output); EventInterface& events_interface; NvCore::Container& core; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 1703f9cc3..0c7aee1b8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -15,7 +15,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_) : nvhost_nvdec_common{system_, core_, NvCore::ChannelType::NvDec} {} nvhost_nvdec::~nvhost_nvdec() = default; -NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 0x0: @@ -55,13 +55,13 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& return NvResult::NotImplemented; } -NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index c1b4e53e8..0d615bbcb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -13,12 +13,12 @@ public: explicit nvhost_nvdec(Core::System& system_, NvCore::Container& core); ~nvhost_nvdec() override; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 99eede702..7bcef105b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -23,7 +23,7 @@ namespace { // Copies count amount of type T from the input vector into the dst vector. // Returns the number of bytes written into dst. template <typename T> -std::size_t SliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count, +std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::size_t count, std::size_t offset) { if (dst.empty()) { return 0; @@ -63,7 +63,7 @@ nvhost_nvdec_common::~nvhost_nvdec_common() { core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint); } -NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { +NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) { IoctlSetNvmapFD params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD)); LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); @@ -72,7 +72,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { return NvResult::Success; } -NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input, +NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::vector<u8>& output) { IoctlSubmit params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); @@ -121,7 +121,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input, return NvResult::Success; } -NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::vector<u8>& output) { IoctlGetSyncpoint params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); @@ -133,7 +133,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::ve return NvResult::Success; } -NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) { IoctlGetWaitbase params{}; LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); @@ -142,7 +142,7 @@ NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vec return NvResult::Success; } -NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::vector<u8>& output) { IoctlMapBuffer params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); @@ -159,7 +159,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto return NvResult::Success; } -NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) { IoctlMapBuffer params{}; std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); @@ -173,8 +173,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec return NvResult::Success; } -NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, - std::vector<u8>& output) { +NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output) { std::memcpy(&submit_timeout, input.data(), input.size()); LOG_WARNING(Service_NVDRV, "(STUBBED) called"); return NvResult::Success; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index fe76100c8..5af26a26f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -107,13 +107,13 @@ protected: static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); /// Ioctl command implementations - NvResult SetNVMAPfd(const std::vector<u8>& input); - NvResult Submit(DeviceFD fd, const std::vector<u8>& input, std::vector<u8>& output); - NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); - NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); - NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); - NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); - NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); + NvResult SetNVMAPfd(std::span<const u8> input); + NvResult Submit(DeviceFD fd, std::span<const u8> input, std::vector<u8>& output); + NvResult GetSyncpoint(std::span<const u8> input, std::vector<u8>& output); + NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output); + NvResult MapBuffer(std::span<const u8> input, std::vector<u8>& output); + NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output); + NvResult SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output); Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index bdbc2f9e1..39f30e7c8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -12,7 +12,7 @@ namespace Service::Nvidia::Devices { nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {} nvhost_nvjpg::~nvhost_nvjpg() = default; -NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 'H': @@ -31,13 +31,13 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& return NvResult::NotImplemented; } -NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; @@ -46,7 +46,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& void nvhost_nvjpg::OnOpen(DeviceFD fd) {} void nvhost_nvjpg::OnClose(DeviceFD fd) {} -NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) { IoctlSetNvmapFD params{}; std::memcpy(¶ms, input.data(), input.size()); LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 440e7d371..41b57e872 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -15,12 +15,12 @@ public: explicit nvhost_nvjpg(Core::System& system_); ~nvhost_nvjpg() override; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -33,7 +33,7 @@ private: s32_le nvmap_fd{}; - NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); + NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output); }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 73f97136e..b0ea402a7 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -15,7 +15,7 @@ nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_) nvhost_vic::~nvhost_vic() = default; -NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 0x0: @@ -55,13 +55,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i return NvResult::NotImplemented; } -NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index f164caafb..b5e350a83 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -12,12 +12,12 @@ public: explicit nvhost_vic(Core::System& system_, NvCore::Container& core); ~nvhost_vic(); - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index fa29db758..277afe0b4 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -25,7 +25,7 @@ nvmap::nvmap(Core::System& system_, NvCore::Container& container_) nvmap::~nvmap() = default; -NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { switch (command.group) { case 0x1: @@ -54,13 +54,13 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, return NvResult::NotImplemented; } -NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; } -NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); return NvResult::NotImplemented; @@ -69,7 +69,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, void nvmap::OnOpen(DeviceFD fd) {} void nvmap::OnClose(DeviceFD fd) {} -NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocCreate(std::span<const u8> input, std::vector<u8>& output) { IocCreateParams params; std::memcpy(¶ms, input.data(), sizeof(params)); LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); @@ -89,7 +89,7 @@ NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) return NvResult::Success; } -NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocAlloc(std::span<const u8> input, std::vector<u8>& output) { IocAllocParams params; std::memcpy(¶ms, input.data(), sizeof(params)); LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); @@ -127,7 +127,7 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) return result; } bool is_out_io{}; - ASSERT(system.CurrentProcess() + ASSERT(system.ApplicationProcess() ->PageTable() .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, handle_description->size, @@ -137,7 +137,7 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) return result; } -NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocGetId(std::span<const u8> input, std::vector<u8>& output) { IocGetIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -161,7 +161,7 @@ NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) return NvResult::Success; } -NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocFromId(std::span<const u8> input, std::vector<u8>& output) { IocFromIdParams params; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -192,7 +192,7 @@ NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) return NvResult::Success; } -NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocParam(std::span<const u8> input, std::vector<u8>& output) { enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; IocParamParams params; @@ -241,7 +241,7 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) return NvResult::Success; } -NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocFree(std::span<const u8> input, std::vector<u8>& output) { IocFreeParams params; std::memcpy(¶ms, input.data(), sizeof(params)); @@ -254,7 +254,7 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { if (auto freeInfo{file.FreeHandle(params.handle, false)}) { if (freeInfo->can_unlock) { - ASSERT(system.CurrentProcess() + ASSERT(system.ApplicationProcess() ->PageTable() .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) .IsSuccess()); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index e9bfd0358..82bd3b118 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -26,12 +26,12 @@ public: nvmap(const nvmap&) = delete; nvmap& operator=(const nvmap&) = delete; - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) override; - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output) override; + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output) override; void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; @@ -106,12 +106,12 @@ private: }; static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); - NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output); - NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output); + NvResult IocCreate(std::span<const u8> input, std::vector<u8>& output); + NvResult IocAlloc(std::span<const u8> input, std::vector<u8>& output); + NvResult IocGetId(std::span<const u8> input, std::vector<u8>& output); + NvResult IocFromId(std::span<const u8> input, std::vector<u8>& output); + NvResult IocParam(std::span<const u8> input, std::vector<u8>& output); + NvResult IocFree(std::span<const u8> input, std::vector<u8>& output); NvCore::Container& container; NvCore::NvMap& file; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 6fc8565c0..52d27e755 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -124,7 +124,7 @@ DeviceFD Module::Open(const std::string& device_name) { return fd; } -NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); @@ -141,8 +141,8 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input return itr->second->Ioctl1(fd, command, input, output); } -NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output) { +NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); return NvResult::InvalidState; @@ -158,7 +158,7 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input return itr->second->Ioctl2(fd, command, input, inline_input, output); } -NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, std::vector<u8>& inline_output) { if (fd < 0) { LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index f3c81bd88..b09b6e585 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -7,6 +7,7 @@ #include <functional> #include <list> #include <memory> +#include <span> #include <string> #include <unordered_map> #include <vector> @@ -79,14 +80,13 @@ public: DeviceFD Open(const std::string& device_name); /// Sends an ioctl command to the specified file descriptor. - NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output); + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output); - NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - const std::vector<u8>& inline_input, std::vector<u8>& output); + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::vector<u8>& output); - NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, - std::vector<u8>& output, std::vector<u8>& inline_output); + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, + std::vector<u8>& inline_output); /// Closes a device file descriptor and returns operation success. NvResult Close(DeviceFD fd); diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index e601b5da1..bcbe05b0d 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -815,8 +815,8 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) { Status status{Status::NoError}; - Parcel parcel_in{ctx.ReadBuffer()}; - Parcel parcel_out{}; + InputParcel parcel_in{ctx.ReadBuffer()}; + OutputParcel parcel_out{}; switch (code) { case TransactionId::Connect: { diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp index 4043c91f1..769e8c0a3 100644 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp @@ -9,7 +9,7 @@ namespace Service::android { -QueueBufferInput::QueueBufferInput(Parcel& parcel) { +QueueBufferInput::QueueBufferInput(InputParcel& parcel) { parcel.ReadFlattened(*this); } diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h index 6ea327bbe..2969f0fd5 100644 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h @@ -14,11 +14,11 @@ namespace Service::android { -class Parcel; +class InputParcel; #pragma pack(push, 1) struct QueueBufferInput final { - explicit QueueBufferInput(Parcel& parcel); + explicit QueueBufferInput(InputParcel& parcel); void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_, NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_, diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index d1cbadde4..f4416f5b2 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -312,8 +312,6 @@ void NVFlinger::Compose() { } s64 NVFlinger::GetNextTicks() const { - static constexpr s64 max_hertz = 120LL; - const auto& settings = Settings::values; auto speed_scale = 1.f; if (settings.use_multi_core.GetValue()) { @@ -327,9 +325,11 @@ s64 NVFlinger::GetNextTicks() const { } } - const auto next_ticks = ((1000000000 * (1LL << swap_interval)) / max_hertz); + // As an extension, treat nonpositive swap interval as framerate multiplier. + const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval) + : 60.f / static_cast<f32>(swap_interval); - return static_cast<s64>(speed_scale * static_cast<float>(next_ticks)); + return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); } } // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 9b22397db..3828cf272 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -133,7 +133,7 @@ private: /// layers. u32 next_buffer_queue_id = 1; - u32 swap_interval = 1; + s32 swap_interval = 1; /// Event that handles screen composition. std::shared_ptr<Core::Timing::EventType> multi_composition_event; diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h index f3fa2587d..d1b6201e0 100644 --- a/src/core/hle/service/nvflinger/parcel.h +++ b/src/core/hle/service/nvflinger/parcel.h @@ -4,6 +4,7 @@ #pragma once #include <memory> +#include <span> #include <vector> #include "common/alignment.h" @@ -12,18 +13,17 @@ namespace Service::android { -class Parcel final { -public: - static constexpr std::size_t DefaultBufferSize = 0x40; - - Parcel() : buffer(DefaultBufferSize) {} - - template <typename T> - explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) { - Write(out_data); - } +struct ParcelHeader { + u32 data_size; + u32 data_offset; + u32 objects_size; + u32 objects_offset; +}; +static_assert(sizeof(ParcelHeader) == 16, "ParcelHeader has wrong size"); - explicit Parcel(std::vector<u8> in_data) : buffer(std::move(in_data)) { +class InputParcel final { +public: + explicit InputParcel(std::span<const u8> in_data) : read_buffer(std::move(in_data)) { DeserializeHeader(); [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); } @@ -31,9 +31,9 @@ public: template <typename T> void Read(T& val) { static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); - ASSERT(read_index + sizeof(T) <= buffer.size()); + ASSERT(read_index + sizeof(T) <= read_buffer.size()); - std::memcpy(&val, buffer.data() + read_index, sizeof(T)); + std::memcpy(&val, read_buffer.data() + read_index, sizeof(T)); read_index += sizeof(T); read_index = Common::AlignUp(read_index, 4); } @@ -62,10 +62,10 @@ public: template <typename T> T ReadUnaligned() { static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); - ASSERT(read_index + sizeof(T) <= buffer.size()); + ASSERT(read_index + sizeof(T) <= read_buffer.size()); T val; - std::memcpy(&val, buffer.data() + read_index, sizeof(T)); + std::memcpy(&val, read_buffer.data() + read_index, sizeof(T)); read_index += sizeof(T); return val; } @@ -101,6 +101,31 @@ public: return token; } + void DeserializeHeader() { + ASSERT(read_buffer.size() > sizeof(ParcelHeader)); + + ParcelHeader header{}; + std::memcpy(&header, read_buffer.data(), sizeof(ParcelHeader)); + + read_index = header.data_offset; + } + +private: + std::span<const u8> read_buffer; + std::size_t read_index = 0; +}; + +class OutputParcel final { +public: + static constexpr std::size_t DefaultBufferSize = 0x40; + + OutputParcel() : buffer(DefaultBufferSize) {} + + template <typename T> + explicit OutputParcel(const T& out_data) : buffer(DefaultBufferSize) { + Write(out_data); + } + template <typename T> void Write(const T& val) { static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); @@ -133,40 +158,20 @@ public: WriteObject(ptr.get()); } - void DeserializeHeader() { - ASSERT(buffer.size() > sizeof(Header)); - - Header header{}; - std::memcpy(&header, buffer.data(), sizeof(Header)); - - read_index = header.data_offset; - } - std::vector<u8> Serialize() const { - ASSERT(read_index == 0); - - Header header{}; - header.data_size = static_cast<u32>(write_index - sizeof(Header)); - header.data_offset = sizeof(Header); + ParcelHeader header{}; + header.data_size = static_cast<u32>(write_index - sizeof(ParcelHeader)); + header.data_offset = sizeof(ParcelHeader); header.objects_size = 4; - header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size); - std::memcpy(buffer.data(), &header, sizeof(Header)); + header.objects_offset = static_cast<u32>(sizeof(ParcelHeader) + header.data_size); + std::memcpy(buffer.data(), &header, sizeof(ParcelHeader)); return buffer; } private: - struct Header { - u32 data_size; - u32 data_offset; - u32 objects_size; - u32 objects_offset; - }; - static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size"); - mutable std::vector<u8> buffer; - std::size_t read_index = 0; - std::size_t write_index = sizeof(Header); + std::size_t write_index = sizeof(ParcelHeader); }; } // namespace Service::android diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp index 2a123b42d..083609b34 100644 --- a/src/core/hle/service/pctl/pctl_module.cpp +++ b/src/core/hle/service/pctl/pctl_module.cpp @@ -187,7 +187,7 @@ private: // TODO(ogniK): Recovery flag initialization for pctl:r - const auto tid = system.GetCurrentProcessProgramID(); + const auto tid = system.GetApplicationProcessProgramID(); if (tid != 0) { const FileSys::PatchManager pm{tid, system.GetFileSystemController(), system.GetContentProvider()}; diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index f7a497a14..98037a8d4 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp @@ -52,32 +52,6 @@ public: } }; -class PCV_ARB final : public ServiceFramework<PCV_ARB> { -public: - explicit PCV_ARB(Core::System& system_) : ServiceFramework{system_, "pcv:arb"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "ReleaseControl"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class PCV_IMM final : public ServiceFramework<PCV_IMM> { -public: - explicit PCV_IMM(Core::System& system_) : ServiceFramework{system_, "pcv:imm"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "SetClockRate"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - class IClkrstSession final : public ServiceFramework<IClkrstSession> { public: explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_) @@ -169,8 +143,6 @@ public: void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { std::make_shared<PCV>(system)->InstallAsService(sm); - std::make_shared<PCV_ARB>(system)->InstallAsService(sm); - std::make_shared<PCV_IMM>(system)->InstallAsService(sm); std::make_shared<CLKRST>(system, "clkrst")->InstallAsService(sm); std::make_shared<CLKRST>(system, "clkrst:i")->InstallAsService(sm); std::make_shared<CLKRST_A>(system)->InstallAsService(sm); diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 78f897d3e..90c5f8756 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -63,7 +63,7 @@ private: return ctx.ReadBuffer(1); } - return std::vector<u8>{}; + return std::span<const u8>{}; }(); LOG_DEBUG(Service_PREPO, @@ -71,7 +71,7 @@ private: Type, process_id, data1.size(), data2.size()); const auto& reporter{system.GetReporter()}; - reporter.SavePlayReport(Type, system.GetCurrentProcessProgramID(), {data1, data2}, + reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2}, process_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -90,7 +90,7 @@ private: return ctx.ReadBuffer(1); } - return std::vector<u8>{}; + return std::span<const u8>{}; }(); LOG_DEBUG(Service_PREPO, @@ -99,7 +99,7 @@ private: Type, user_id[1], user_id[0], process_id, data1.size(), data2.size()); const auto& reporter{system.GetReporter()}; - reporter.SavePlayReport(Type, system.GetCurrentProcessProgramID(), {data1, data2}, + reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2}, process_id, user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -142,7 +142,7 @@ private: return ctx.ReadBuffer(1); } - return std::vector<u8>{}; + return std::span<const u8>{}; }(); LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}", @@ -166,7 +166,7 @@ private: return ctx.ReadBuffer(1); } - return std::vector<u8>{}; + return std::span<const u8>{}; }(); LOG_DEBUG(Service_PREPO, diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 0de67f1e1..1ffc1c694 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -68,7 +68,6 @@ #include "core/hle/service/time/time.h" #include "core/hle/service/usb/usb.h" #include "core/hle/service/vi/vi.h" -#include "core/hle/service/wlan/wlan.h" #include "core/reporter.h" namespace Service { @@ -306,7 +305,6 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system Time::InstallInterfaces(system); USB::InstallInterfaces(*sm, system); VI::InstallInterfaces(*sm, system, *nv_flinger, *hos_binder_driver_server); - WLAN::InstallInterfaces(*sm, system); } Services::~Services() = default; diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 9e94a462f..bdb499268 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -208,7 +208,6 @@ void BSD::Bind(Kernel::HLERequestContext& ctx) { const s32 fd = rp.Pop<s32>(); LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize()); - BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer())); } @@ -312,7 +311,7 @@ void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { const u32 level = rp.Pop<u32>(); const OptName optname = static_cast<OptName>(rp.Pop<u32>()); - const std::vector<u8> buffer = ctx.ReadBuffer(); + const auto buffer = ctx.ReadBuffer(); const u8* optval = buffer.empty() ? nullptr : buffer.data(); size_t optlen = buffer.size(); @@ -489,7 +488,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco return {fd, Errno::SUCCESS}; } -std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, +std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout) { if (write_buffer.size() < nfds * sizeof(PollFD)) { return {-1, Errno::INVAL}; @@ -584,7 +583,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) { return {new_fd, Errno::SUCCESS}; } -Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) { +Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) { if (!IsFileDescriptorValid(fd)) { return Errno::BADF; } @@ -595,7 +594,7 @@ Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) { return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); } -Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) { +Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) { if (!IsFileDescriptorValid(fd)) { return Errno::BADF; } @@ -800,15 +799,15 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess return {ret, bsd_errno}; } -std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) { +std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) { if (!IsFileDescriptorValid(fd)) { return {-1, Errno::BADF}; } return Translate(file_descriptors[fd]->socket->Send(message, flags)); } -std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message, - const std::vector<u8>& addr) { +std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message, + std::span<const u8> addr) { if (!IsFileDescriptorValid(fd)) { return {-1, Errno::BADF}; } diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 81e855e0f..56bb3f8b1 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -4,6 +4,7 @@ #pragma once #include <memory> +#include <span> #include <vector> #include "common/common_types.h" @@ -44,7 +45,7 @@ private: s32 nfds; s32 timeout; - std::vector<u8> read_buffer; + std::span<const u8> read_buffer; std::vector<u8> write_buffer; s32 ret{}; Errno bsd_errno{}; @@ -65,7 +66,7 @@ private: void Response(Kernel::HLERequestContext& ctx); s32 fd; - std::vector<u8> addr; + std::span<const u8> addr; Errno bsd_errno{}; }; @@ -98,7 +99,7 @@ private: s32 fd; u32 flags; - std::vector<u8> message; + std::span<const u8> message; s32 ret{}; Errno bsd_errno{}; }; @@ -109,8 +110,8 @@ private: s32 fd; u32 flags; - std::vector<u8> message; - std::vector<u8> addr; + std::span<const u8> message; + std::span<const u8> addr; s32 ret{}; Errno bsd_errno{}; }; @@ -143,11 +144,11 @@ private: void ExecuteWork(Kernel::HLERequestContext& ctx, Work work); std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol); - std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, + std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout); std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer); - Errno BindImpl(s32 fd, const std::vector<u8>& addr); - Errno ConnectImpl(s32 fd, const std::vector<u8>& addr); + Errno BindImpl(s32 fd, std::span<const u8> addr); + Errno ConnectImpl(s32 fd, std::span<const u8> addr); Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer); Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer); Errno ListenImpl(s32 fd, s32 backlog); @@ -157,9 +158,9 @@ private: std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::vector<u8>& addr); - std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message); - std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message, - const std::vector<u8>& addr); + std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message); + std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message, + std::span<const u8> addr); Errno CloseImpl(s32 fd); s32 FindFreeFileDescriptorHandle() noexcept; diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp deleted file mode 100644 index c12ea999b..000000000 --- a/src/core/hle/service/sockets/ethc.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/sockets/ethc.h" - -namespace Service::Sockets { - -ETHC_C::ETHC_C(Core::System& system_) : ServiceFramework{system_, "ethc:c"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "Initialize"}, - {1, nullptr, "Cancel"}, - {2, nullptr, "GetResult"}, - {3, nullptr, "GetMediaList"}, - {4, nullptr, "SetMediaType"}, - {5, nullptr, "GetMediaType"}, - {6, nullptr, "Unknown6"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -ETHC_C::~ETHC_C() = default; - -ETHC_I::ETHC_I(Core::System& system_) : ServiceFramework{system_, "ethc:i"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetReadableHandle"}, - {1, nullptr, "Cancel"}, - {2, nullptr, "GetResult"}, - {3, nullptr, "GetInterfaceList"}, - {4, nullptr, "GetInterfaceCount"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -ETHC_I::~ETHC_I() = default; - -} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h deleted file mode 100644 index 7c5759a96..000000000 --- a/src/core/hle/service/sockets/ethc.h +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Sockets { - -class ETHC_C final : public ServiceFramework<ETHC_C> { -public: - explicit ETHC_C(Core::System& system_); - ~ETHC_C() override; -}; - -class ETHC_I final : public ServiceFramework<ETHC_I> { -public: - explicit ETHC_I(Core::System& system_); - ~ETHC_I() override; -}; - -} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 097c37d7a..e96eda7f3 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -243,4 +243,4 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx) { rb.Push(0); } -} // namespace Service::Sockets
\ No newline at end of file +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp index 8d3ba6f96..b191b5cf5 100644 --- a/src/core/hle/service/sockets/sockets.cpp +++ b/src/core/hle/service/sockets/sockets.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/sockets/bsd.h" -#include "core/hle/service/sockets/ethc.h" #include "core/hle/service/sockets/nsd.h" #include "core/hle/service/sockets/sfdnsres.h" #include "core/hle/service/sockets/sockets.h" @@ -14,9 +13,6 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager); std::make_shared<BSDCFG>(system)->InstallAsService(service_manager); - std::make_shared<ETHC_C>(system)->InstallAsService(service_manager); - std::make_shared<ETHC_I>(system)->InstallAsService(service_manager); - std::make_shared<NSD>(system, "nsd:a")->InstallAsService(service_manager); std::make_shared<NSD>(system, "nsd:u")->InstallAsService(service_manager); diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index 3735e0452..dcf47083f 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -101,7 +101,7 @@ private: void ImportServerPki(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto certificate_format = rp.PopEnum<CertificateFormat>(); - const auto pkcs_12_certificates = ctx.ReadBuffer(0); + [[maybe_unused]] const auto pkcs_12_certificates = ctx.ReadBuffer(0); constexpr u64 server_id = 0; @@ -113,13 +113,13 @@ private: } void ImportClientPki(Kernel::HLERequestContext& ctx) { - const auto pkcs_12_certificate = ctx.ReadBuffer(0); - const auto ascii_password = [&ctx] { + [[maybe_unused]] const auto pkcs_12_certificate = ctx.ReadBuffer(0); + [[maybe_unused]] const auto ascii_password = [&ctx] { if (ctx.CanReadBuffer(1)) { return ctx.ReadBuffer(1); } - return std::vector<u8>{}; + return std::span<const u8>{}; }(); constexpr u64 client_id = 0; diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index f9ada7c93..973f7837a 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -286,7 +286,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) { } static bool ParsePosixName(const char* name, TimeZoneRule& rule) { - constexpr char default_rule[]{",M4.1.0,M10.5.0"}; + static constexpr char default_rule[]{",M4.1.0,M10.5.0"}; const char* std_name{name}; int std_len{}; int offset{}; diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index bb283e74e..2fb631183 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -603,7 +603,7 @@ private: return; } - const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}}; + const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}}; const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); IPC::ResponseBuilder rb{ctx, 4}; @@ -649,7 +649,7 @@ private: return; } - const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}}; + const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}}; const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); IPC::ResponseBuilder rb{ctx, 6}; diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp deleted file mode 100644 index 226e3034c..000000000 --- a/src/core/hle/service/wlan/wlan.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <memory> - -#include "core/hle/service/service.h" -#include "core/hle/service/sm/sm.h" -#include "core/hle/service/wlan/wlan.h" - -namespace Service::WLAN { - -class WLANInfra final : public ServiceFramework<WLANInfra> { -public: - explicit WLANInfra(Core::System& system_) : ServiceFramework{system_, "wlan:inf"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "OpenMode"}, - {1, nullptr, "CloseMode"}, - {2, nullptr, "GetMacAddress"}, - {3, nullptr, "StartScan"}, - {4, nullptr, "StopScan"}, - {5, nullptr, "Connect"}, - {6, nullptr, "CancelConnect"}, - {7, nullptr, "Disconnect"}, - {8, nullptr, "GetConnectionEvent"}, - {9, nullptr, "GetConnectionStatus"}, - {10, nullptr, "GetState"}, - {11, nullptr, "GetScanResult"}, - {12, nullptr, "GetRssi"}, - {13, nullptr, "ChangeRxAntenna"}, - {14, nullptr, "GetFwVersion"}, - {15, nullptr, "RequestSleep"}, - {16, nullptr, "RequestWakeUp"}, - {17, nullptr, "RequestIfUpDown"}, - {18, nullptr, "Unknown18"}, - {19, nullptr, "Unknown19"}, - {20, nullptr, "Unknown20"}, - {21, nullptr, "Unknown21"}, - {22, nullptr, "Unknown22"}, - {23, nullptr, "Unknown23"}, - {24, nullptr, "Unknown24"}, - {25, nullptr, "Unknown25"}, - {26, nullptr, "Unknown26"}, - {27, nullptr, "Unknown27"}, - {28, nullptr, "Unknown28"}, - {29, nullptr, "Unknown29"}, - {30, nullptr, "Unknown30"}, - {31, nullptr, "Unknown31"}, - {32, nullptr, "Unknown32"}, - {33, nullptr, "Unknown33"}, - {34, nullptr, "Unknown34"}, - {35, nullptr, "Unknown35"}, - {36, nullptr, "Unknown36"}, - {37, nullptr, "Unknown37"}, - {38, nullptr, "Unknown38"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class WLANLocal final : public ServiceFramework<WLANLocal> { -public: - explicit WLANLocal(Core::System& system_) : ServiceFramework{system_, "wlan:lcl"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "Unknown0"}, - {1, nullptr, "Unknown1"}, - {2, nullptr, "Unknown2"}, - {3, nullptr, "Unknown3"}, - {4, nullptr, "Unknown4"}, - {5, nullptr, "Unknown5"}, - {6, nullptr, "GetMacAddress"}, - {7, nullptr, "CreateBss"}, - {8, nullptr, "DestroyBss"}, - {9, nullptr, "StartScan"}, - {10, nullptr, "StopScan"}, - {11, nullptr, "Connect"}, - {12, nullptr, "CancelConnect"}, - {13, nullptr, "Join"}, - {14, nullptr, "CancelJoin"}, - {15, nullptr, "Disconnect"}, - {16, nullptr, "SetBeaconLostCount"}, - {17, nullptr, "Unknown17"}, - {18, nullptr, "Unknown18"}, - {19, nullptr, "Unknown19"}, - {20, nullptr, "GetBssIndicationEvent"}, - {21, nullptr, "GetBssIndicationInfo"}, - {22, nullptr, "GetState"}, - {23, nullptr, "GetAllowedChannels"}, - {24, nullptr, "AddIe"}, - {25, nullptr, "DeleteIe"}, - {26, nullptr, "Unknown26"}, - {27, nullptr, "Unknown27"}, - {28, nullptr, "CreateRxEntry"}, - {29, nullptr, "DeleteRxEntry"}, - {30, nullptr, "Unknown30"}, - {31, nullptr, "Unknown31"}, - {32, nullptr, "AddMatchingDataToRxEntry"}, - {33, nullptr, "RemoveMatchingDataFromRxEntry"}, - {34, nullptr, "GetScanResult"}, - {35, nullptr, "Unknown35"}, - {36, nullptr, "SetActionFrameWithBeacon"}, - {37, nullptr, "CancelActionFrameWithBeacon"}, - {38, nullptr, "CreateRxEntryForActionFrame"}, - {39, nullptr, "DeleteRxEntryForActionFrame"}, - {40, nullptr, "Unknown40"}, - {41, nullptr, "Unknown41"}, - {42, nullptr, "CancelGetActionFrame"}, - {43, nullptr, "GetRssi"}, - {44, nullptr, "Unknown44"}, - {45, nullptr, "Unknown45"}, - {46, nullptr, "Unknown46"}, - {47, nullptr, "Unknown47"}, - {48, nullptr, "Unknown48"}, - {49, nullptr, "Unknown49"}, - {50, nullptr, "Unknown50"}, - {51, nullptr, "Unknown51"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> { -public: - explicit WLANLocalGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:lg"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "Unknown"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> { -public: - explicit WLANSocketGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:sg"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "Unknown"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class WLANSocketManager final : public ServiceFramework<WLANSocketManager> { -public: - explicit WLANSocketManager(Core::System& system_) : ServiceFramework{system_, "wlan:soc"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "Unknown0"}, - {1, nullptr, "Unknown1"}, - {2, nullptr, "Unknown2"}, - {3, nullptr, "Unknown3"}, - {4, nullptr, "Unknown4"}, - {5, nullptr, "Unknown5"}, - {6, nullptr, "GetMacAddress"}, - {7, nullptr, "SwitchTsfTimerFunction"}, - {8, nullptr, "Unknown8"}, - {9, nullptr, "Unknown9"}, - {10, nullptr, "Unknown10"}, - {11, nullptr, "Unknown11"}, - {12, nullptr, "Unknown12"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { - std::make_shared<WLANInfra>(system)->InstallAsService(sm); - std::make_shared<WLANLocal>(system)->InstallAsService(sm); - std::make_shared<WLANLocalGetFrame>(system)->InstallAsService(sm); - std::make_shared<WLANSocketGetFrame>(system)->InstallAsService(sm); - std::make_shared<WLANSocketManager>(system)->InstallAsService(sm); -} - -} // namespace Service::WLAN diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h deleted file mode 100644 index 535c3bf0d..000000000 --- a/src/core/hle/service/wlan/wlan.h +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -namespace Core { -class System; -} - -namespace Service::SM { -class ServiceManager; -} - -namespace Service::WLAN { - -void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); - -} // namespace Service::WLAN diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index 282ea1ff9..7494fb62d 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -550,7 +550,7 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock return {-1, GetAndLogLastError()}; } -std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { +std::pair<s32, Errno> Socket::Send(std::span<const u8> message, int flags) { ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); ASSERT(flags == 0); @@ -563,7 +563,7 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { return {-1, GetAndLogLastError()}; } -std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, +std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message, const SockAddrIn* addr) { ASSERT(flags == 0); diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 1e1c42cea..7a77171c2 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -182,7 +182,7 @@ std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& mes return {static_cast<u32>(read_bytes), Errno::SUCCESS}; } -std::pair<s32, Errno> ProxySocket::Send(const std::vector<u8>& message, int flags) { +std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) { LOG_WARNING(Network, "(STUBBED) called"); ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); ASSERT(flags == 0); @@ -200,7 +200,7 @@ void ProxySocket::SendPacket(ProxyPacket& packet) { } } -std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& message, +std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message, const SockAddrIn* addr) { ASSERT(flags == 0); diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h index f12b5f567..9421492bc 100644 --- a/src/core/internal_network/socket_proxy.h +++ b/src/core/internal_network/socket_proxy.h @@ -4,6 +4,7 @@ #pragma once #include <mutex> +#include <span> #include <vector> #include <queue> @@ -48,11 +49,11 @@ public: std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr, std::size_t max_length); - std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override; + std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override; void SendPacket(ProxyPacket& packet); - std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, + std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const SockAddrIn* addr) override; Errno SetLinger(bool enable, u32 linger) override; diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h index 2e328c645..4c7489258 100644 --- a/src/core/internal_network/sockets.h +++ b/src/core/internal_network/sockets.h @@ -5,6 +5,7 @@ #include <map> #include <memory> +#include <span> #include <utility> #if defined(_WIN32) @@ -66,9 +67,9 @@ public: virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) = 0; - virtual std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) = 0; + virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0; - virtual std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, + virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const SockAddrIn* addr) = 0; virtual Errno SetLinger(bool enable, u32 linger) = 0; @@ -138,9 +139,9 @@ public: std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override; - std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override; + std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override; - std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, + std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const SockAddrIn* addr) override; Errno SetLinger(bool enable, u32 linger) override; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 4c3b3c655..a5c384fb5 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -145,7 +145,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: // Apply cheats if they exist and the program has a valid title ID if (pm) { - system.SetCurrentProcessBuildID(nso_header.build_id); + system.SetApplicationProcessBuildID(nso_header.build_id); const auto cheats = pm->CreateCheatList(nso_header.build_id); if (!cheats.empty()) { system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a1e41faff..4397fcfb1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -247,11 +247,11 @@ struct Memory::Impl { } void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { - ReadBlockImpl<false>(*system.CurrentProcess(), src_addr, dest_buffer, size); + ReadBlockImpl<false>(*system.ApplicationProcess(), src_addr, dest_buffer, size); } void ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) { - ReadBlockImpl<true>(*system.CurrentProcess(), src_addr, dest_buffer, size); + ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size); } template <bool UNSAFE> @@ -279,11 +279,11 @@ struct Memory::Impl { } void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { - WriteBlockImpl<false>(*system.CurrentProcess(), dest_addr, src_buffer, size); + WriteBlockImpl<false>(*system.ApplicationProcess(), dest_addr, src_buffer, size); } void WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { - WriteBlockImpl<true>(*system.CurrentProcess(), dest_addr, src_buffer, size); + WriteBlockImpl<true>(*system.ApplicationProcess(), dest_addr, src_buffer, size); } void ZeroBlock(const Kernel::KProcess& process, const VAddr dest_addr, const std::size_t size) { @@ -383,6 +383,10 @@ struct Memory::Impl { return; } + if (Settings::IsFastmemEnabled()) { + system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug); + } + // Iterate over a contiguous CPU address space, marking/unmarking the region. // The region is at a granularity of CPU pages. @@ -436,7 +440,7 @@ struct Memory::Impl { } if (Settings::IsFastmemEnabled()) { - const bool is_read_enable = !Settings::IsGPULevelExtreme() || !cached; + const bool is_read_enable = Settings::IsGPULevelHigh() || !cached; system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached); } @@ -707,7 +711,7 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { } bool Memory::IsValidVirtualAddress(const VAddr vaddr) const { - const Kernel::KProcess& process = *system.CurrentProcess(); + const Kernel::KProcess& process = *system.ApplicationProcess(); const auto& page_table = process.PageTable().PageTableImpl(); const size_t page = vaddr >> YUZU_PAGEBITS; if (page >= page_table.pointers.size()) { diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index ffdbacc18..44ee39648 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -191,10 +191,10 @@ void CheatEngine::Initialize() { }); core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event); - metadata.process_id = system.CurrentProcess()->GetProcessID(); - metadata.title_id = system.GetCurrentProcessProgramID(); + metadata.process_id = system.ApplicationProcess()->GetProcessID(); + metadata.title_id = system.GetApplicationProcessProgramID(); - const auto& page_table = system.CurrentProcess()->PageTable(); + const auto& page_table = system.ApplicationProcess()->PageTable(); metadata.heap_extents = { .base = page_table.GetHeapRegionStart(), .size = page_table.GetHeapRegionSize(), diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 77821e047..708ae17aa 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -110,7 +110,7 @@ json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64 } json GetProcessorStateDataAuto(Core::System& system) { - const auto* process{system.CurrentProcess()}; + const auto* process{system.ApplicationProcess()}; auto& arm{system.CurrentArmInterface()}; Core::ARM_Interface::ThreadContext64 context{}; @@ -234,7 +234,7 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 } const auto timestamp = GetTimestamp(); - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); auto out = GetFullDataAuto(timestamp, title_id, system); auto break_out = json{ @@ -261,7 +261,7 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u } const auto timestamp = GetTimestamp(); - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); auto out = GetFullDataAuto(timestamp, title_id, system); auto function_out = GetHLERequestContextData(ctx, system.Memory()); @@ -283,7 +283,7 @@ void Reporter::SaveUnimplementedAppletReport( } const auto timestamp = GetTimestamp(); - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); auto out = GetFullDataAuto(timestamp, title_id, system); out["applet_common_args"] = { @@ -312,7 +312,7 @@ void Reporter::SaveUnimplementedAppletReport( } void Reporter::SavePlayReport(PlayReportType type, u64 title_id, - const std::vector<std::vector<u8>>& data, + const std::vector<std::span<const u8>>& data, std::optional<u64> process_id, std::optional<u128> user_id) const { if (!IsReportingEnabled()) { return; @@ -376,7 +376,7 @@ void Reporter::SaveUserReport() const { } const auto timestamp = GetTimestamp(); - const auto title_id = system.GetCurrentProcessProgramID(); + const auto title_id = system.GetApplicationProcessProgramID(); SaveToFile(GetFullDataAuto(timestamp, title_id, system), GetPath("user_report", title_id, timestamp)); diff --git a/src/core/reporter.h b/src/core/reporter.h index 9fdb9d6c1..bb11f8e7c 100644 --- a/src/core/reporter.h +++ b/src/core/reporter.h @@ -5,6 +5,7 @@ #include <array> #include <optional> +#include <span> #include <string> #include <vector> #include "common/common_types.h" @@ -56,7 +57,8 @@ public: System, }; - void SavePlayReport(PlayReportType type, u64 title_id, const std::vector<std::vector<u8>>& data, + void SavePlayReport(PlayReportType type, u64 title_id, + const std::vector<std::span<const u8>>& data, std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const; // Used by error applet diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 8d5f2be2f..9178b00ca 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -34,7 +34,7 @@ static u64 GenerateTelemetryId() { mbedtls_entropy_context entropy; mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_context ctr_drbg; - constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}}; + static constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}}; mbedtls_ctr_drbg_init(&ctr_drbg); ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, |