diff options
Diffstat (limited to 'src/core')
195 files changed, 4062 insertions, 1683 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8ce141e6a..3621449b3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -29,15 +29,17 @@ set(SRCS file_sys/ivfc_archive.cpp file_sys/path_parser.cpp file_sys/savedata_archive.cpp + frontend/emu_window.cpp + frontend/key_map.cpp gdbstub/gdbstub.cpp hle/config_mem.cpp - hle/hle.cpp hle/applets/applet.cpp hle/applets/erreula.cpp hle/applets/mii_selector.cpp hle/applets/swkbd.cpp hle/kernel/address_arbiter.cpp hle/kernel/client_port.cpp + hle/kernel/client_session.cpp hle/kernel/event.cpp hle/kernel/kernel.cpp hle/kernel/memory.cpp @@ -46,14 +48,15 @@ set(SRCS hle/kernel/resource_limit.cpp hle/kernel/semaphore.cpp hle/kernel/server_port.cpp - hle/kernel/session.cpp + hle/kernel/server_session.cpp hle/kernel/shared_memory.cpp hle/kernel/thread.cpp hle/kernel/timer.cpp hle/kernel/vm_manager.cpp hle/service/ac_u.cpp - hle/service/act_a.cpp - hle/service/act_u.cpp + hle/service/act/act.cpp + hle/service/act/act_a.cpp + hle/service/act/act_u.cpp hle/service/am/am.cpp hle/service/am/am_app.cpp hle/service/am/am_net.cpp @@ -73,10 +76,12 @@ set(SRCS hle/service/cam/cam_s.cpp hle/service/cam/cam_u.cpp hle/service/cecd/cecd.cpp + hle/service/cecd/cecd_ndm.cpp hle/service/cecd/cecd_s.cpp hle/service/cecd/cecd_u.cpp hle/service/cfg/cfg.cpp hle/service/cfg/cfg_i.cpp + hle/service/cfg/cfg_nor.cpp hle/service/cfg/cfg_s.cpp hle/service/cfg/cfg_u.cpp hle/service/csnd_snd.cpp @@ -105,8 +110,13 @@ set(SRCS hle/service/ldr_ro/ldr_ro.cpp hle/service/ldr_ro/memory_synchronizer.cpp hle/service/mic_u.cpp + hle/service/mvd/mvd.cpp + hle/service/mvd/mvd_std.cpp hle/service/ndm/ndm.cpp hle/service/ndm/ndm_u.cpp + hle/service/nfc/nfc.cpp + hle/service/nfc/nfc_m.cpp + hle/service/nfc/nfc_u.cpp hle/service/news/news.cpp hle/service/news/news_s.cpp hle/service/news/news_u.cpp @@ -115,12 +125,25 @@ set(SRCS hle/service/nim/nim_s.cpp hle/service/nim/nim_u.cpp hle/service/ns_s.cpp - hle/service/nwm_uds.cpp + hle/service/nwm/nwm.cpp + hle/service/nwm/nwm_cec.cpp + hle/service/nwm/nwm_ext.cpp + hle/service/nwm/nwm_inf.cpp + hle/service/nwm/nwm_sap.cpp + hle/service/nwm/nwm_soc.cpp + hle/service/nwm/nwm_tst.cpp + hle/service/nwm/nwm_uds.cpp hle/service/pm_app.cpp hle/service/ptm/ptm.cpp + hle/service/ptm/ptm_gets.cpp hle/service/ptm/ptm_play.cpp + hle/service/ptm/ptm_sets.cpp hle/service/ptm/ptm_sysm.cpp hle/service/ptm/ptm_u.cpp + hle/service/qtm/qtm.cpp + hle/service/qtm/qtm_s.cpp + hle/service/qtm/qtm_sp.cpp + hle/service/qtm/qtm_u.cpp hle/service/service.cpp hle/service/soc_u.cpp hle/service/srv.cpp @@ -140,7 +163,6 @@ set(SRCS tracer/recorder.cpp memory.cpp settings.cpp - system.cpp ) set(HEADERS @@ -178,16 +200,19 @@ set(HEADERS file_sys/ivfc_archive.h file_sys/path_parser.h file_sys/savedata_archive.h + frontend/emu_window.h + frontend/key_map.h gdbstub/gdbstub.h hle/config_mem.h hle/function_wrappers.h - hle/hle.h + hle/ipc.h hle/applets/applet.h hle/applets/erreula.h hle/applets/mii_selector.h hle/applets/swkbd.h hle/kernel/address_arbiter.h hle/kernel/client_port.h + hle/kernel/client_session.h hle/kernel/event.h hle/kernel/kernel.h hle/kernel/memory.h @@ -196,15 +221,16 @@ set(HEADERS hle/kernel/resource_limit.h hle/kernel/semaphore.h hle/kernel/server_port.h - hle/kernel/session.h + hle/kernel/server_session.h hle/kernel/shared_memory.h hle/kernel/thread.h hle/kernel/timer.h hle/kernel/vm_manager.h hle/result.h hle/service/ac_u.h - hle/service/act_a.h - hle/service/act_u.h + hle/service/act/act.h + hle/service/act/act_a.h + hle/service/act/act_u.h hle/service/am/am.h hle/service/am/am_app.h hle/service/am/am_net.h @@ -224,10 +250,12 @@ set(HEADERS hle/service/cam/cam_s.h hle/service/cam/cam_u.h hle/service/cecd/cecd.h + hle/service/cecd/cecd_ndm.h hle/service/cecd/cecd_s.h hle/service/cecd/cecd_u.h hle/service/cfg/cfg.h hle/service/cfg/cfg_i.h + hle/service/cfg/cfg_nor.h hle/service/cfg/cfg_s.h hle/service/cfg/cfg_u.h hle/service/csnd_snd.h @@ -256,8 +284,13 @@ set(HEADERS hle/service/ldr_ro/ldr_ro.h hle/service/ldr_ro/memory_synchronizer.h hle/service/mic_u.h + hle/service/mvd/mvd.h + hle/service/mvd/mvd_std.h hle/service/ndm/ndm.h hle/service/ndm/ndm_u.h + hle/service/nfc/nfc.h + hle/service/nfc/nfc_m.h + hle/service/nfc/nfc_u.h hle/service/news/news.h hle/service/news/news_s.h hle/service/news/news_u.h @@ -266,12 +299,25 @@ set(HEADERS hle/service/nim/nim_s.h hle/service/nim/nim_u.h hle/service/ns_s.h - hle/service/nwm_uds.h + hle/service/nwm/nwm.h + hle/service/nwm/nwm_cec.h + hle/service/nwm/nwm_ext.h + hle/service/nwm/nwm_inf.h + hle/service/nwm/nwm_sap.h + hle/service/nwm/nwm_soc.h + hle/service/nwm/nwm_tst.h + hle/service/nwm/nwm_uds.h hle/service/pm_app.h hle/service/ptm/ptm.h + hle/service/ptm/ptm_gets.h hle/service/ptm/ptm_play.h + hle/service/ptm/ptm_sets.h hle/service/ptm/ptm_sysm.h hle/service/ptm/ptm_u.h + hle/service/qtm/qtm.h + hle/service/qtm/qtm_s.h + hle/service/qtm/qtm_sp.h + hle/service/qtm/qtm_u.h hle/service/service.h hle/service/soc_u.h hle/service/srv.h @@ -294,7 +340,6 @@ set(HEADERS memory_setup.h mmio.h settings.h - system.h ) include_directories(../../externals/dynarmic/include) diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index e466b21b2..ccd43f431 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -8,15 +8,22 @@ #include "core/arm/skyeye_common/arm_regformat.h" #include "core/arm/skyeye_common/vfp/asm_vfp.h" -namespace Core { -struct ThreadContext; -} - /// Generic ARM11 CPU interface class ARM_Interface : NonCopyable { public: virtual ~ARM_Interface() {} + struct ThreadContext { + u32 cpu_registers[13]; + u32 sp; + u32 lr; + u32 pc; + u32 cpsr; + u32 fpu_registers[64]; + u32 fpscr; + u32 fpexc; + }; + /** * Runs the CPU for the given number of instructions * @param num_instructions Number of instructions to run @@ -124,13 +131,13 @@ public: * Saves the current CPU context * @param ctx Thread context to save */ - virtual void SaveContext(Core::ThreadContext& ctx) = 0; + virtual void SaveContext(ThreadContext& ctx) = 0; /** * Loads a CPU context * @param ctx Thread context to load */ - virtual void LoadContext(const Core::ThreadContext& ctx) = 0; + virtual void LoadContext(const ThreadContext& ctx) = 0; /// Prepare core for thread reschedule (if needed to correctly handle state) virtual void PrepareReschedule() = 0; diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index ca8a94ee9..9f25e3b00 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> #include <dynarmic/dynarmic.h> #include "common/assert.h" #include "common/microprofile.h" @@ -44,6 +45,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks(ARMul_State* interpeter_state) { user_callbacks.user_arg = static_cast<void*>(interpeter_state); user_callbacks.CallSVC = &SVC::CallSVC; user_callbacks.IsReadOnlyMemory = &IsReadOnlyMemory; + user_callbacks.MemoryReadCode = &Memory::Read32; user_callbacks.MemoryRead8 = &Memory::Read8; user_callbacks.MemoryRead16 = &Memory::Read16; user_callbacks.MemoryRead32 = &Memory::Read32; @@ -136,7 +138,7 @@ void ARM_Dynarmic::ExecuteInstructions(int num_instructions) { AddTicks(ticks_executed); } -void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) { +void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers)); memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers)); @@ -149,7 +151,7 @@ void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) { ctx.fpexc = interpreter_state->VFP[VFP_FPEXC]; } -void ARM_Dynarmic::LoadContext(const Core::ThreadContext& ctx) { +void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index ced86d29b..87ab53d81 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -10,10 +10,6 @@ #include "core/arm/arm_interface.h" #include "core/arm/skyeye_common/armstate.h" -namespace Core { -struct ThreadContext; -} - class ARM_Dynarmic final : public ARM_Interface { public: ARM_Dynarmic(PrivilegeMode initial_mode); @@ -33,8 +29,8 @@ public: void AddTicks(u64 ticks) override; - void SaveContext(Core::ThreadContext& ctx) override; - void LoadContext(const Core::ThreadContext& ctx) override; + void SaveContext(ThreadContext& ctx) override; + void LoadContext(const ThreadContext& ctx) override; void PrepareReschedule() override; void ExecuteInstructions(int num_instructions) override; diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 34c7f945e..81f9bf99e 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -89,7 +89,7 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) { AddTicks(ticks_executed); } -void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { +void ARM_DynCom::SaveContext(ThreadContext& ctx) { memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); @@ -102,7 +102,7 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { ctx.fpexc = state->VFP[VFP_FPEXC]; } -void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { +void ARM_DynCom::LoadContext(const ThreadContext& ctx) { memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 65db1f0f9..62c174f3c 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -10,10 +10,6 @@ #include "core/arm/skyeye_common/arm_regformat.h" #include "core/arm/skyeye_common/armstate.h" -namespace Core { -struct ThreadContext; -} - class ARM_DynCom final : public ARM_Interface { public: ARM_DynCom(PrivilegeMode initial_mode); @@ -36,8 +32,8 @@ public: void AddTicks(u64 ticks) override; - void SaveContext(Core::ThreadContext& ctx) override; - void LoadContext(const Core::ThreadContext& ctx) override; + void SaveContext(ThreadContext& ctx) override; + void LoadContext(const ThreadContext& ctx) override; void PrepareReschedule() override; void ExecuteInstructions(int num_instructions) override; diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 7b8616702..67c45640a 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -953,7 +953,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #define GDB_BP_CHECK \ cpu->Cpsr &= ~(1 << 5); \ cpu->Cpsr |= cpu->TFlag << 5; \ - if (GDBStub::g_server_enabled) { \ + if (GDBStub::IsServerEnabled()) { \ if (GDBStub::IsMemoryBreak() || (breakpoint_data.type != GDBStub::BreakpointType::None && \ PC == breakpoint_data.address)) { \ GDBStub::Break(); \ @@ -1649,7 +1649,7 @@ DISPATCH : { } // Find breakpoint if one exists within the block - if (GDBStub::g_server_enabled && GDBStub::IsConnected()) { + if (GDBStub::IsConnected()) { breakpoint_data = GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute); } diff --git a/src/core/arm/dyncom/arm_dyncom_trans.h b/src/core/arm/dyncom/arm_dyncom_trans.h index b1ec90662..632ff2cd6 100644 --- a/src/core/arm/dyncom/arm_dyncom_trans.h +++ b/src/core/arm/dyncom/arm_dyncom_trans.h @@ -1,3 +1,5 @@ +#pragma once + #include <cstddef> #include "common/common_types.h" diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp index 1465b074e..c36b0208f 100644 --- a/src/core/arm/skyeye_common/armstate.cpp +++ b/src/core/arm/skyeye_common/armstate.cpp @@ -182,7 +182,7 @@ void ARMul_State::ResetMPCoreCP15Registers() { } static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) { - if (GDBStub::g_server_enabled && GDBStub::CheckBreakpoint(address, type)) { + if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) { LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address); GDBStub::Break(true); } diff --git a/src/core/core.cpp b/src/core/core.cpp index 49ac8be6e..202cd332b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -3,6 +3,8 @@ // Refer to the license.txt file included. #include <memory> + +#include "audio_core/audio_core.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/arm/dynarmic/arm_dynarmic.h" @@ -10,19 +12,25 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/gdbstub/gdbstub.h" -#include "core/hle/hle.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/memory.h" #include "core/hle/kernel/thread.h" +#include "core/hle/service/service.h" #include "core/hw/hw.h" +#include "core/loader/loader.h" #include "core/settings.h" +#include "video_core/video_core.h" namespace Core { -std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core -std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core +/*static*/ System System::s_instance; + +System::ResultStatus System::RunLoop(int tight_loop) { + if (!cpu_core) { + return ResultStatus::ErrorNotInitialized; + } -/// Run the core CPU loop -void RunLoop(int tight_loop) { - if (GDBStub::g_server_enabled) { + if (GDBStub::IsServerEnabled()) { GDBStub::HandlePacket(); // If the loop is halted and we want to step, use a tiny (1) number of instructions to @@ -32,7 +40,7 @@ void RunLoop(int tight_loop) { GDBStub::SetCpuStepFlag(false); tight_loop = 1; } else { - return; + return ResultStatus::Success; } } } @@ -43,48 +51,115 @@ void RunLoop(int tight_loop) { LOG_TRACE(Core_ARM11, "Idling"); CoreTiming::Idle(); CoreTiming::Advance(); - HLE::Reschedule(__func__); + PrepareReschedule(); } else { - g_app_core->Run(tight_loop); + cpu_core->Run(tight_loop); } HW::Update(); - if (HLE::IsReschedulePending()) { - Kernel::Reschedule(); - } + Reschedule(); + + return ResultStatus::Success; +} + +System::ResultStatus System::SingleStep() { + return RunLoop(1); } -/// Step the CPU one instruction -void SingleStep() { - RunLoop(1); +System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) { + if (app_loader) { + app_loader.reset(); + } + + app_loader = Loader::GetLoader(filepath); + + if (!app_loader) { + LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str()); + return ResultStatus::ErrorGetLoader; + } + + boost::optional<u32> system_mode{app_loader->LoadKernelSystemMode()}; + if (!system_mode) { + LOG_CRITICAL(Core, "Failed to determine system mode!"); + return ResultStatus::ErrorSystemMode; + } + + ResultStatus init_result{Init(emu_window, system_mode.get())}; + if (init_result != ResultStatus::Success) { + LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result); + System::Shutdown(); + return init_result; + } + + const Loader::ResultStatus load_result{app_loader->Load()}; + if (Loader::ResultStatus::Success != load_result) { + LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result); + System::Shutdown(); + + switch (load_result) { + case Loader::ResultStatus::ErrorEncrypted: + return ResultStatus::ErrorLoader_ErrorEncrypted; + case Loader::ResultStatus::ErrorInvalidFormat: + return ResultStatus::ErrorLoader_ErrorInvalidFormat; + default: + return ResultStatus::ErrorLoader; + } + } + return ResultStatus::Success; } -/// Halt the core -void Halt(const char* msg) { - // TODO(ShizZy): ImplementMe +void System::PrepareReschedule() { + cpu_core->PrepareReschedule(); + reschedule_pending = true; } -/// Kill the core -void Stop() { - // TODO(ShizZy): ImplementMe +void System::Reschedule() { + if (!reschedule_pending) { + return; + } + + reschedule_pending = false; + Kernel::Reschedule(); } -/// Initialize the core -void Init() { +System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { + if (cpu_core) { + cpu_core.reset(); + } + + Memory::Init(); + if (Settings::values.use_cpu_jit) { - g_sys_core = std::make_unique<ARM_Dynarmic>(USER32MODE); - g_app_core = std::make_unique<ARM_Dynarmic>(USER32MODE); + cpu_core = std::make_unique<ARM_Dynarmic>(USER32MODE); } else { - g_sys_core = std::make_unique<ARM_DynCom>(USER32MODE); - g_app_core = std::make_unique<ARM_DynCom>(USER32MODE); + cpu_core = std::make_unique<ARM_DynCom>(USER32MODE); + } + + CoreTiming::Init(); + HW::Init(); + Kernel::Init(system_mode); + Service::Init(); + AudioCore::Init(); + GDBStub::Init(); + + if (!VideoCore::Init(emu_window)) { + return ResultStatus::ErrorVideoCore; } LOG_DEBUG(Core, "Initialized OK"); + + return ResultStatus::Success; } -void Shutdown() { - g_app_core.reset(); - g_sys_core.reset(); +void System::Shutdown() { + GDBStub::Shutdown(); + AudioCore::Shutdown(); + VideoCore::Shutdown(); + Service::Shutdown(); + Kernel::Shutdown(); + HW::Shutdown(); + CoreTiming::Shutdown(); + cpu_core.reset(); LOG_DEBUG(Core, "Shutdown OK"); } diff --git a/src/core/core.h b/src/core/core.h index ffbfa91c3..1015e8847 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -5,56 +5,118 @@ #pragma once #include <memory> +#include <string> + #include "common/common_types.h" +#include "core/memory.h" +class EmuWindow; class ARM_Interface; -//////////////////////////////////////////////////////////////////////////////////////////////////// +namespace Loader { +class AppLoader; +} namespace Core { -struct ThreadContext { - u32 cpu_registers[13]; - u32 sp; - u32 lr; - u32 pc; - u32 cpsr; - u32 fpu_registers[64]; - u32 fpscr; - u32 fpexc; +class System { +public: + /** + * Gets the instance of the System singleton class. + * @returns Reference to the instance of the System singleton class. + */ + static System& GetInstance() { + return s_instance; + } + + /// Enumeration representing the return values of the System Initialize and Load process. + enum class ResultStatus : u32 { + Success, ///< Succeeded + ErrorNotInitialized, ///< Error trying to use core prior to initialization + ErrorGetLoader, ///< Error finding the correct application loader + ErrorSystemMode, ///< Error determining the system mode + ErrorLoader, ///< Error loading the specified application + ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption + ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an + /// invalid format + ErrorVideoCore, ///< Error in the video core + }; + + /** + * Run the core CPU loop + * This function runs the core for the specified number of CPU instructions before trying to + * update hardware. This is much faster than SingleStep (and should be equivalent), as the CPU + * is not required to do a full dispatch with each instruction. NOTE: the number of instructions + * requested is not guaranteed to run, as this will be interrupted preemptively if a hardware + * update is requested (e.g. on a thread switch). + * @param tight_loop Number of instructions to execute. + * @return Result status, indicating whethor or not the operation succeeded. + */ + ResultStatus RunLoop(int tight_loop = 1000); + + /** + * Step the CPU one instruction + * @return Result status, indicating whethor or not the operation succeeded. + */ + ResultStatus SingleStep(); + + /// Shutdown the emulated system. + void Shutdown(); + + /** + * Load an executable application. + * @param emu_window Pointer to the host-system window used for video output and keyboard input. + * @param filepath String path to the executable application to load on the host file system. + * @returns ResultStatus code, indicating if the operation succeeded. + */ + ResultStatus Load(EmuWindow* emu_window, const std::string& filepath); + + /** + * Indicates if the emulated system is powered on (all subsystems initialized and able to run an + * application). + * @returns True if the emulated system is powered on, otherwise false. + */ + bool IsPoweredOn() const { + return cpu_core != nullptr; + } + + /// Prepare the core emulation for a reschedule + void PrepareReschedule(); + + /** + * Gets a reference to the emulated CPU. + * @returns A reference to the emulated CPU. + */ + ARM_Interface& CPU() { + return *cpu_core; + } + +private: + /** + * Initialize the emulated system. + * @param emu_window Pointer to the host-system window used for video output and keyboard input. + * @param system_mode The system mode. + * @return ResultStatus code, indicating if the operation succeeded. + */ + ResultStatus Init(EmuWindow* emu_window, u32 system_mode); + + /// Reschedule the core emulation + void Reschedule(); + + /// AppLoader used to load the current executing application + std::unique_ptr<Loader::AppLoader> app_loader; + + ///< ARM11 CPU core + std::unique_ptr<ARM_Interface> cpu_core; + + /// When true, signals that a reschedule should happen + bool reschedule_pending{}; + + static System s_instance; }; -extern std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core -extern std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Start the core -void Start(); - -/** - * Run the core CPU loop - * This function runs the core for the specified number of CPU instructions before trying to update - * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not - * required to do a full dispatch with each instruction. NOTE: the number of instructions requested - * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is - * requested (e.g. on a thread switch). - */ -void RunLoop(int tight_loop = 1000); - -/// Step the CPU one instruction -void SingleStep(); - -/// Halt the core -void Halt(const char* msg); - -/// Kill the core -void Stop(); - -/// Initialize the core -void Init(); - -/// Shutdown the core -void Shutdown(); +static ARM_Interface& CPU() { + return System::GetInstance().CPU(); +} -} // namespace +} // namespace Core diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 5220b55ea..a437d0823 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -130,7 +130,6 @@ int RegisterEvent(const char* name, TimedCallback callback) { static void AntiCrashCallback(u64 userdata, int cycles_late) { LOG_CRITICAL(Core_Timing, "Savestate broken: an unregistered event was called."); - Core::Halt("invalid timing events"); } void RestoreRegisterEvent(int event_type, const char* name, TimedCallback callback) { @@ -147,7 +146,7 @@ void UnregisterAllEvents() { } void Init() { - Core::g_app_core->down_count = INITIAL_SLICE_LENGTH; + Core::CPU().down_count = INITIAL_SLICE_LENGTH; g_slice_length = INITIAL_SLICE_LENGTH; global_timer = 0; idled_cycles = 0; @@ -187,7 +186,7 @@ void Shutdown() { } u64 GetTicks() { - return (u64)global_timer + g_slice_length - Core::g_app_core->down_count; + return (u64)global_timer + g_slice_length - Core::CPU().down_count; } u64 GetIdleTicks() { @@ -461,18 +460,18 @@ void MoveEvents() { } void ForceCheck() { - s64 cycles_executed = g_slice_length - Core::g_app_core->down_count; + s64 cycles_executed = g_slice_length - Core::CPU().down_count; global_timer += cycles_executed; // This will cause us to check for new events immediately. - Core::g_app_core->down_count = 0; + Core::CPU().down_count = 0; // But let's not eat a bunch more time in Advance() because of this. g_slice_length = 0; } void Advance() { - s64 cycles_executed = g_slice_length - Core::g_app_core->down_count; + s64 cycles_executed = g_slice_length - Core::CPU().down_count; global_timer += cycles_executed; - Core::g_app_core->down_count = g_slice_length; + Core::CPU().down_count = g_slice_length; if (has_ts_events) MoveEvents(); @@ -481,7 +480,7 @@ void Advance() { if (!first) { if (g_slice_length < 10000) { g_slice_length += 10000; - Core::g_app_core->down_count += g_slice_length; + Core::CPU().down_count += g_slice_length; } } else { // Note that events can eat cycles as well. @@ -491,7 +490,7 @@ void Advance() { const int diff = target - g_slice_length; g_slice_length += diff; - Core::g_app_core->down_count += diff; + Core::CPU().down_count += diff; } if (advance_callback) advance_callback(static_cast<int>(cycles_executed)); @@ -507,12 +506,12 @@ void LogPendingEvents() { } void Idle(int max_idle) { - s64 cycles_down = Core::g_app_core->down_count; + s64 cycles_down = Core::CPU().down_count; if (max_idle != 0 && cycles_down > max_idle) cycles_down = max_idle; if (first && cycles_down > 0) { - s64 cycles_executed = g_slice_length - Core::g_app_core->down_count; + s64 cycles_executed = g_slice_length - Core::CPU().down_count; s64 cycles_next_event = first->time - global_timer; if (cycles_next_event < cycles_executed + cycles_down) { @@ -527,9 +526,9 @@ void Idle(int max_idle) { cycles_down / (float)(g_clock_rate_arm11 * 0.001f)); idled_cycles += cycles_down; - Core::g_app_core->down_count -= cycles_down; - if (Core::g_app_core->down_count == 0) - Core::g_app_core->down_count = -1; + Core::CPU().down_count -= cycles_down; + if (Core::CPU().down_count == 0) + Core::CPU().down_count = -1; } std::string GetScheduledEventsSummary() { diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index e1c4931ec..51ce78435 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -64,7 +64,7 @@ private: */ class ExtSaveDataArchive : public SaveDataArchive { public: - ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {} + explicit ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {} std::string GetName() const override { return "ExtSaveDataArchive: " + mount_point; @@ -141,11 +141,10 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) { if (shared) - return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), - SYSTEM_ID.c_str()); + return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID); - return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), - SYSTEM_ID.c_str(), SDCARD_ID.c_str()); + return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), SYSTEM_ID, + SDCARD_ID); } Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) { diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp index 6f1aadfc3..89455e39c 100644 --- a/src/core/file_sys/archive_ncch.cpp +++ b/src/core/file_sys/archive_ncch.cpp @@ -19,7 +19,7 @@ namespace FileSys { static std::string GetNCCHContainerPath(const std::string& nand_directory) { - return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID.c_str()); + return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID); } static std::string GetNCCHPath(const std::string& mount_point, u32 high, u32 low) { diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h index 66b8ce75d..753b91f96 100644 --- a/src/core/file_sys/archive_ncch.h +++ b/src/core/file_sys/archive_ncch.h @@ -17,7 +17,7 @@ namespace FileSys { /// File system interface to the NCCH archive class ArchiveFactory_NCCH final : public ArchiveFactory { public: - ArchiveFactory_NCCH(const std::string& mount_point); + explicit ArchiveFactory_NCCH(const std::string& mount_point); std::string GetName() const override { return "NCCH"; diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 8a8082a05..1eaf99b54 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -20,7 +20,7 @@ namespace FileSys { /// File system interface to the RomFS archive class ArchiveFactory_RomFS final : public ArchiveFactory { public: - ArchiveFactory_RomFS(Loader::AppLoader& app_loader); + explicit ArchiveFactory_RomFS(Loader::AppLoader& app_loader); std::string GetName() const override { return "RomFS"; diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 9d99b110c..f6c70bfcc 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -17,7 +17,7 @@ namespace FileSys { /// Archive backend for SDMC archive class SDMCArchive : public ArchiveBackend { public: - SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {} + explicit SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {} std::string GetName() const override { return "SDMCArchive: " + mount_point; @@ -43,7 +43,7 @@ protected: /// File system interface to the SDMC archive class ArchiveFactory_SDMC final : public ArchiveFactory { public: - ArchiveFactory_SDMC(const std::string& mount_point); + explicit ArchiveFactory_SDMC(const std::string& mount_point); /** * Initialize the archive. diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h index ed977485a..9cd38d96f 100644 --- a/src/core/file_sys/archive_sdmcwriteonly.h +++ b/src/core/file_sys/archive_sdmcwriteonly.h @@ -19,7 +19,7 @@ namespace FileSys { */ class SDMCWriteOnlyArchive : public SDMCArchive { public: - SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {} + explicit SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {} std::string GetName() const override { return "SDMCWriteOnlyArchive: " + mount_point; @@ -34,7 +34,7 @@ public: /// File system interface to the SDMC write-only archive class ArchiveFactory_SDMCWriteOnly final : public ArchiveFactory { public: - ArchiveFactory_SDMCWriteOnly(const std::string& mount_point); + explicit ArchiveFactory_SDMCWriteOnly(const std::string& mount_point); /** * Initialize the archive. diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp index 2d8a950a3..e01357891 100644 --- a/src/core/file_sys/archive_source_sd_savedata.cpp +++ b/src/core/file_sys/archive_source_sd_savedata.cpp @@ -18,7 +18,7 @@ namespace { std::string GetSaveDataContainerPath(const std::string& sdmc_directory) { return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), - SYSTEM_ID.c_str(), SDCARD_ID.c_str()); + SYSTEM_ID, SDCARD_ID); } std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) { @@ -90,4 +90,9 @@ ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program return MakeResult<ArchiveFormatInfo>(info); } +std::string ArchiveSource_SDSaveData::GetSaveDataPathFor(const std::string& mount_point, + u64 program_id) { + return GetSaveDataPath(GetSaveDataContainerPath(mount_point), program_id); +} + } // namespace FileSys diff --git a/src/core/file_sys/archive_source_sd_savedata.h b/src/core/file_sys/archive_source_sd_savedata.h index b33126c31..b5fe43cc1 100644 --- a/src/core/file_sys/archive_source_sd_savedata.h +++ b/src/core/file_sys/archive_source_sd_savedata.h @@ -23,6 +23,8 @@ public: ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info); ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const; + static std::string GetSaveDataPathFor(const std::string& mount_point, u64 program_id); + private: std::string mount_point; }; diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index 54e7793e0..8986b5c0e 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp @@ -26,7 +26,7 @@ std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& pa } std::string GetSystemSaveDataContainerPath(const std::string& mount_point) { - return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID.c_str()); + return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID); } Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) { diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h index a24b89f2b..52eb6c630 100644 --- a/src/core/file_sys/archive_systemsavedata.h +++ b/src/core/file_sys/archive_systemsavedata.h @@ -18,7 +18,7 @@ namespace FileSys { /// File system interface to the SystemSaveData archive class ArchiveFactory_SystemSaveData final : public ArchiveFactory { public: - ArchiveFactory_SystemSaveData(const std::string& mount_point); + explicit ArchiveFactory_SystemSaveData(const std::string& mount_point); ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; diff --git a/src/core/file_sys/path_parser.h b/src/core/file_sys/path_parser.h index 990802579..b9f52f65d 100644 --- a/src/core/file_sys/path_parser.h +++ b/src/core/file_sys/path_parser.h @@ -17,7 +17,7 @@ namespace FileSys { */ class PathParser { public: - PathParser(const Path& path); + explicit PathParser(const Path& path); /** * Checks if the Path is valid. diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h index 2fb6c452a..176d35710 100644 --- a/src/core/file_sys/savedata_archive.h +++ b/src/core/file_sys/savedata_archive.h @@ -18,7 +18,7 @@ namespace FileSys { /// Archive backend for general save data archive type (SaveData and SystemSaveData) class SaveDataArchive : public ArchiveBackend { public: - SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {} + explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {} std::string GetName() const override { return "SaveDataArchive: " + mount_point; diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp new file mode 100644 index 000000000..f6f90f9e1 --- /dev/null +++ b/src/core/frontend/emu_window.cpp @@ -0,0 +1,107 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cmath> +#include "common/assert.h" +#include "core/frontend/emu_window.h" +#include "core/frontend/key_map.h" +#include "video_core/video_core.h" + +void EmuWindow::ButtonPressed(Service::HID::PadState pad) { + pad_state.hex |= pad.hex; +} + +void EmuWindow::ButtonReleased(Service::HID::PadState pad) { + pad_state.hex &= ~pad.hex; +} + +void EmuWindow::CirclePadUpdated(float x, float y) { + constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position + + // Make sure the coordinates are in the unit circle, + // otherwise normalize it. + float r = x * x + y * y; + if (r > 1) { + r = std::sqrt(r); + x /= r; + y /= r; + } + + circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS); + circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS); +} + +/** + * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout + * @param layout FramebufferLayout object describing the framebuffer size and screen positions + * @param framebuffer_x Framebuffer x-coordinate to check + * @param framebuffer_y Framebuffer y-coordinate to check + * @return True if the coordinates are within the touchpad, otherwise false + */ +static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigned framebuffer_x, + unsigned framebuffer_y) { + return ( + framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom && + framebuffer_x >= layout.bottom_screen.left && framebuffer_x < layout.bottom_screen.right); +} + +std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { + new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); + new_x = std::min(new_x, framebuffer_layout.bottom_screen.right - 1); + + new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); + new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom - 1); + + return std::make_tuple(new_x, new_y); +} + +void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { + if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) + return; + + touch_x = VideoCore::kScreenBottomWidth * + (framebuffer_x - framebuffer_layout.bottom_screen.left) / + (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); + touch_y = VideoCore::kScreenBottomHeight * + (framebuffer_y - framebuffer_layout.bottom_screen.top) / + (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); + + touch_pressed = true; + pad_state.touch.Assign(1); +} + +void EmuWindow::TouchReleased() { + touch_pressed = false; + touch_x = 0; + touch_y = 0; + pad_state.touch.Assign(0); +} + +void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { + if (!touch_pressed) + return; + + if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) + std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); + + TouchPressed(framebuffer_x, framebuffer_y); +} + +void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { + Layout::FramebufferLayout layout; + switch (Settings::values.layout_option) { + case Settings::LayoutOption::SingleScreen: + layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen); + break; + case Settings::LayoutOption::LargeScreen: + layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen); + break; + case Settings::LayoutOption::Default: + default: + layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen); + break; + } + NotifyFramebufferLayoutChanged(layout); +} diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h new file mode 100644 index 000000000..835c4d500 --- /dev/null +++ b/src/core/frontend/emu_window.h @@ -0,0 +1,290 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <tuple> +#include <utility> +#include "common/common_types.h" +#include "common/framebuffer_layout.h" +#include "common/math_util.h" +#include "core/hle/service/hid/hid.h" + +/** + * Abstraction class used to provide an interface between emulation code and the frontend + * (e.g. SDL, QGLWidget, GLFW, etc...). + * + * Design notes on the interaction between EmuWindow and the emulation core: + * - Generally, decisions on anything visible to the user should be left up to the GUI. + * For example, the emulation core should not try to dictate some window title or size. + * This stuff is not the core's business and only causes problems with regards to thread-safety + * anyway. + * - Under certain circumstances, it may be desirable for the core to politely request the GUI + * to set e.g. a minimum window size. However, the GUI should always be free to ignore any + * such hints. + * - EmuWindow may expose some of its state as read-only to the emulation core, however care + * should be taken to make sure the provided information is self-consistent. This requires + * some sort of synchronization (most of this is still a TODO). + * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please + * re-read the upper points again and think about it if you don't see this. + */ +class EmuWindow { +public: + /// Data structure to store emuwindow configuration + struct WindowConfig { + bool fullscreen; + int res_width; + int res_height; + std::pair<unsigned, unsigned> min_client_area_size; + }; + + /// Swap buffers to display the next frame + virtual void SwapBuffers() = 0; + + /// Polls window events + virtual void PollEvents() = 0; + + /// Makes the graphics context current for the caller thread + virtual void MakeCurrent() = 0; + + /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread + virtual void DoneCurrent() = 0; + + virtual void ReloadSetKeymaps() = 0; + + /** + * Signals a button press action to the HID module. + * @param pad_state indicates which button to press + * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad. + */ + void ButtonPressed(Service::HID::PadState pad_state); + + /** + * Signals a button release action to the HID module. + * @param pad_state indicates which button to press + * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad. + */ + void ButtonReleased(Service::HID::PadState pad_state); + + /** + * Signals a circle pad change action to the HID module. + * @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0] + * @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0] + * @note the coordinates will be normalized if the radius is larger than 1 + */ + void CirclePadUpdated(float x, float y); + + /** + * Signal that a touch pressed event has occurred (e.g. mouse click pressed) + * @param framebuffer_x Framebuffer x-coordinate that was pressed + * @param framebuffer_y Framebuffer y-coordinate that was pressed + */ + void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y); + + /// Signal that a touch released event has occurred (e.g. mouse click released) + void TouchReleased(); + + /** + * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) + * @param framebuffer_x Framebuffer x-coordinate + * @param framebuffer_y Framebuffer y-coordinate + */ + void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); + + /** + * Gets the current pad state (which buttons are pressed). + * @note This should be called by the core emu thread to get a state set by the window thread. + * @note This doesn't include analog input like circle pad direction + * @todo Fix this function to be thread-safe. + * @return PadState object indicating the current pad state + */ + Service::HID::PadState GetPadState() const { + return pad_state; + } + + /** + * Gets the current circle pad state. + * @note This should be called by the core emu thread to get a state set by the window thread. + * @todo Fix this function to be thread-safe. + * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates + */ + std::tuple<s16, s16> GetCirclePadState() const { + return std::make_tuple(circle_pad_x, circle_pad_y); + } + + /** + * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). + * @note This should be called by the core emu thread to get a state set by the window thread. + * @todo Fix this function to be thread-safe. + * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and + * `pressed` is true if the touch screen is currently being pressed + */ + std::tuple<u16, u16, bool> GetTouchState() const { + return std::make_tuple(touch_x, touch_y, touch_pressed); + } + + /** + * Gets the current accelerometer state (acceleration along each three axis). + * Axis explained: + * +x is the same direction as LEFT on D-pad. + * +y is normal to the touch screen, pointing outward. + * +z is the same direction as UP on D-pad. + * Units: + * 1 unit of return value = 1/512 g (measured by hw test), + * where g is the gravitational acceleration (9.8 m/sec2). + * @note This should be called by the core emu thread to get a state set by the window thread. + * @todo Implement accelerometer input in front-end. + * @return std::tuple of (x, y, z) + */ + std::tuple<s16, s16, s16> GetAccelerometerState() const { + // stubbed + return std::make_tuple(0, -512, 0); + } + + /** + * Gets the current gyroscope state (angular rates about each three axis). + * Axis explained: + * +x is the same direction as LEFT on D-pad. + * +y is normal to the touch screen, pointing outward. + * +z is the same direction as UP on D-pad. + * Orientation is determined by right-hand rule. + * Units: + * 1 unit of return value = (1/coef) deg/sec, + * where coef is the return value of GetGyroscopeRawToDpsCoefficient(). + * @note This should be called by the core emu thread to get a state set by the window thread. + * @todo Implement gyroscope input in front-end. + * @return std::tuple of (x, y, z) + */ + std::tuple<s16, s16, s16> GetGyroscopeState() const { + // stubbed + return std::make_tuple(0, 0, 0); + } + + /** + * Gets the coefficient for units conversion of gyroscope state. + * The conversion formula is r = coefficient * v, + * where v is angular rate in deg/sec, + * and r is the gyroscope state. + * @return float-type coefficient + */ + f32 GetGyroscopeRawToDpsCoefficient() const { + return 14.375f; // taken from hw test, and gyroscope's document + } + + /** + * Returns currently active configuration. + * @note Accesses to the returned object need not be consistent because it may be modified in + * another thread + */ + const WindowConfig& GetActiveConfig() const { + return active_config; + } + + /** + * Requests the internal configuration to be replaced by the specified argument at some point in + * the future. + * @note This method is thread-safe, because it delays configuration changes to the GUI event + * loop. Hence there is no guarantee on when the requested configuration will be active. + */ + void SetConfig(const WindowConfig& val) { + config = val; + } + + /** + * Gets the framebuffer layout (width, height, and screen regions) + * @note This method is thread-safe + */ + const Layout::FramebufferLayout& GetFramebufferLayout() const { + return framebuffer_layout; + } + + /** + * Convenience method to update the current frame layout + * Read from the current settings to determine which layout to use. + */ + void UpdateCurrentFramebufferLayout(unsigned width, unsigned height); + +protected: + EmuWindow() { + // TODO: Find a better place to set this. + config.min_client_area_size = std::make_pair(400u, 480u); + active_config = config; + pad_state.hex = 0; + touch_x = 0; + touch_y = 0; + circle_pad_x = 0; + circle_pad_y = 0; + touch_pressed = false; + } + virtual ~EmuWindow() {} + + /** + * Processes any pending configuration changes from the last SetConfig call. + * This method invokes OnMinimalClientAreaChangeRequest if the corresponding configuration + * field changed. + * @note Implementations will usually want to call this from the GUI thread. + * @todo Actually call this in existing implementations. + */ + void ProcessConfigurationChanges() { + // TODO: For proper thread safety, we should eventually implement a proper + // multiple-writer/single-reader queue... + + if (config.min_client_area_size != active_config.min_client_area_size) { + OnMinimalClientAreaChangeRequest(config.min_client_area_size); + config.min_client_area_size = active_config.min_client_area_size; + } + } + + /** + * Update framebuffer layout with the given parameter. + * @note EmuWindow implementations will usually use this in window resize event handlers. + */ + void NotifyFramebufferLayoutChanged(const Layout::FramebufferLayout& layout) { + framebuffer_layout = layout; + } + + /** + * Update internal client area size with the given parameter. + * @note EmuWindow implementations will usually use this in window resize event handlers. + */ + void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) { + client_area_width = size.first; + client_area_height = size.second; + } + +private: + /** + * Handler called when the minimal client area was requested to be changed via SetConfig. + * For the request to be honored, EmuWindow implementations will usually reimplement this + * function. + */ + virtual void OnMinimalClientAreaChangeRequest( + const std::pair<unsigned, unsigned>& minimal_size) { + // By default, ignore this request and do nothing. + } + + Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout + + unsigned client_area_width; ///< Current client width, should be set by window impl. + unsigned client_area_height; ///< Current client height, should be set by window impl. + + WindowConfig config; ///< Internal configuration (changes pending for being applied in + /// ProcessConfigurationChanges) + WindowConfig active_config; ///< Internal active configuration + + bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false + + u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) + u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) + + s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156) + s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156) + + /** + * Clip the provided coordinates to be inside the touchscreen area. + */ + std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); + + Service::HID::PadState pad_state; +}; diff --git a/src/core/frontend/key_map.cpp b/src/core/frontend/key_map.cpp new file mode 100644 index 000000000..15f0e079c --- /dev/null +++ b/src/core/frontend/key_map.cpp @@ -0,0 +1,152 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <map> +#include "core/frontend/emu_window.h" +#include "core/frontend/key_map.h" + +namespace KeyMap { + +// TODO (wwylele): currently we treat c-stick as four direction buttons +// and map it directly to EmuWindow::ButtonPressed. +// It should go the analog input way like circle pad does. +const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ + Service::HID::PAD_A, + Service::HID::PAD_B, + Service::HID::PAD_X, + Service::HID::PAD_Y, + Service::HID::PAD_L, + Service::HID::PAD_R, + Service::HID::PAD_ZL, + Service::HID::PAD_ZR, + Service::HID::PAD_START, + Service::HID::PAD_SELECT, + Service::HID::PAD_NONE, + Service::HID::PAD_UP, + Service::HID::PAD_DOWN, + Service::HID::PAD_LEFT, + Service::HID::PAD_RIGHT, + Service::HID::PAD_C_UP, + Service::HID::PAD_C_DOWN, + Service::HID::PAD_C_LEFT, + Service::HID::PAD_C_RIGHT, + + IndirectTarget::CirclePadUp, + IndirectTarget::CirclePadDown, + IndirectTarget::CirclePadLeft, + IndirectTarget::CirclePadRight, + IndirectTarget::CirclePadModifier, +}}; + +static std::map<HostDeviceKey, KeyTarget> key_map; +static int next_device_id = 0; + +static bool circle_pad_up = false; +static bool circle_pad_down = false; +static bool circle_pad_left = false; +static bool circle_pad_right = false; +static bool circle_pad_modifier = false; + +static void UpdateCirclePad(EmuWindow& emu_window) { + constexpr float SQRT_HALF = 0.707106781f; + int x = 0, y = 0; + + if (circle_pad_right) + ++x; + if (circle_pad_left) + --x; + if (circle_pad_up) + ++y; + if (circle_pad_down) + --y; + + float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0f; + emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0f : SQRT_HALF), + y * modifier * (x == 0 ? 1.0f : SQRT_HALF)); +} + +int NewDeviceId() { + return next_device_id++; +} + +void SetKeyMapping(HostDeviceKey key, KeyTarget target) { + key_map[key] = target; +} + +void ClearKeyMapping(int device_id) { + auto iter = key_map.begin(); + while (iter != key_map.end()) { + if (iter->first.device_id == device_id) + key_map.erase(iter++); + else + ++iter; + } +} + +void PressKey(EmuWindow& emu_window, HostDeviceKey key) { + auto target = key_map.find(key); + if (target == key_map.end()) + return; + + if (target->second.direct) { + emu_window.ButtonPressed({{target->second.target.direct_target_hex}}); + } else { + switch (target->second.target.indirect_target) { + case IndirectTarget::CirclePadUp: + circle_pad_up = true; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadDown: + circle_pad_down = true; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadLeft: + circle_pad_left = true; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadRight: + circle_pad_right = true; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadModifier: + circle_pad_modifier = true; + UpdateCirclePad(emu_window); + break; + } + } +} + +void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) { + auto target = key_map.find(key); + if (target == key_map.end()) + return; + + if (target->second.direct) { + emu_window.ButtonReleased({{target->second.target.direct_target_hex}}); + } else { + switch (target->second.target.indirect_target) { + case IndirectTarget::CirclePadUp: + circle_pad_up = false; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadDown: + circle_pad_down = false; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadLeft: + circle_pad_left = false; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadRight: + circle_pad_right = false; + UpdateCirclePad(emu_window); + break; + case IndirectTarget::CirclePadModifier: + circle_pad_modifier = false; + UpdateCirclePad(emu_window); + break; + } + } +} +} diff --git a/src/core/frontend/key_map.h b/src/core/frontend/key_map.h new file mode 100644 index 000000000..040794578 --- /dev/null +++ b/src/core/frontend/key_map.h @@ -0,0 +1,93 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <tuple> +#include "core/hle/service/hid/hid.h" + +class EmuWindow; + +namespace KeyMap { + +/** + * Represents key mapping targets that are not real 3DS buttons. + * They will be handled by KeyMap and translated to 3DS input. + */ +enum class IndirectTarget { + CirclePadUp, + CirclePadDown, + CirclePadLeft, + CirclePadRight, + CirclePadModifier, +}; + +/** + * Represents a key mapping target. It can be a PadState that represents real 3DS buttons, + * or an IndirectTarget. + */ +struct KeyTarget { + bool direct; + union { + u32 direct_target_hex; + IndirectTarget indirect_target; + } target; + + KeyTarget() : direct(true) { + target.direct_target_hex = 0; + } + + KeyTarget(Service::HID::PadState pad) : direct(true) { + target.direct_target_hex = pad.hex; + } + + KeyTarget(IndirectTarget i) : direct(false) { + target.indirect_target = i; + } +}; + +/** + * Represents a key for a specific host device. + */ +struct HostDeviceKey { + int key_code; + int device_id; ///< Uniquely identifies a host device + + bool operator<(const HostDeviceKey& other) const { + return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id); + } + + bool operator==(const HostDeviceKey& other) const { + return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id); + } +}; + +extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets; + +/** + * Generates a new device id, which uniquely identifies a host device within KeyMap. + */ +int NewDeviceId(); + +/** + * Maps a device-specific key to a target (a PadState or an IndirectTarget). + */ +void SetKeyMapping(HostDeviceKey key, KeyTarget target); + +/** + * Clears all key mappings belonging to one device. + */ +void ClearKeyMapping(int device_id); + +/** + * Maps a key press action and call the corresponding function in EmuWindow + */ +void PressKey(EmuWindow& emu_window, HostDeviceKey key); + +/** + * Maps a key release action and call the corresponding function in EmuWindow + */ +void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); +} diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index aea43e92b..d88e25073 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -5,6 +5,7 @@ // Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. #include <algorithm> +#include <atomic> #include <climits> #include <csignal> #include <cstdarg> @@ -15,8 +16,8 @@ #include <fcntl.h> #ifdef _WIN32 -#include <WinSock2.h> -#include <common/x64/abi.h> +#include <winsock2.h> +// winsock2.h needs to be included first to prevent winsock.h being included by other includes #include <io.h> #include <iphlpapi.h> #include <ws2tcpip.h> @@ -34,6 +35,7 @@ #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" +#include "core/loader/loader.h" #include "core/memory.h" const int GDB_BUFFER_SIZE = 10000; @@ -130,7 +132,10 @@ static u16 gdbstub_port = 24689; static bool halt_loop = true; static bool step_loop = false; -std::atomic<bool> g_server_enabled(false); + +// If set to false, the server will never be started and no +// gdbstub-related functions will be executed. +static std::atomic<bool> server_enabled(false); #ifdef _WIN32 WSADATA InitData; @@ -181,11 +186,10 @@ static u8 NibbleToHex(u8 n) { /** * Converts input hex string characters into an array of equivalent of u8 bytes. * -* @param dest Pointer to buffer to store u8 bytes. * @param src Pointer to array of output hex string characters. * @param len Length of src array. */ -static u32 HexToInt(u8* src, u32 len) { +static u32 HexToInt(const u8* src, size_t len) { u32 output = 0; while (len-- > 0) { output = (output << 4) | HexCharToValue(src[0]); @@ -201,7 +205,7 @@ static u32 HexToInt(u8* src, u32 len) { * @param src Pointer to array of u8 bytes. * @param len Length of src array. */ -static void MemToGdbHex(u8* dest, u8* src, u32 len) { +static void MemToGdbHex(u8* dest, const u8* src, size_t len) { while (len-- > 0) { u8 tmp = *src++; *dest++ = NibbleToHex(tmp >> 4); @@ -216,7 +220,7 @@ static void MemToGdbHex(u8* dest, u8* src, u32 len) { * @param src Pointer to array of output hex string characters. * @param len Length of src array. */ -static void GdbHexToMem(u8* dest, u8* src, u32 len) { +static void GdbHexToMem(u8* dest, const u8* src, size_t len) { while (len-- > 0) { *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]); src += 2; @@ -240,7 +244,7 @@ static void IntToGdbHex(u8* dest, u32 v) { * * @param src Pointer to hex string. */ -static u32 GdbHexToInt(u8* src) { +static u32 GdbHexToInt(const u8* src) { u32 output = 0; for (int i = 0; i < 8; i += 2) { @@ -264,7 +268,7 @@ static u8 ReadByte() { } /// Calculate the checksum of the current command buffer. -static u8 CalculateChecksum(u8* buffer, u32 length) { +static u8 CalculateChecksum(const u8* buffer, size_t length) { return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>())); } @@ -446,9 +450,9 @@ static void SendSignal(u32 signal) { latest_signal = signal; - std::string buffer = Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15, - htonl(Core::g_app_core->GetPC()), 13, - htonl(Core::g_app_core->GetReg(13))); + std::string buffer = + Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15, + htonl(Core::CPU().GetPC()), 13, htonl(Core::CPU().GetReg(13))); LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str()); SendReply(buffer.c_str()); } @@ -535,15 +539,15 @@ static void ReadRegister() { } if (id <= R15_REGISTER) { - IntToGdbHex(reply, Core::g_app_core->GetReg(id)); + IntToGdbHex(reply, Core::CPU().GetReg(id)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, Core::g_app_core->GetCPSR()); + IntToGdbHex(reply, Core::CPU().GetCPSR()); } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - IntToGdbHex(reply, Core::g_app_core->GetVFPReg( + IntToGdbHex(reply, Core::CPU().GetVFPReg( id - CPSR_REGISTER - 1)); // VFP registers should start at 26, so one after CSPR_REGISTER } else if (id == FPSCR_REGISTER) { - IntToGdbHex(reply, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR + IntToGdbHex(reply, Core::CPU().GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR IntToGdbHex(reply + 8, 0); } else { return SendReply("E01"); @@ -560,29 +564,29 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= R15_REGISTER; reg++) { - IntToGdbHex(bufptr + reg * CHAR_BIT, Core::g_app_core->GetReg(reg)); + IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetReg(reg)); } bufptr += (16 * CHAR_BIT); - IntToGdbHex(bufptr, Core::g_app_core->GetCPSR()); + IntToGdbHex(bufptr, Core::CPU().GetCPSR()); bufptr += CHAR_BIT; for (int reg = 0; reg <= 31; reg++) { - IntToGdbHex(bufptr + reg * CHAR_BIT, Core::g_app_core->GetVFPReg(reg)); + IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetVFPReg(reg)); } bufptr += (32 * CHAR_BIT); - IntToGdbHex(bufptr, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR)); + IntToGdbHex(bufptr, Core::CPU().GetVFPSystemReg(VFP_FPSCR)); SendReply(reinterpret_cast<char*>(buffer)); } /// Modify data of register specified by gdb client. static void WriteRegister() { - u8* buffer_ptr = command_buffer + 3; + const u8* buffer_ptr = command_buffer + 3; u32 id = HexCharToValue(command_buffer[1]); if (command_buffer[2] != '=') { @@ -592,13 +596,13 @@ static void WriteRegister() { } if (id <= R15_REGISTER) { - Core::g_app_core->SetReg(id, GdbHexToInt(buffer_ptr)); + Core::CPU().SetReg(id, GdbHexToInt(buffer_ptr)); } else if (id == CPSR_REGISTER) { - Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr)); + Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr)); } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - Core::g_app_core->SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr)); + Core::CPU().SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr)); } else if (id == FPSCR_REGISTER) { - Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr)); + Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr)); } else { return SendReply("E01"); } @@ -608,27 +612,26 @@ static void WriteRegister() { /// Modify all registers with data received from the client. static void WriteRegisters() { - u8* buffer_ptr = command_buffer + 1; + const u8* buffer_ptr = command_buffer + 1; if (command_buffer[0] != 'G') return SendReply("E01"); for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { if (reg <= R15_REGISTER) { - Core::g_app_core->SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); + Core::CPU().SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); } else if (reg == CPSR_REGISTER) { - Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT)); + Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT)); } else if (reg == CPSR_REGISTER - 1) { // Dummy FPA register, ignore } else if (reg < CPSR_REGISTER) { // Dummy FPA registers, ignore i += 2; } else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) { - Core::g_app_core->SetVFPReg(reg - CPSR_REGISTER - 1, - GdbHexToInt(buffer_ptr + i * CHAR_BIT)); + Core::CPU().SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); i++; // Skip padding } else if (reg == FPSCR_REGISTER) { - Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); + Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); } } @@ -653,7 +656,7 @@ static void ReadMemory() { SendReply("E01"); } - u8* data = Memory::GetPointer(addr); + const u8* data = Memory::GetPointer(addr); if (!data) { return SendReply("E00"); } @@ -902,10 +905,10 @@ void SetServerPort(u16 port) { void ToggleServer(bool status) { if (status) { - g_server_enabled = status; + server_enabled = status; // Start server - if (!IsConnected() && Core::g_sys_core != nullptr) { + if (!IsConnected() && Core::System().GetInstance().IsPoweredOn()) { Init(); } } else { @@ -914,12 +917,12 @@ void ToggleServer(bool status) { Shutdown(); } - g_server_enabled = status; + server_enabled = status; } } static void Init(u16 port) { - if (!g_server_enabled) { + if (!server_enabled) { // Set the halt loop to false in case the user enabled the gdbstub mid-execution. // This way the CPU can still execute normally. halt_loop = false; @@ -998,7 +1001,7 @@ void Init() { } void Shutdown() { - if (!g_server_enabled) { + if (!server_enabled) { return; } @@ -1015,8 +1018,12 @@ void Shutdown() { LOG_INFO(Debug_GDBStub, "GDB stopped."); } +bool IsServerEnabled() { + return server_enabled; +} + bool IsConnected() { - return g_server_enabled && gdbserver_socket != -1; + return IsServerEnabled() && gdbserver_socket != -1; } bool GetCpuHaltFlag() { diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index a7483bb10..38177e32c 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -5,7 +5,7 @@ // Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. #pragma once -#include <atomic> + #include "common/common_types.h" namespace GDBStub { @@ -24,10 +24,6 @@ struct BreakpointAddress { BreakpointType type; }; -/// If set to false, the server will never be started and no gdbstub-related functions will be -/// executed. -extern std::atomic<bool> g_server_enabled; - /** * Set the port the gdbstub should use to listen for connections. * @@ -36,7 +32,7 @@ extern std::atomic<bool> g_server_enabled; void SetServerPort(u16 port); /** - * Set the g_server_enabled flag and start or stop the server if possible. + * Starts or stops the server if possible. * * @param status Set the server to enabled or disabled. */ @@ -48,6 +44,9 @@ void Init(); /// Stop gdbstub server. void Shutdown(); +/// Checks if the gdbstub server is enabled. +bool IsServerEnabled(); + /// Returns true if there is an active socket connection. bool IsConnected(); diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 4311d9897..645b2d5fe 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -101,6 +101,10 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) return result; } +bool Applet::IsRunning() const { + return is_running; +} + bool IsLibraryAppletRunning() { // Check the applets map for instances of any applet for (auto itr = applets.begin(); itr != applets.end(); ++itr) diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h index bfdcad126..ebeed9813 100644 --- a/src/core/hle/applets/applet.h +++ b/src/core/hle/applets/applet.h @@ -13,8 +13,7 @@ namespace Applets { class Applet { public: - virtual ~Applet() {} - Applet(Service::APT::AppletId id) : id(id) {} + virtual ~Applet() = default; /** * Creates an instance of the Applet subclass identified by the parameter. @@ -48,7 +47,7 @@ public: /** * Whether the applet is currently executing instead of the host application or not. */ - virtual bool IsRunning() const = 0; + bool IsRunning() const; /** * Handles an update tick for the Applet, lets it update the screen, send commands, etc. @@ -56,6 +55,8 @@ public: virtual void Update() = 0; protected: + explicit Applet(Service::APT::AppletId id) : id(id) {} + /** * Handles the Applet start event, triggered from the application. * @param parameter Parameter data to handle. @@ -65,6 +66,9 @@ protected: Service::APT::AppletId id; ///< Id of this Applet std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet + + /// Whether this applet is currently running instead of the host application or not. + bool is_running = false; }; /// Returns whether a library applet is currently running diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp index e1379ac4d..75d7fd9fc 100644 --- a/src/core/hle/applets/erreula.cpp +++ b/src/core/hle/applets/erreula.cpp @@ -47,7 +47,7 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param } ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) { - started = true; + is_running = true; // TODO(Subv): Set the expected fields in the response buffer before resending it to the // application. @@ -62,7 +62,7 @@ ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parame message.sender_id = static_cast<u32>(id); Service::APT::SendParameter(message); - started = false; + is_running = false; return RESULT_SUCCESS; } diff --git a/src/core/hle/applets/erreula.h b/src/core/hle/applets/erreula.h index a7ec7ec01..681bbea0c 100644 --- a/src/core/hle/applets/erreula.h +++ b/src/core/hle/applets/erreula.h @@ -17,18 +17,12 @@ public: ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; void Update() override; - bool IsRunning() const override { - return started; - } +private: /// This SharedMemory will be created when we receive the LibAppJustStarted message. /// It holds the framebuffer info retrieved by the application with /// GSPGPU::ImportDisplayCaptureInfo Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; - -private: - /// Whether this applet is currently running instead of the host application or not. - bool started = false; }; } // namespace Applets diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index 3455b9201..07c7f5b99 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -55,7 +55,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p } ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) { - started = true; + is_running = true; // TODO(Subv): Set the expected fields in the response buffer before resending it to the // application. @@ -78,7 +78,7 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa message.sender_id = static_cast<u32>(id); Service::APT::SendParameter(message); - started = false; + is_running = false; return RESULT_SUCCESS; } diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h index e3ab9f0cd..ec00e29d2 100644 --- a/src/core/hle/applets/mii_selector.h +++ b/src/core/hle/applets/mii_selector.h @@ -65,23 +65,18 @@ ASSERT_REG_POSITION(unk_6C, 0x6C); class MiiSelector final : public Applet { public: - MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) {} + MiiSelector(Service::APT::AppletId id) : Applet(id) {} ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; void Update() override; - bool IsRunning() const override { - return started; - } +private: /// This SharedMemory will be created when we receive the LibAppJustStarted message. /// It holds the framebuffer info retrieved by the application with /// GSPGPU::ImportDisplayCaptureInfo Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; - /// Whether this applet is currently running instead of the host application or not. - bool started; - MiiConfig config; }; } diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index 1e21337f5..059297fbc 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -70,7 +70,7 @@ ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter cons DrawScreenKeyboard(); - started = true; + is_running = true; return RESULT_SUCCESS; } @@ -94,13 +94,13 @@ void SoftwareKeyboard::Update() { } void SoftwareKeyboard::DrawScreenKeyboard() { - auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1); + auto bottom_screen = Service::GSP::GetFrameBufferInfo(0, 1); auto info = bottom_screen->framebuffer_info[bottom_screen->index]; // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer Memory::ZeroBlock(info.address_left, info.stride * 320); - GSP_GPU::SetBufferSwap(1, info); + Service::GSP::SetBufferSwap(1, info); } void SoftwareKeyboard::Finalize() { @@ -113,7 +113,7 @@ void SoftwareKeyboard::Finalize() { message.sender_id = static_cast<u32>(id); Service::APT::SendParameter(message); - started = false; + is_running = false; } } } // namespace diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h index ea0b1fba9..cc92a8f19 100644 --- a/src/core/hle/applets/swkbd.h +++ b/src/core/hle/applets/swkbd.h @@ -52,14 +52,11 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config class SoftwareKeyboard final : public Applet { public: - SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {} + SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {} ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; void Update() override; - bool IsRunning() const override { - return started; - } /** * Draws a keyboard to the current bottom screen framebuffer. @@ -72,6 +69,7 @@ public: */ void Finalize(); +private: /// This SharedMemory will be created when we receive the LibAppJustStarted message. /// It holds the framebuffer info retrieved by the application with /// GSPGPU::ImportDisplayCaptureInfo @@ -82,9 +80,6 @@ public: /// Configuration of this instance of the SoftwareKeyboard, as received from the application SoftwareKeyboardConfig config; - - /// Whether this applet is currently running instead of the host application or not. - bool started; }; } } // namespace diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 8ce0f6d2b..7875971ce 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -7,14 +7,14 @@ #include "common/common_types.h" #include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/hle/hle.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/result.h" #include "core/hle/svc.h" #include "core/memory.h" namespace HLE { -#define PARAM(n) Core::g_app_core->GetReg(n) +#define PARAM(n) Core::CPU().GetReg(n) /// An invalid result code that is meant to be overwritten when a thread resumes from waiting static const ResultCode RESULT_INVALID(0xDEADC0DE); @@ -24,7 +24,7 @@ static const ResultCode RESULT_INVALID(0xDEADC0DE); * @param res Result to return */ static inline void FuncReturn(u32 res) { - Core::g_app_core->SetReg(0, res); + Core::CPU().SetReg(0, res); } /** @@ -33,8 +33,8 @@ static inline void FuncReturn(u32 res) { * @todo Verify that this function is correct */ static inline void FuncReturn64(u64 res) { - Core::g_app_core->SetReg(0, (u32)(res & 0xFFFFFFFF)); - Core::g_app_core->SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF)); + Core::CPU().SetReg(0, (u32)(res & 0xFFFFFFFF)); + Core::CPU().SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF)); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -49,7 +49,7 @@ template <ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -57,19 +57,19 @@ template <ResultCode func(u32*, s32, u32, u32, u32, s32)> void Wrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } template <ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() { s32 param_1 = 0; - s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), + s32 retval = func(¶m_1, (Kernel::Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))) .raw; if (retval != RESULT_INVALID.raw) { - Core::g_app_core->SetReg(1, (u32)param_1); + Core::CPU().SetReg(1, (u32)param_1); FuncReturn(retval); } } @@ -84,7 +84,7 @@ template <ResultCode func(u32*)> void Wrap() { u32 param_1 = 0; u32 retval = func(¶m_1).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -102,24 +102,24 @@ void Wrap() { MemoryInfo memory_info = {}; PageInfo page_info = {}; u32 retval = func(&memory_info, &page_info, PARAM(2)).raw; - Core::g_app_core->SetReg(1, memory_info.base_address); - Core::g_app_core->SetReg(2, memory_info.size); - Core::g_app_core->SetReg(3, memory_info.permission); - Core::g_app_core->SetReg(4, memory_info.state); - Core::g_app_core->SetReg(5, page_info.flags); + Core::CPU().SetReg(1, memory_info.base_address); + Core::CPU().SetReg(2, memory_info.size); + Core::CPU().SetReg(3, memory_info.permission); + Core::CPU().SetReg(4, memory_info.state); + Core::CPU().SetReg(5, page_info.flags); FuncReturn(retval); } -template <ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> +template <ResultCode func(MemoryInfo*, PageInfo*, Kernel::Handle, u32)> void Wrap() { MemoryInfo memory_info = {}; PageInfo page_info = {}; u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw; - Core::g_app_core->SetReg(1, memory_info.base_address); - Core::g_app_core->SetReg(2, memory_info.size); - Core::g_app_core->SetReg(3, memory_info.permission); - Core::g_app_core->SetReg(4, memory_info.state); - Core::g_app_core->SetReg(5, page_info.flags); + Core::CPU().SetReg(1, memory_info.base_address); + Core::CPU().SetReg(2, memory_info.size); + Core::CPU().SetReg(3, memory_info.permission); + Core::CPU().SetReg(4, memory_info.state); + Core::CPU().SetReg(5, page_info.flags); FuncReturn(retval); } @@ -127,7 +127,7 @@ template <ResultCode func(s32*, u32)> void Wrap() { s32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1)).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -140,7 +140,7 @@ template <ResultCode func(u32*, u32)> void Wrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1)).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -160,7 +160,7 @@ template <ResultCode func(u32*, const char*)> void Wrap() { u32 param_1 = 0; u32 retval = func(¶m_1, (char*)Memory::GetPointer(PARAM(1))).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -168,7 +168,7 @@ template <ResultCode func(u32*, s32, s32)> void Wrap() { u32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -176,7 +176,7 @@ template <ResultCode func(s32*, u32, s32)> void Wrap() { s32 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -184,8 +184,8 @@ template <ResultCode func(s64*, u32, s32)> void Wrap() { s64 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; - Core::g_app_core->SetReg(1, (u32)param_1); - Core::g_app_core->SetReg(2, (u32)(param_1 >> 32)); + Core::CPU().SetReg(1, (u32)param_1); + Core::CPU().SetReg(2, (u32)(param_1 >> 32)); FuncReturn(retval); } @@ -194,7 +194,7 @@ void Wrap() { u32 param_1 = 0; // The last parameter is passed in R0 instead of R4 u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw; - Core::g_app_core->SetReg(1, param_1); + Core::CPU().SetReg(1, param_1); FuncReturn(retval); } @@ -205,30 +205,30 @@ void Wrap() { FuncReturn(func(PARAM(0), param1, param2).raw); } -template <ResultCode func(s64*, Handle, u32)> +template <ResultCode func(s64*, Kernel::Handle, u32)> void Wrap() { s64 param_1 = 0; u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; - Core::g_app_core->SetReg(1, (u32)param_1); - Core::g_app_core->SetReg(2, (u32)(param_1 >> 32)); + Core::CPU().SetReg(1, (u32)param_1); + Core::CPU().SetReg(2, (u32)(param_1 >> 32)); FuncReturn(retval); } -template <ResultCode func(Handle, u32)> +template <ResultCode func(Kernel::Handle, u32)> void Wrap() { FuncReturn(func(PARAM(0), PARAM(1)).raw); } -template <ResultCode func(Handle*, Handle*, const char*, u32)> +template <ResultCode func(Kernel::Handle*, Kernel::Handle*, const char*, u32)> void Wrap() { - Handle param_1 = 0; - Handle param_2 = 0; + Kernel::Handle param_1 = 0; + Kernel::Handle param_2 = 0; u32 retval = func(¶m_1, ¶m_2, reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3)) .raw; // The first out parameter is moved into R2 and the second is moved into R1. - Core::g_app_core->SetReg(1, param_2); - Core::g_app_core->SetReg(2, param_1); + Core::CPU().SetReg(1, param_2); + Core::CPU().SetReg(2, param_1); FuncReturn(retval); } diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp deleted file mode 100644 index 41b772163..000000000 --- a/src/core/hle/hle.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/arm/arm_interface.h" -#include "core/core.h" -#include "core/hle/hle.h" -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace { - -bool reschedule; ///< If true, immediately reschedules the CPU to a new thread -} - -namespace HLE { - -void Reschedule(const char* reason) { - DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256, - "Reschedule: Invalid or too long reason."); - - // TODO(bunnei): It seems that games depend on some CPU execution time elapsing during HLE - // routines. This simulates that time by artificially advancing the number of CPU "ticks". - // The value was chosen empirically, it seems to work well enough for everything tested, but - // is likely not ideal. We should find a more accurate way to simulate timing with HLE. - Core::g_app_core->AddTicks(4000); - - Core::g_app_core->PrepareReschedule(); - - reschedule = true; -} - -bool IsReschedulePending() { - return reschedule; -} - -void DoneRescheduling() { - reschedule = false; -} - -void Init() { - Service::Init(); - - reschedule = false; - - LOG_DEBUG(Kernel, "initialized OK"); -} - -void Shutdown() { - Service::Shutdown(); - - LOG_DEBUG(Kernel, "shutdown OK"); -} - -} // namespace diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h deleted file mode 100644 index 23859e129..000000000 --- a/src/core/hle/hle.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -typedef u32 Handle; -typedef s32 Result; - -const Handle INVALID_HANDLE = 0; - -namespace HLE { - -void Reschedule(const char* reason); -bool IsReschedulePending(); -void DoneRescheduling(); - -void Init(); -void Shutdown(); - -} // namespace diff --git a/src/core/hle/kernel/session.h b/src/core/hle/ipc.h index ec025f732..4e094faa7 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/ipc.h @@ -1,17 +1,31 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2016 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once -#include <string> -#include "common/assert.h" #include "common/common_types.h" -#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -#include "core/hle/result.h" #include "core/memory.h" +namespace Kernel { + +static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header + +/** + * Returns a pointer to the command buffer in the current thread's TLS + * TODO(Subv): This is not entirely correct, the command buffer should be copied from + * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to + * the service handler process' memory. + * @param offset Optional offset into command buffer + * @return Pointer to command buffer + */ +inline u32* GetCommandBuffer(const int offset = 0) { + return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + + offset); +} +} + namespace IPC { enum DescriptorType : u32 { @@ -144,75 +158,3 @@ inline DescriptorType GetDescriptorType(u32 descriptor) { } } // namespace IPC - -namespace Kernel { - -static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header - -/** - * Returns a pointer to the command buffer in the current thread's TLS - * TODO(Subv): This is not entirely correct, the command buffer should be copied from - * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to - * the service handler process' memory. - * @param offset Optional offset into command buffer - * @return Pointer to command buffer - */ -inline u32* GetCommandBuffer(const int offset = 0) { - return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + - offset); -} - -/** - * Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS - * primitive for communication between different processes, and are used to implement service calls - * to the various system services. - * - * To make a service call, the client must write the command header and parameters to the buffer - * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest - * SVC call with its Session handle. The kernel will read the command header, using it to marshall - * the parameters to the process at the server endpoint of the session. After the server replies to - * the request, the response is marshalled back to the caller's TLS buffer and control is - * transferred back to it. - * - * In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC - * request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called - * with the session handle, this class's SyncRequest method is called, which should read the TLS - * buffer and emulate the call accordingly. Since the code can directly read the emulated memory, - * no parameter marshalling is done. - * - * In the long term, this should be turned into the full-fledged IPC mechanism implemented by - * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as - * opposed to HLE simulations. - */ -class Session : public WaitObject { -public: - Session(); - ~Session() override; - - std::string GetTypeName() const override { - return "Session"; - } - - static const HandleType HANDLE_TYPE = HandleType::Session; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - /** - * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls - * aren't supported yet. - */ - virtual ResultVal<bool> SyncRequest() = 0; - - // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object - // passed into WaitSynchronization. Figure out the meaning of them. - - bool ShouldWait() override { - return true; - } - - void Acquire() override { - ASSERT_MSG(!ShouldWait(), "object unavailable!"); - } -}; -} diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 37eec4c84..01fab123e 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -4,7 +4,6 @@ #include "common/common_types.h" #include "common/logging/log.h" -#include "core/hle/hle.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/thread.h" #include "core/memory.h" @@ -79,8 +78,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, ErrorSummary::WrongArgument, ErrorLevel::Usage); } - HLE::Reschedule(__func__); - // The calls that use a timeout seem to always return a Timeout error even if they did not put // the thread to sleep if (type == ArbitrationType::WaitIfLessThanWithTimeout || diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index aedc6f989..22645f4ec 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -4,12 +4,44 @@ #include "common/assert.h" #include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} +ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { + // Note: Threads do not wait for the server endpoint to call + // AcceptSession before returning from this call. + + if (active_sessions >= max_sessions) { + // TODO(Subv): Return an error code in this situation after session disconnection is + // implemented. + /*return ResultCode(ErrorDescription::MaxConnectionsReached, + ErrorModule::OS, ErrorSummary::WouldBlock, + ErrorLevel::Temporary);*/ + } + active_sessions++; + + // Create a new session pair, let the created sessions inherit the parent port's HLE handler. + auto sessions = + ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); + auto client_session = std::get<SharedPtr<ClientSession>>(sessions); + auto server_session = std::get<SharedPtr<ServerSession>>(sessions); + + if (server_port->hle_handler) + server_port->hle_handler->ClientConnected(server_session); + + server_port->pending_sessions.push_back(std::move(server_session)); + + // Wake the threads waiting on the ServerPort + server_port->WakeupAllWaitingThreads(); + + return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); +} + } // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index d28147718..511490c7c 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -11,8 +11,9 @@ namespace Kernel { class ServerPort; +class ClientSession; -class ClientPort : public Object { +class ClientPort final : public Object { public: friend class ServerPort; std::string GetTypeName() const override { @@ -27,12 +28,20 @@ public: return HANDLE_TYPE; } + /** + * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's + * list of pending sessions, and signals the ServerPort, causing any threads + * waiting on it to awake. + * @returns ClientSession The client endpoint of the created Session pair, or error code. + */ + ResultVal<SharedPtr<ClientSession>> Connect(); + SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions; ///< Number of currently open sessions to this port std::string name; ///< Name of client port (optional) -protected: +private: ClientPort(); ~ClientPort() override; }; diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp new file mode 100644 index 000000000..0331386ec --- /dev/null +++ b/src/core/hle/kernel/client_session.cpp @@ -0,0 +1,40 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" + +namespace Kernel { + +ClientSession::ClientSession() = default; +ClientSession::~ClientSession() { + // This destructor will be called automatically when the last ClientSession handle is closed by + // the emulated application. + + if (server_session->hle_handler) + server_session->hle_handler->ClientDisconnected(server_session); + + // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client), + // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to + // 0xC920181A. +} + +ResultVal<SharedPtr<ClientSession>> ClientSession::Create(ServerSession* server_session, + std::string name) { + SharedPtr<ClientSession> client_session(new ClientSession); + + client_session->name = std::move(name); + client_session->server_session = server_session; + client_session->session_status = SessionStatus::Open; + return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); +} + +ResultCode ClientSession::SendSyncRequest() { + // Signal the server session that new data is available + return server_session->HandleSyncRequest(); +} + +} // namespace diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h new file mode 100644 index 000000000..ed468dec6 --- /dev/null +++ b/src/core/hle/kernel/client_session.h @@ -0,0 +1,65 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ServerSession; + +enum class SessionStatus { + Open = 1, + ClosedByClient = 2, + ClosedBYServer = 3, +}; + +class ClientSession final : public Object { +public: + friend class ServerSession; + + std::string GetTypeName() const override { + return "ClientSession"; + } + + std::string GetName() const override { + return name; + } + + static const HandleType HANDLE_TYPE = HandleType::ClientSession; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + /** + * Sends an SyncRequest from the current emulated thread. + * @return ResultCode of the operation. + */ + ResultCode SendSyncRequest(); + + std::string name; ///< Name of client port (optional) + ServerSession* server_session; ///< The server session associated with this client session. + SessionStatus session_status; ///< The session's current status. + +private: + ClientSession(); + ~ClientSession() override; + + /** + * Creates a client session. + * @param server_session The server session associated with this client session + * @param name Optional name of client session + * @return The created client session + */ + static ResultVal<SharedPtr<ClientSession>> Create(ServerSession* server_session, + std::string name = "Unknown"); +}; + +} // namespace diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0c8752670..1db8e102f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <algorithm> +#include <boost/range/algorithm_ext/erase.hpp> #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/config_mem.h" @@ -31,13 +32,61 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -void WaitObject::WakeupAllWaitingThreads() { - for (auto thread : waiting_threads) - thread->ResumeFromWait(); +SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { + // Remove the threads that are ready or already running from our waitlist + boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& thread) { + return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY || + thread->status == THREADSTATUS_DEAD; + }); + + // TODO(Subv): This call should be performed inside the loop below to check if an object can be + // acquired by a particular thread. This is useful for things like recursive locking of Mutexes. + if (ShouldWait()) + return nullptr; + + Thread* candidate = nullptr; + s32 candidate_priority = THREADPRIO_LOWEST + 1; + + for (const auto& thread : waiting_threads) { + if (thread->current_priority >= candidate_priority) + continue; - waiting_threads.clear(); + bool ready_to_run = + std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), + [](const SharedPtr<WaitObject>& object) { return object->ShouldWait(); }); + if (ready_to_run) { + candidate = thread.get(); + candidate_priority = thread->current_priority; + } + } + + return candidate; +} - HLE::Reschedule(__func__); +void WaitObject::WakeupAllWaitingThreads() { + while (auto thread = GetHighestPriorityReadyThread()) { + if (!thread->IsSleepingOnWaitAll()) { + Acquire(); + // Set the output index of the WaitSynchronizationN call to the index of this object. + if (thread->wait_set_output) { + thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); + thread->wait_set_output = false; + } + } else { + for (auto& object : thread->wait_objects) { + object->Acquire(); + object->RemoveWaitingThread(thread.get()); + } + // Note: This case doesn't update the output index of WaitSynchronizationN. + // Clear the thread's waitlist + thread->wait_objects.clear(); + } + + thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + thread->ResumeFromWait(); + // Note: Removing the thread from the object's waitlist will be + // done by GetHighestPriorityReadyThread. + } } const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 231cf7b75..9503e7d04 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,11 +11,12 @@ #include <vector> #include <boost/smart_ptr/intrusive_ptr.hpp> #include "common/common_types.h" -#include "core/hle/hle.h" #include "core/hle/result.h" namespace Kernel { +using Handle = u32; + class Thread; // TODO: Verify code @@ -31,22 +32,21 @@ enum KernelHandle : Handle { }; enum class HandleType : u32 { - Unknown = 0, - - Session = 2, - Event = 3, - Mutex = 4, - SharedMemory = 5, - Redirection = 6, - Thread = 7, - Process = 8, - AddressArbiter = 9, - Semaphore = 10, - Timer = 11, - ResourceLimit = 12, - CodeSet = 13, - ClientPort = 14, - ServerPort = 15, + Unknown, + Event, + Mutex, + SharedMemory, + Thread, + Process, + AddressArbiter, + Semaphore, + Timer, + ResourceLimit, + CodeSet, + ClientPort, + ServerPort, + ClientSession, + ServerSession, }; enum { @@ -82,23 +82,23 @@ public: */ bool IsWaitable() const { switch (GetHandleType()) { - case HandleType::Session: - case HandleType::ServerPort: case HandleType::Event: case HandleType::Mutex: case HandleType::Thread: case HandleType::Semaphore: case HandleType::Timer: + case HandleType::ServerPort: + case HandleType::ServerSession: return true; case HandleType::Unknown: case HandleType::SharedMemory: - case HandleType::Redirection: case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: case HandleType::CodeSet: case HandleType::ClientPort: + case HandleType::ClientSession: return false; } } @@ -152,9 +152,15 @@ public: */ void RemoveWaitingThread(Thread* thread); - /// Wake up all threads waiting on this object + /** + * Wake up all threads waiting on this object that can be awoken, in priority order, + * and set the synchronization result and output of the thread. + */ void WakeupAllWaitingThreads(); + /// Obtains the highest priority thread that is ready to run from this object's waiting list. + SharedPtr<Thread> GetHighestPriorityReadyThread(); + /// Get a const reference to the waiting threads list for debug use const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 8e3ec8a14..6c19aa7c0 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -24,12 +24,14 @@ void ServerPort::Acquire() { } std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( - u32 max_sessions, std::string name) { + u32 max_sessions, std::string name, + std::shared_ptr<Service::SessionRequestHandler> hle_handler) { SharedPtr<ServerPort> server_port(new ServerPort); SharedPtr<ClientPort> client_port(new ClientPort); server_port->name = name + "_Server"; + server_port->hle_handler = std::move(hle_handler); client_port->name = name + "_Client"; client_port->server_port = server_port; client_port->max_sessions = max_sessions; diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index fa9448ca0..b0f8df62c 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -4,11 +4,16 @@ #pragma once +#include <memory> #include <string> #include <tuple> #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +namespace Service { +class SessionRequestHandler; +} + namespace Kernel { class ClientPort; @@ -19,10 +24,13 @@ public: * Creates a pair of ServerPort and an associated ClientPort. * @param max_sessions Maximum number of sessions to the port * @param name Optional name of the ports + * @param hle_handler Optional HLE handler template for the port, + * ServerSessions crated from this port will inherit a reference to this handler. * @return The created port tuple */ static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( - u32 max_sessions, std::string name = "UnknownPort"); + u32 max_sessions, std::string name = "UnknownPort", + std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); std::string GetTypeName() const override { return "ServerPort"; @@ -41,6 +49,10 @@ public: std::vector<SharedPtr<WaitObject>> pending_sessions; ///< ServerSessions waiting to be accepted by the port + /// This session's HLE request handler template (optional) + /// ServerSessions created from this port inherit a reference to this handler. + std::shared_ptr<Service::SessionRequestHandler> hle_handler; + bool ShouldWait() override; void Acquire() override; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp new file mode 100644 index 000000000..146458c1c --- /dev/null +++ b/src/core/hle/kernel/server_session.cpp @@ -0,0 +1,79 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <tuple> + +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +ServerSession::ServerSession() = default; +ServerSession::~ServerSession() { + // This destructor will be called automatically when the last ServerSession handle is closed by + // the emulated application. + // TODO(Subv): Reduce the ClientPort's connection count, + // if the session is still open, set the connection status to 3 (Closed by server), +} + +ResultVal<SharedPtr<ServerSession>> ServerSession::Create( + std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) { + SharedPtr<ServerSession> server_session(new ServerSession); + + server_session->name = std::move(name); + server_session->signaled = false; + server_session->hle_handler = std::move(hle_handler); + + return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); +} + +bool ServerSession::ShouldWait() { + return !signaled; +} + +void ServerSession::Acquire() { + ASSERT_MSG(!ShouldWait(), "object unavailable!"); + signaled = false; +} + +ResultCode ServerSession::HandleSyncRequest() { + // The ServerSession received a sync request, this means that there's new data available + // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or + // similar. + + // If this ServerSession has an associated HLE handler, forward the request to it. + if (hle_handler != nullptr) { + // Attempt to translate the incoming request's command buffer. + ResultCode result = TranslateHLERequest(this); + if (result.IsError()) + return result; + hle_handler->HandleSyncRequest(SharedPtr<ServerSession>(this)); + // TODO(Subv): Translate the response command buffer. + } + + // If this ServerSession does not have an HLE implementation, just wake up the threads waiting + // on it. + signaled = true; + WakeupAllWaitingThreads(); + return RESULT_SUCCESS; +} + +ServerSession::SessionPair ServerSession::CreateSessionPair( + const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) { + auto server_session = + ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); + // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want + // to prevent the ServerSession's destructor from being called when the emulated + // application closes the last ServerSession handle. + auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom(); + + return std::make_tuple(std::move(server_session), std::move(client_session)); +} + +ResultCode TranslateHLERequest(ServerSession* server_session) { + // TODO(Subv): Implement this function once multiple concurrent processes are supported. + return RESULT_SUCCESS; +} +} diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h new file mode 100644 index 000000000..458284a5d --- /dev/null +++ b/src/core/hle/kernel/server_session.h @@ -0,0 +1,94 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include "common/assert.h" +#include "common/common_types.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/thread.h" +#include "core/hle/result.h" +#include "core/hle/service/service.h" +#include "core/memory.h" + +namespace Kernel { + +class ClientSession; + +/** + * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS + * primitive for communication between different processes, and are used to implement service calls + * to the various system services. + * + * To make a service call, the client must write the command header and parameters to the buffer + * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest + * SVC call with its ClientSession handle. The kernel will read the command header, using it to + * marshall the parameters to the process at the server endpoint of the session. + * After the server replies to the request, the response is marshalled back to the caller's + * TLS buffer and control is transferred back to it. + */ +class ServerSession final : public WaitObject { +public: + std::string GetTypeName() const override { + return "ServerSession"; + } + + static const HandleType HANDLE_TYPE = HandleType::ServerSession; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>; + + /** + * Creates a pair of ServerSession and an associated ClientSession. + * @param name Optional name of the ports + * @return The created session tuple + */ + static SessionPair CreateSessionPair( + const std::string& name = "Unknown", + std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); + + /** + * Handle a sync request from the emulated application. + * @returns ResultCode from the operation. + */ + ResultCode HandleSyncRequest(); + + bool ShouldWait() override; + + void Acquire() override; + + std::string name; ///< The name of this session (optional) + bool signaled; ///< Whether there's new data available to this ServerSession + std::shared_ptr<Service::SessionRequestHandler> + hle_handler; ///< This session's HLE request handler (optional) + +private: + ServerSession(); + ~ServerSession() override; + + /** + * Creates a server session. The server session can have an optional HLE handler, + * which will be invoked to handle the IPC requests that this session receives. + * @param name Optional name of the server session. + * @param hle_handler Optional HLE handler for this server session. + * @return The created server session + */ + static ResultVal<SharedPtr<ServerSession>> Create( + std::string name = "Unknown", + std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); +}; + +/** + * Performs command buffer translation for an HLE IPC request. + * The command buffer from the ServerSession thread's TLS is copied into a + * buffer and all descriptors in the buffer are processed. + * TODO(Subv): Implement this function, currently we do not support multiple processes running at + * once, but once that is implemented we'll need to properly translate all descriptors + * in the command buffer. + */ +ResultCode TranslateHLERequest(ServerSession* server_session); +} diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 84d6d24c6..5fb95dada 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -14,7 +14,6 @@ #include "core/arm/skyeye_common/armstate.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hle/hle.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/mutex.h" @@ -46,7 +45,7 @@ static std::vector<SharedPtr<Thread>> thread_list; // Lists only ready thread ids. static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue; -static Thread* current_thread; +static SharedPtr<Thread> current_thread; // The first available thread id at startup static u32 next_thread_id; @@ -63,7 +62,7 @@ Thread::Thread() {} Thread::~Thread() {} Thread* GetCurrentThread() { - return current_thread; + return current_thread.get(); } /** @@ -120,8 +119,6 @@ void Thread::Stop() { u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); - - HLE::Reschedule(__func__); } Thread* ArbitrateHighestPriorityThread(u32 address) { @@ -181,50 +178,6 @@ static void PriorityBoostStarvedThreads() { } /** - * Gets the registers for timeout parameter of the next WaitSynchronization call. - * @param thread a pointer to the thread that is ready to call WaitSynchronization - * @returns a tuple of two register pointers to low and high part of the timeout parameter - */ -static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* thread) { - bool thumb_mode = (thread->context.cpsr & TBIT) != 0; - u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE); - u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF; - - if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { - // svc #0x24 (WaitSynchronization1) - return std::make_tuple(&thread->context.cpu_registers[2], - &thread->context.cpu_registers[3]); - } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { - // svc #0x25 (WaitSynchronizationN) - return std::make_tuple(&thread->context.cpu_registers[0], - &thread->context.cpu_registers[4]); - } - - UNREACHABLE(); -} - -/** - * Updates the WaitSynchronization timeout parameter according to the difference - * between ticks of the last WaitSynchronization call and the incoming one. - * @param timeout_low a pointer to the register for the low part of the timeout parameter - * @param timeout_high a pointer to the register for the high part of the timeout parameter - * @param last_tick tick of the last WaitSynchronization call - */ -static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) { - s64 timeout = ((s64)*timeout_high << 32) | *timeout_low; - - if (timeout != -1) { - timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds - - if (timeout < 0) - timeout = 0; - - *timeout_low = timeout & 0xFFFFFFFF; - *timeout_high = timeout >> 32; - } -} - -/** * Switches the CPU's active thread context to that of the specified thread * @param new_thread The thread to switch to */ @@ -234,7 +187,7 @@ static void SwitchContext(Thread* new_thread) { // Save context for previous thread if (previous_thread) { previous_thread->last_running_ticks = CoreTiming::GetTicks(); - Core::g_app_core->SaveContext(previous_thread->context); + Core::CPU().SaveContext(previous_thread->context); if (previous_thread->status == THREADSTATUS_RUNNING) { // This is only the case when a reschedule is triggered without the current thread @@ -254,40 +207,14 @@ static void SwitchContext(Thread* new_thread) { current_thread = new_thread; - // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun - // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire - // the requested wait object(s) before continuing. - if (new_thread->waitsynch_waited) { - // CPSR flag indicates CPU mode - bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0; - - // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM - new_thread->context.pc -= thumb_mode ? 2 : 4; - - // Get the register for timeout parameter - u32 *timeout_low, *timeout_high; - std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); - - // Update the timeout parameter - UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks); - } - - // Clean up the thread's wait_objects, they'll be restored if needed during - // the svcWaitSynchronization call - for (size_t i = 0; i < new_thread->wait_objects.size(); ++i) { - SharedPtr<WaitObject> object = new_thread->wait_objects[i]; - object->RemoveWaitingThread(new_thread); - } - new_thread->wait_objects.clear(); - ready_queue.remove(new_thread->current_priority, new_thread); new_thread->status = THREADSTATUS_RUNNING; // Restores thread to its nominal priority if it has been temporarily changed new_thread->current_priority = new_thread->nominal_priority; - Core::g_app_core->LoadContext(new_thread->context); - Core::g_app_core->SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress()); + Core::CPU().LoadContext(new_thread->context); + Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress()); } else { current_thread = nullptr; } @@ -319,17 +246,13 @@ static Thread* PopNextReadyThread() { void WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); thread->status = THREADSTATUS_WAIT_SLEEP; - - HLE::Reschedule(__func__); } void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, - bool wait_set_output, bool wait_all) { + bool wait_set_output) { Thread* thread = GetCurrentThread(); thread->wait_set_output = wait_set_output; - thread->wait_all = wait_all; thread->wait_objects = std::move(wait_objects); - thread->waitsynch_waited = true; thread->status = THREADSTATUS_WAIT_SYNCH; } @@ -339,6 +262,13 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { thread->status = THREADSTATUS_WAIT_ARB; } +void ExitCurrentThread() { + Thread* thread = GetCurrentThread(); + thread->Stop(); + thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), + thread_list.end()); +} + /** * Callback that will wake up the thread it was scheduled for * @param thread_handle The handle of the thread that's been awoken @@ -351,15 +281,15 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { return; } - thread->waitsynch_waited = false; - if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { + thread->wait_set_output = false; + // Remove the thread from each of its waiting objects' waitlists + for (auto& object : thread->wait_objects) + object->RemoveWaitingThread(thread.get()); + thread->wait_objects.clear(); thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged, ErrorLevel::Info)); - - if (thread->wait_set_output) - thread->SetWaitSynchronizationOutput(-1); } thread->ResumeFromWait(); @@ -399,6 +329,7 @@ void Thread::ResumeFromWait() { ready_queue.push_back(current_priority, this); status = THREADSTATUS_READY; + Core::System::GetInstance().PrepareReschedule(); } /** @@ -453,9 +384,9 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t * @param entry_point Address of entry point for execution * @param arg User argument for thread */ -static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, - u32 arg) { - memset(&context, 0, sizeof(Core::ThreadContext)); +static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_top, + u32 entry_point, u32 arg) { + memset(&context, 0, sizeof(ARM_Interface::ThreadContext)); context.cpu_registers[0] = arg; context.pc = entry_point; @@ -494,13 +425,11 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->last_running_ticks = CoreTiming::GetTicks(); thread->processor_id = processor_id; thread->wait_set_output = false; - thread->wait_all = false; thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); thread->owner_process = g_current_process; - thread->waitsynch_waited = false; // Find the next available TLS index, and mark it as used auto& tls_slots = Kernel::g_current_process->tls_slots; @@ -555,8 +484,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, ready_queue.push_back(thread->current_priority, thread.get()); thread->status = THREADSTATUS_READY; - HLE::Reschedule(__func__); - return MakeResult<SharedPtr<Thread>>(std::move(thread)); } @@ -617,16 +544,6 @@ void Reschedule() { Thread* cur = GetCurrentThread(); Thread* next = PopNextReadyThread(); - HLE::DoneRescheduling(); - - // Don't bother switching to the same thread. - // But if the thread was waiting on objects, we still need to switch it - // to perform PC modification, change state to RUNNING, etc. - // This occurs in the case when an object the thread is waiting on immediately wakes up - // the current thread before Reschedule() is called. - if (next == cur && (next == nullptr || next->waitsynch_waited == false)) - return; - if (cur && next) { LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); } else if (cur) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e0ffcea8a..c77ac644d 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -5,11 +5,13 @@ #pragma once #include <string> +#include <unordered_map> #include <vector> +#include <boost/container/flat_map.hpp> #include <boost/container/flat_set.hpp> #include "common/common_types.h" +#include "core/arm/arm_interface.h" #include "core/core.h" -#include "core/hle/hle.h" #include "core/hle/kernel/kernel.h" #include "core/hle/result.h" @@ -125,6 +127,16 @@ public: void SetWaitSynchronizationOutput(s32 output); /** + * Retrieves the index that this particular object occupies in the list of objects + * that the thread passed to WaitSynchronizationN. + * It is used to set the output value of WaitSynchronizationN when the thread is awakened. + * @param object Object to query the index of. + */ + s32 GetWaitObjectIndex(const WaitObject* object) const { + return wait_objects_index.at(object->GetObjectId()); + } + + /** * Stops a thread, invalidating it from further use */ void Stop(); @@ -137,7 +149,16 @@ public: return tls_address; } - Core::ThreadContext context; + /** + * Returns whether this thread is waiting for all the objects in + * its wait list to become ready, as a result of a WaitSynchronizationN call + * with wait_all = true, or a ReplyAndReceive call. + */ + bool IsSleepingOnWaitAll() const { + return !wait_objects.empty(); + } + + ARM_Interface::ThreadContext context; u32 thread_id; @@ -154,16 +175,22 @@ public: VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread - bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait - /// Mutexes currently held by this thread, which will be released when it exits. boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; - SharedPtr<Process> owner_process; ///< Process that owns this thread - std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on - VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address - bool wait_all; ///< True if the thread is waiting on all objects before resuming - bool wait_set_output; ///< True if the output parameter should be set on thread wakeup + SharedPtr<Process> owner_process; ///< Process that owns this thread + + /// Objects that the thread is waiting on. + /// This is only populated when the thread should wait for all the objects to become ready. + std::vector<SharedPtr<WaitObject>> wait_objects; + + /// Mapping of Object ids to their position in the last waitlist that this object waited on. + boost::container::flat_map<int, s32> wait_objects_index; + + VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address + + /// True if the WaitSynchronizationN output parameter should be set on thread wakeup. + bool wait_set_output; std::string name; @@ -215,10 +242,9 @@ void WaitCurrentThread_Sleep(); * @param wait_objects Kernel objects that we are waiting on * @param wait_set_output If true, set the output parameter on thread wakeup (for * WaitSynchronizationN only) - * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) */ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, - bool wait_set_output, bool wait_all); + bool wait_set_output); /** * Waits the current thread from an ArbitrateAddress call @@ -227,6 +253,11 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); /** + * Stops the current thread and removes it from the thread_list + */ +void ExitCurrentThread(); + +/** * Initialize threading */ void ThreadingInit(); diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index eac181f4e..b50cf520d 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -60,14 +60,10 @@ void Timer::Set(s64 initial, s64 interval) { u64 initial_microseconds = initial / 1000; CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, callback_handle); - - HLE::Reschedule(__func__); } void Timer::Cancel() { CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); - - HLE::Reschedule(__func__); } void Timer::Clear() { diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 8d29117a8..53864a3a7 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -18,6 +18,7 @@ enum class ErrorDescription : u32 { Success = 0, WrongPermission = 46, OS_InvalidBufferDescriptor = 48, + MaxConnectionsReached = 52, WrongAddress = 53, FS_ArchiveNotMounted = 101, FS_FileNotFound = 112, diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp index fe367aca5..36204db4d 100644 --- a/src/core/hle/service/ac_u.cpp +++ b/src/core/hle/service/ac_u.cpp @@ -2,14 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> + #include "common/logging/log.h" #include "core/hle/kernel/event.h" #include "core/hle/service/ac_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AC_U - -namespace AC_U { +namespace Service { +namespace AC { struct ACConfig { std::array<u8, 0x200> data; @@ -31,7 +31,7 @@ static Kernel::SharedPtr<Kernel::Event> disconnect_event; * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void CreateDefaultConfig(Service::Interface* self) { +static void CreateDefaultConfig(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 ac_config_addr = cmd_buff[65]; @@ -56,7 +56,7 @@ static void CreateDefaultConfig(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void ConnectAsync(Service::Interface* self) { +static void ConnectAsync(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); connect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); @@ -77,7 +77,7 @@ static void ConnectAsync(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void GetConnectResult(Service::Interface* self) { +static void GetConnectResult(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -94,7 +94,7 @@ static void GetConnectResult(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void CloseAsync(Service::Interface* self) { +static void CloseAsync(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); if (ac_connected && disconnect_event) { @@ -120,7 +120,7 @@ static void CloseAsync(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void GetCloseResult(Service::Interface* self) { +static void GetCloseResult(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -134,7 +134,7 @@ static void GetCloseResult(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : Output connection type, 0 = none, 1 = Old3DS Internet, 2 = New3DS Internet. */ -static void GetWifiStatus(Service::Interface* self) { +static void GetWifiStatus(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(purpasmart96): This function is only a stub, @@ -155,7 +155,7 @@ static void GetWifiStatus(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : Infra Priority */ -static void GetInfraPriority(Service::Interface* self) { +static void GetInfraPriority(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -177,7 +177,7 @@ static void GetInfraPriority(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : Infra Priority */ -static void SetRequestEulaVersion(Service::Interface* self) { +static void SetRequestEulaVersion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 major = cmd_buff[1] & 0xFF; @@ -203,7 +203,7 @@ static void SetRequestEulaVersion(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void RegisterDisconnectEvent(Service::Interface* self) { +static void RegisterDisconnectEvent(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); disconnect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); @@ -221,7 +221,7 @@ static void RegisterDisconnectEvent(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : bool, is connected */ -static void IsConnected(Service::Interface* self) { +static void IsConnected(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -237,7 +237,7 @@ static void IsConnected(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetClientVersion(Service::Interface* self) { +static void SetClientVersion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); const u32 version = cmd_buff[1]; @@ -271,10 +271,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00400042, SetClientVersion, "SetClientVersion"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +AC_U::AC_U() { Register(FunctionTable); ac_connected = false; @@ -284,10 +281,11 @@ Interface::Interface() { disconnect_event = nullptr; } -Interface::~Interface() { +AC_U::~AC_U() { close_event = nullptr; connect_event = nullptr; disconnect_event = nullptr; } -} // namespace +} // namespace AC +} // namespace Service diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h index 6592b21c9..573c32d7e 100644 --- a/src/core/hle/service/ac_u.h +++ b/src/core/hle/service/ac_u.h @@ -6,21 +6,18 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AC_U +namespace Service { +namespace AC { -// socket service "ac:u" - -namespace AC_U { - -class Interface : public Service::Interface { +class AC_U final : public Interface { public: - Interface(); - ~Interface(); + AC_U(); + ~AC_U(); std::string GetPortName() const override { return "ac:u"; } }; -} // namespace +} // namespace AC +} // namespace Service diff --git a/src/core/hle/service/act/act.cpp b/src/core/hle/service/act/act.cpp new file mode 100644 index 000000000..9600036c0 --- /dev/null +++ b/src/core/hle/service/act/act.cpp @@ -0,0 +1,18 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/act/act.h" +#include "core/hle/service/act/act_a.h" +#include "core/hle/service/act/act_u.h" + +namespace Service { +namespace ACT { + +void Init() { + AddService(new ACT_A); + AddService(new ACT_U); +} + +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h new file mode 100644 index 000000000..1425291aa --- /dev/null +++ b/src/core/hle/service/act/act.h @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service { +namespace ACT { + +/// Initializes all ACT services +void Init(); + +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act/act_a.cpp b/src/core/hle/service/act/act_a.cpp new file mode 100644 index 000000000..5c523368f --- /dev/null +++ b/src/core/hle/service/act/act_a.cpp @@ -0,0 +1,30 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/act/act.h" +#include "core/hle/service/act/act_a.h" + +namespace Service { +namespace ACT { + +const Interface::FunctionInfo FunctionTable[] = { + // act:u shared commands + {0x00010084, nullptr, "Initialize"}, + {0x00020040, nullptr, "GetErrorCode"}, + {0x000600C2, nullptr, "GetAccountDataBlock"}, + {0x000B0042, nullptr, "AcquireEulaList"}, + {0x000D0040, nullptr, "GenerateUuid"}, + // act:a + {0x041300C2, nullptr, "UpdateMiiImage"}, + {0x041B0142, nullptr, "AgreeEula"}, + {0x04210042, nullptr, "UploadMii"}, + {0x04230082, nullptr, "ValidateMailAddress"}, +}; + +ACT_A::ACT_A() { + Register(FunctionTable); +} + +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act_a.h b/src/core/hle/service/act/act_a.h index 765cae644..e3adb03e5 100644 --- a/src/core/hle/service/act_a.h +++ b/src/core/hle/service/act/act_a.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace ACT_A +namespace Service { +namespace ACT { -namespace ACT_A { - -class Interface : public Service::Interface { +class ACT_A final : public Service::Interface { public: - Interface(); + ACT_A(); std::string GetPortName() const override { return "act:a"; } }; -} // namespace +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act/act_u.cpp index 05de4d002..cf98aa1d6 100644 --- a/src/core/hle/service/act_u.cpp +++ b/src/core/hle/service/act/act_u.cpp @@ -2,25 +2,25 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/service/act_u.h" +#include "core/hle/service/act/act.h" +#include "core/hle/service/act/act_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace ACT_U - -namespace ACT_U { +namespace Service { +namespace ACT { const Interface::FunctionInfo FunctionTable[] = { + // clang-format off {0x00010084, nullptr, "Initialize"}, {0x00020040, nullptr, "GetErrorCode"}, {0x000600C2, nullptr, "GetAccountDataBlock"}, + {0x000B0042, nullptr, "AcquireEulaList"}, {0x000D0040, nullptr, "GenerateUuid"}, + // clang-format on }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +ACT_U::ACT_U() { Register(FunctionTable); } -} // namespace +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act_u.h b/src/core/hle/service/act/act_u.h index be41454a4..9d8538fbf 100644 --- a/src/core/hle/service/act_u.h +++ b/src/core/hle/service/act/act_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace ACT_U +namespace Service { +namespace ACT { -namespace ACT_U { - -class Interface : public Service::Interface { +class ACT_U final : public Interface { public: - Interface(); + ACT_U(); std::string GetPortName() const override { return "act:u"; } }; -} // namespace +} // namespace ACT +} // namespace Service diff --git a/src/core/hle/service/act_a.cpp b/src/core/hle/service/act_a.cpp deleted file mode 100644 index 3a775fa90..000000000 --- a/src/core/hle/service/act_a.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/service/act_a.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace ACT_A - -namespace ACT_A { - -const Interface::FunctionInfo FunctionTable[] = { - {0x041300C2, nullptr, "UpdateMiiImage"}, - {0x041B0142, nullptr, "AgreeEula"}, - {0x04210042, nullptr, "UploadMii"}, - {0x04230082, nullptr, "ValidateMailAddress"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index f7a990d69..d344a622f 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -20,7 +20,7 @@ static std::array<u32, 3> am_titles_list_count = {0, 0, 0}; static u32 am_ticket_count = 0; static u32 am_ticket_list_count = 0; -void GetTitleCount(Service::Interface* self) { +void GetNumPrograms(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 media_type = cmd_buff[1] & 0xFF; @@ -81,7 +81,7 @@ void DeleteContents(Service::Interface* self) { media_type, title_id, am_content_count[media_type], content_ids_pointer); } -void GetTitleList(Service::Interface* self) { +void GetProgramList(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 media_type = cmd_buff[2] & 0xFF; @@ -97,7 +97,7 @@ void GetTitleList(Service::Interface* self) { media_type, am_titles_list_count[media_type], title_ids_output_pointer); } -void GetTitleInfo(Service::Interface* self) { +void GetProgramInfos(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 media_type = cmd_buff[1] & 0xFF; @@ -113,7 +113,7 @@ void GetTitleInfo(Service::Interface* self) { } void GetDataTitleInfos(Service::Interface* self) { - GetTitleInfo(self); + GetProgramInfos(self); LOG_WARNING(Service_AM, "(STUBBED) called"); } @@ -151,7 +151,7 @@ void DeleteTicket(Service::Interface* self) { LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id); } -void GetTicketCount(Service::Interface* self) { +void GetNumTickets(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 5676cdd5f..9bc2ca305 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -11,7 +11,7 @@ class Interface; namespace AM { /** - * AM::GetTitleCount service function + * AM::GetNumPrograms service function * Gets the number of installed titles in the requested media type * Inputs: * 0 : Command header (0x00010040) @@ -20,7 +20,7 @@ namespace AM { * 1 : Result, 0 on success, otherwise error code * 2 : The number of titles in the requested media type */ -void GetTitleCount(Service::Interface* self); +void GetNumPrograms(Service::Interface* self); /** * AM::FindContentInfos service function @@ -62,7 +62,7 @@ void ListContentInfos(Service::Interface* self); void DeleteContents(Service::Interface* self); /** - * AM::GetTitleList service function + * AM::GetProgramList service function * Loads information about the desired number of titles from the desired media type into an array * Inputs: * 1 : Title count @@ -72,10 +72,10 @@ void DeleteContents(Service::Interface* self); * 1 : Result, 0 on success, otherwise error code * 2 : The number of titles loaded from the requested media type */ -void GetTitleList(Service::Interface* self); +void GetProgramList(Service::Interface* self); /** - * AM::GetTitleInfo service function + * AM::GetProgramInfos service function * Inputs: * 1 : u8 Mediatype * 2 : Total titles @@ -84,11 +84,11 @@ void GetTitleList(Service::Interface* self); * Outputs: * 1 : Result, 0 on success, otherwise error code */ -void GetTitleInfo(Service::Interface* self); +void GetProgramInfos(Service::Interface* self); /** * AM::GetDataTitleInfos service function - * Wrapper for AM::GetTitleInfo + * Wrapper for AM::GetProgramInfos * Inputs: * 1 : u8 Mediatype * 2 : Total titles @@ -135,12 +135,12 @@ void GetNumContentInfos(Service::Interface* self); void DeleteTicket(Service::Interface* self); /** - * AM::GetTicketCount service function + * AM::GetNumTickets service function * Outputs: * 1 : Result, 0 on success, otherwise error code - * 2 : Total titles + * 2 : Number of tickets */ -void GetTicketCount(Service::Interface* self); +void GetNumTickets(Service::Interface* self); /** * AM::GetTicketList service function diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp index bfc1ca6bd..218375c8f 100644 --- a/src/core/hle/service/am/am_app.cpp +++ b/src/core/hle/service/am/am_app.cpp @@ -14,9 +14,14 @@ const Interface::FunctionInfo FunctionTable[] = { {0x10030142, ListContentInfos, "ListContentInfos"}, {0x10040102, DeleteContents, "DeleteContents"}, {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, + {0x10060080, nullptr, "GetNumDataTitleTickets"}, {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, + {0x100801C2, nullptr, "GetItemRights"}, {0x100900C0, nullptr, "IsDataTitleInUse"}, {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, + {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, + {0x100C0142, nullptr, "ListExistingContentInfos"}, + {0x100D0084, nullptr, "GetPatchTitleInfos"}, }; AM_APP_Interface::AM_APP_Interface() { diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp index 3a597a34c..f3cd1d23f 100644 --- a/src/core/hle/service/am/am_net.cpp +++ b/src/core/hle/service/am/am_net.cpp @@ -9,61 +9,116 @@ namespace Service { namespace AM { const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, GetTitleCount, "GetTitleCount"}, - {0x00020082, GetTitleList, "GetTitleList"}, - {0x00030084, GetTitleInfo, "GetTitleInfo"}, - {0x000400C0, nullptr, "DeleteApplicationTitle"}, - {0x000500C0, nullptr, "GetTitleProductCode"}, - {0x000600C0, nullptr, "GetTitleExtDataId"}, + {0x00010040, GetNumPrograms, "GetNumPrograms"}, + {0x00020082, GetProgramList, "GetProgramList"}, + {0x00030084, GetProgramInfos, "GetProgramInfos"}, + {0x000400C0, nullptr, "DeleteUserProgram"}, + {0x000500C0, nullptr, "GetProductCode"}, + {0x000600C0, nullptr, "GetStorageId"}, {0x00070080, DeleteTicket, "DeleteTicket"}, - {0x00080000, GetTicketCount, "GetTicketCount"}, + {0x00080000, GetNumTickets, "GetNumTickets"}, {0x00090082, GetTicketList, "GetTicketList"}, {0x000A0000, nullptr, "GetDeviceID"}, - {0x000D0084, nullptr, "GetPendingTitleInfo"}, - {0x000E00C0, nullptr, "DeletePendingTitle"}, - {0x00140040, nullptr, "FinalizePendingTitles"}, - {0x00150040, nullptr, "DeleteAllPendingTitles"}, + {0x000B0040, nullptr, "GetNumImportTitleContexts"}, + {0x000C0082, nullptr, "GetImportTitleContextList"}, + {0x000D0084, nullptr, "GetImportTitleContexts"}, + {0x000E00C0, nullptr, "DeleteImportTitleContext"}, + {0x000F00C0, nullptr, "GetNumImportContentContexts"}, + {0x00100102, nullptr, "GetImportContentContextList"}, + {0x00110104, nullptr, "GetImportContentContexts"}, + {0x00120102, nullptr, "DeleteImportContentContexts"}, + {0x00130040, nullptr, "NeedsCleanup"}, + {0x00140040, nullptr, "DoCleanup"}, + {0x00150040, nullptr, "DeleteAllImportContexts"}, + {0x00160000, nullptr, "DeleteAllTemporaryPrograms"}, + {0x00170044, nullptr, "ImportTwlBackupLegacy"}, {0x00180080, nullptr, "InitializeTitleDatabase"}, - {0x00190040, nullptr, "ReloadDBS"}, - {0x001A00C0, nullptr, "GetDSiWareExportSize"}, - {0x001B0144, nullptr, "ExportDSiWare"}, - {0x001C0084, nullptr, "ImportDSiWare"}, - {0x00230080, nullptr, "TitleIDListGetTotal2"}, - {0x002400C2, nullptr, "GetTitleIDList2"}, - {0x04010080, nullptr, "InstallFIRM"}, - {0x04020040, nullptr, "StartInstallCIADB0"}, - {0x04030000, nullptr, "StartInstallCIADB1"}, - {0x04040002, nullptr, "AbortCIAInstall"}, - {0x04050002, nullptr, "CloseCIAFinalizeInstall"}, - {0x04060002, nullptr, "CloseCIA"}, - {0x040700C2, nullptr, "FinalizeTitlesInstall"}, - {0x04080042, nullptr, "GetCiaFileInfo"}, - {0x040E00C2, nullptr, "InstallTitlesFinish"}, - {0x040F0000, nullptr, "InstallNATIVEFIRM"}, - {0x041000C0, nullptr, "DeleteTitle"}, - {0x04120000, nullptr, "Initialize"}, - {0x041700C0, nullptr, "MigrateAGBtoSAV"}, - {0x08010000, nullptr, "OpenTicket"}, - {0x08020002, nullptr, "TicketAbortInstall"}, - {0x08030002, nullptr, "TicketFinalizeInstall"}, - {0x08040100, nullptr, "InstallTitleBegin"}, - {0x08050000, nullptr, "InstallTitleAbort"}, - {0x080600C0, nullptr, "InstallTitleResume"}, - {0x08070000, nullptr, "InstallTitleAbortTMD"}, - {0x08080000, nullptr, "InstallTitleFinish"}, - {0x080A0000, nullptr, "OpenTMD"}, - {0x080B0002, nullptr, "TMDAbortInstall"}, - {0x080C0042, nullptr, "TMDFinalizeInstall"}, - {0x080E0040, nullptr, "OpenContentCreate"}, - {0x080F0002, nullptr, "ContentAbortInstall"}, - {0x08100040, nullptr, "OpenContentResume"}, - {0x08120002, nullptr, "ContentFinalizeInstall"}, - {0x08130000, nullptr, "GetTotalContents"}, - {0x08140042, nullptr, "GetContentIndexes"}, - {0x08150044, nullptr, "GetContentsInfo"}, - {0x08180042, nullptr, "GetCTCert"}, - {0x08190108, nullptr, "SetCertificates"}, - {0x081B00C2, nullptr, "InstallTitlesFinish"}, + {0x00190040, nullptr, "QueryAvailableTitleDatabase"}, + {0x001A00C0, nullptr, "CalcTwlBackupSize"}, + {0x001B0144, nullptr, "ExportTwlBackup"}, + {0x001C0084, nullptr, "ImportTwlBackup"}, + {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"}, + {0x001E00C8, nullptr, "ReadTwlBackupInfo"}, + {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"}, + {0x00200000, nullptr, "GetTwlArchiveResourceInfo"}, + {0x00210042, nullptr, "GetPersonalizedTicketInfoList"}, + {0x00220080, nullptr, "DeleteAllImportContextsFiltered"}, + {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"}, + {0x002400C2, nullptr, "GetImportTitleContextListFiltered"}, + {0x002500C0, nullptr, "CheckContentRights"}, + {0x00260044, nullptr, "GetTicketLimitInfos"}, + {0x00270044, nullptr, "GetDemoLaunchInfos"}, + {0x00280108, nullptr, "ReadTwlBackupInfoEx"}, + {0x00290082, nullptr, "DeleteUserProgramsAtomically"}, + {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"}, + {0x002B0142, nullptr, "ListExistingContentInfosSystem"}, + {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, + {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, + {0x04010080, nullptr, "UpdateFirmwareTo"}, + {0x04020040, nullptr, "BeginImportProgram"}, + {0x04030000, nullptr, "BeginImportProgramTemporarily"}, + {0x04040002, nullptr, "CancelImportProgram"}, + {0x04050002, nullptr, "EndImportProgram"}, + {0x04060002, nullptr, "EndImportProgramWithoutCommit"}, + {0x040700C2, nullptr, "CommitImportPrograms"}, + {0x04080042, nullptr, "GetProgramInfoFromCia"}, + {0x04090004, nullptr, "GetSystemMenuDataFromCia"}, + {0x040A0002, nullptr, "GetDependencyListFromCia"}, + {0x040B0002, nullptr, "GetTransferSizeFromCia"}, + {0x040C0002, nullptr, "GetCoreVersionFromCia"}, + {0x040D0042, nullptr, "GetRequiredSizeFromCia"}, + {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"}, + {0x040F0000, nullptr, "UpdateFirmwareAuto"}, + {0x041000C0, nullptr, "DeleteProgram"}, + {0x04110044, nullptr, "GetTwlProgramListForReboot"}, + {0x04120000, nullptr, "GetSystemUpdaterMutex"}, + {0x04130002, nullptr, "GetMetaSizeFromCia"}, + {0x04140044, nullptr, "GetMetaDataFromCia"}, + {0x04150080, nullptr, "CheckDemoLaunchRights"}, + {0x041600C0, nullptr, "GetInternalTitleLocationInfo"}, + {0x041700C0, nullptr, "PerpetuateAgbSaveData"}, + {0x04180040, nullptr, "BeginImportProgramForOverWrite"}, + {0x04190000, nullptr, "BeginImportSystemProgram"}, + {0x08010000, nullptr, "BeginImportTicket"}, + {0x08020002, nullptr, "CancelImportTicket"}, + {0x08030002, nullptr, "EndImportTicket"}, + {0x08040100, nullptr, "BeginImportTitle"}, + {0x08050000, nullptr, "StopImportTitle"}, + {0x080600C0, nullptr, "ResumeImportTitle"}, + {0x08070000, nullptr, "CancelImportTitle"}, + {0x08080000, nullptr, "EndImportTitle"}, + {0x080900C2, nullptr, "CommitImportTitles"}, + {0x080A0000, nullptr, "BeginImportTmd"}, + {0x080B0002, nullptr, "CancelImportTmd"}, + {0x080C0042, nullptr, "EndImportTmd"}, + {0x080D0042, nullptr, "CreateImportContentContexts"}, + {0x080E0040, nullptr, "BeginImportContent"}, + {0x080F0002, nullptr, "StopImportContent"}, + {0x08100040, nullptr, "ResumeImportContent"}, + {0x08110002, nullptr, "CancelImportContent"}, + {0x08120002, nullptr, "EndImportContent"}, + {0x08130000, nullptr, "GetNumCurrentImportContentContexts"}, + {0x08140042, nullptr, "GetCurrentImportContentContextList"}, + {0x08150044, nullptr, "GetCurrentImportContentContexts"}, + {0x08160146, nullptr, "Sign"}, + {0x08170146, nullptr, "Verify"}, + {0x08180042, nullptr, "GetDeviceCert"}, + {0x08190108, nullptr, "ImportCertificates"}, + {0x081A0042, nullptr, "ImportCertificate"}, + {0x081B00C2, nullptr, "CommitImportTitlesAndUpdateFirmwareAuto"}, + {0x081C0100, nullptr, "DeleteTicketId"}, + {0x081D0080, nullptr, "GetNumTicketIds"}, + {0x081E0102, nullptr, "GetTicketIdList"}, + {0x081F0080, nullptr, "GetNumTicketsOfProgram"}, + {0x08200102, nullptr, "ListTicketInfos"}, + {0x08210142, nullptr, "GetRightsOnlyTicketData"}, + {0x08220000, nullptr, "GetNumCurrentContentInfos"}, + {0x08230044, nullptr, "FindCurrentContentInfos"}, + {0x08240082, nullptr, "ListCurrentContentInfos"}, + {0x08250102, nullptr, "CalculateContextRequiredSize"}, + {0x08260042, nullptr, "UpdateImportContentContexts"}, + {0x08270000, nullptr, "DeleteAllDemoLaunchInfos"}, + {0x082800C0, nullptr, "BeginImportTitleForOverWrite"}, }; AM_NET_Interface::AM_NET_Interface() { diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp index a2268303c..949b3591d 100644 --- a/src/core/hle/service/am/am_sys.cpp +++ b/src/core/hle/service/am/am_sys.cpp @@ -9,27 +9,64 @@ namespace Service { namespace AM { const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, GetTitleCount, "GetTitleCount"}, - {0x00020082, GetTitleList, "GetTitleList"}, - {0x00030084, GetTitleInfo, "GetTitleInfo"}, - {0x000400C0, nullptr, "DeleteApplicationTitle"}, - {0x000500C0, nullptr, "GetTitleProductCode"}, - {0x000600C0, nullptr, "GetTitleExtDataId"}, + {0x00010040, GetNumPrograms, "GetNumPrograms"}, + {0x00020082, GetProgramList, "GetProgramList"}, + {0x00030084, GetProgramInfos, "GetProgramInfos"}, + {0x000400C0, nullptr, "DeleteUserProgram"}, + {0x000500C0, nullptr, "GetProductCode"}, + {0x000600C0, nullptr, "GetStorageId"}, {0x00070080, DeleteTicket, "DeleteTicket"}, - {0x00080000, GetTicketCount, "GetTicketCount"}, + {0x00080000, GetNumTickets, "GetNumTickets"}, {0x00090082, GetTicketList, "GetTicketList"}, {0x000A0000, nullptr, "GetDeviceID"}, - {0x000D0084, nullptr, "GetPendingTitleInfo"}, - {0x000E00C0, nullptr, "DeletePendingTitle"}, - {0x00140040, nullptr, "FinalizePendingTitles"}, - {0x00150040, nullptr, "DeleteAllPendingTitles"}, + {0x000B0040, nullptr, "GetNumImportTitleContexts"}, + {0x000C0082, nullptr, "GetImportTitleContextList"}, + {0x000D0084, nullptr, "GetImportTitleContexts"}, + {0x000E00C0, nullptr, "DeleteImportTitleContext"}, + {0x000F00C0, nullptr, "GetNumImportContentContexts"}, + {0x00100102, nullptr, "GetImportContentContextList"}, + {0x00110104, nullptr, "GetImportContentContexts"}, + {0x00120102, nullptr, "DeleteImportContentContexts"}, + {0x00130040, nullptr, "NeedsCleanup"}, + {0x00140040, nullptr, "DoCleanup"}, + {0x00150040, nullptr, "DeleteAllImportContexts"}, + {0x00160000, nullptr, "DeleteAllTemporaryPrograms"}, + {0x00170044, nullptr, "ImportTwlBackupLegacy"}, {0x00180080, nullptr, "InitializeTitleDatabase"}, - {0x00190040, nullptr, "ReloadDBS"}, - {0x001A00C0, nullptr, "GetDSiWareExportSize"}, - {0x001B0144, nullptr, "ExportDSiWare"}, - {0x001C0084, nullptr, "ImportDSiWare"}, - {0x00230080, nullptr, "GetPendingTitleCount"}, - {0x002400C2, nullptr, "GetPendingTitleList"}, + {0x00190040, nullptr, "QueryAvailableTitleDatabase"}, + {0x001A00C0, nullptr, "CalcTwlBackupSize"}, + {0x001B0144, nullptr, "ExportTwlBackup"}, + {0x001C0084, nullptr, "ImportTwlBackup"}, + {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"}, + {0x001E00C8, nullptr, "ReadTwlBackupInfo"}, + {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"}, + {0x00200000, nullptr, "GetTwlArchiveResourceInfo"}, + {0x00210042, nullptr, "GetPersonalizedTicketInfoList"}, + {0x00220080, nullptr, "DeleteAllImportContextsFiltered"}, + {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"}, + {0x002400C2, nullptr, "GetImportTitleContextListFiltered"}, + {0x002500C0, nullptr, "CheckContentRights"}, + {0x00260044, nullptr, "GetTicketLimitInfos"}, + {0x00270044, nullptr, "GetDemoLaunchInfos"}, + {0x00280108, nullptr, "ReadTwlBackupInfoEx"}, + {0x00290082, nullptr, "DeleteUserProgramsAtomically"}, + {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"}, + {0x002B0142, nullptr, "ListExistingContentInfosSystem"}, + {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, + {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, + {0x100100C0, GetNumContentInfos, "GetNumContentInfos"}, + {0x10020104, FindContentInfos, "FindContentInfos"}, + {0x10030142, ListContentInfos, "ListContentInfos"}, + {0x10040102, DeleteContents, "DeleteContents"}, + {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, + {0x10060080, nullptr, "GetNumDataTitleTickets"}, + {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, + {0x100801C2, nullptr, "GetItemRights"}, + {0x100900C0, nullptr, "IsDataTitleInUse"}, + {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, + {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, + {0x100C0142, nullptr, "ListExistingContentInfos"}, + {0x100D0084, nullptr, "GetPatchTitleInfos"}, }; AM_SYS_Interface::AM_SYS_Interface() { diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp index 151b5e42b..354d51610 100644 --- a/src/core/hle/service/am/am_u.cpp +++ b/src/core/hle/service/am/am_u.cpp @@ -9,40 +9,76 @@ namespace Service { namespace AM { const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, GetTitleCount, "GetTitleCount"}, - {0x00020082, GetTitleList, "GetTitleList"}, - {0x00030084, GetTitleInfo, "GetTitleInfo"}, - {0x000400C0, nullptr, "DeleteApplicationTitle"}, - {0x000500C0, nullptr, "GetTitleProductCode"}, - {0x000600C0, nullptr, "GetTitleExtDataId"}, + {0x00010040, GetNumPrograms, "GetNumPrograms"}, + {0x00020082, GetProgramList, "GetProgramList"}, + {0x00030084, GetProgramInfos, "GetProgramInfos"}, + {0x000400C0, nullptr, "DeleteUserProgram"}, + {0x000500C0, nullptr, "GetProductCode"}, + {0x000600C0, nullptr, "GetStorageId"}, {0x00070080, DeleteTicket, "DeleteTicket"}, - {0x00080000, GetTicketCount, "GetTicketCount"}, + {0x00080000, GetNumTickets, "GetNumTickets"}, {0x00090082, GetTicketList, "GetTicketList"}, {0x000A0000, nullptr, "GetDeviceID"}, - {0x000D0084, nullptr, "GetPendingTitleInfo"}, - {0x000E00C0, nullptr, "DeletePendingTitle"}, - {0x00140040, nullptr, "FinalizePendingTitles"}, - {0x00150040, nullptr, "DeleteAllPendingTitles"}, + {0x000B0040, nullptr, "GetNumImportTitleContexts"}, + {0x000C0082, nullptr, "GetImportTitleContextList"}, + {0x000D0084, nullptr, "GetImportTitleContexts"}, + {0x000E00C0, nullptr, "DeleteImportTitleContext"}, + {0x000F00C0, nullptr, "GetNumImportContentContexts"}, + {0x00100102, nullptr, "GetImportContentContextList"}, + {0x00110104, nullptr, "GetImportContentContexts"}, + {0x00120102, nullptr, "DeleteImportContentContexts"}, + {0x00130040, nullptr, "NeedsCleanup"}, + {0x00140040, nullptr, "DoCleanup"}, + {0x00150040, nullptr, "DeleteAllImportContexts"}, + {0x00160000, nullptr, "DeleteAllTemporaryPrograms"}, + {0x00170044, nullptr, "ImportTwlBackupLegacy"}, {0x00180080, nullptr, "InitializeTitleDatabase"}, - {0x00190040, nullptr, "ReloadDBS"}, - {0x001A00C0, nullptr, "GetDSiWareExportSize"}, - {0x001B0144, nullptr, "ExportDSiWare"}, - {0x001C0084, nullptr, "ImportDSiWare"}, - {0x00230080, nullptr, "TitleIDListGetTotal2"}, - {0x002400C2, nullptr, "GetTitleIDList2"}, - {0x04010080, nullptr, "InstallFIRM"}, - {0x04020040, nullptr, "StartInstallCIADB0"}, - {0x04030000, nullptr, "StartInstallCIADB1"}, - {0x04040002, nullptr, "AbortCIAInstall"}, - {0x04050002, nullptr, "CloseCIAFinalizeInstall"}, - {0x04060002, nullptr, "CloseCIA"}, - {0x040700C2, nullptr, "FinalizeTitlesInstall"}, - {0x04080042, nullptr, "GetCiaFileInfo"}, - {0x040E00C2, nullptr, "InstallTitlesFinish"}, - {0x040F0000, nullptr, "InstallNATIVEFIRM"}, - {0x041000C0, nullptr, "DeleteTitle"}, - {0x04120000, nullptr, "Initialize"}, - {0x041700C0, nullptr, "MigrateAGBtoSAV"}, + {0x00190040, nullptr, "QueryAvailableTitleDatabase"}, + {0x001A00C0, nullptr, "CalcTwlBackupSize"}, + {0x001B0144, nullptr, "ExportTwlBackup"}, + {0x001C0084, nullptr, "ImportTwlBackup"}, + {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"}, + {0x001E00C8, nullptr, "ReadTwlBackupInfo"}, + {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"}, + {0x00200000, nullptr, "GetTwlArchiveResourceInfo"}, + {0x00210042, nullptr, "GetPersonalizedTicketInfoList"}, + {0x00220080, nullptr, "DeleteAllImportContextsFiltered"}, + {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"}, + {0x002400C2, nullptr, "GetImportTitleContextListFiltered"}, + {0x002500C0, nullptr, "CheckContentRights"}, + {0x00260044, nullptr, "GetTicketLimitInfos"}, + {0x00270044, nullptr, "GetDemoLaunchInfos"}, + {0x00280108, nullptr, "ReadTwlBackupInfoEx"}, + {0x00290082, nullptr, "DeleteUserProgramsAtomically"}, + {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"}, + {0x002B0142, nullptr, "ListExistingContentInfosSystem"}, + {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, + {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, + {0x04010080, nullptr, "UpdateFirmwareTo"}, + {0x04020040, nullptr, "BeginImportProgram"}, + {0x04030000, nullptr, "BeginImportProgramTemporarily"}, + {0x04040002, nullptr, "CancelImportProgram"}, + {0x04050002, nullptr, "EndImportProgram"}, + {0x04060002, nullptr, "EndImportProgramWithoutCommit"}, + {0x040700C2, nullptr, "CommitImportPrograms"}, + {0x04080042, nullptr, "GetProgramInfoFromCia"}, + {0x04090004, nullptr, "GetSystemMenuDataFromCia"}, + {0x040A0002, nullptr, "GetDependencyListFromCia"}, + {0x040B0002, nullptr, "GetTransferSizeFromCia"}, + {0x040C0002, nullptr, "GetCoreVersionFromCia"}, + {0x040D0042, nullptr, "GetRequiredSizeFromCia"}, + {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"}, + {0x040F0000, nullptr, "UpdateFirmwareAuto"}, + {0x041000C0, nullptr, "DeleteProgram"}, + {0x04110044, nullptr, "GetTwlProgramListForReboot"}, + {0x04120000, nullptr, "GetSystemUpdaterMutex"}, + {0x04130002, nullptr, "GetMetaSizeFromCia"}, + {0x04140044, nullptr, "GetMetaDataFromCia"}, + {0x04150080, nullptr, "CheckDemoLaunchRights"}, + {0x041600C0, nullptr, "GetInternalTitleLocationInfo"}, + {0x041700C0, nullptr, "PerpetuateAgbSaveData"}, + {0x04180040, nullptr, "BeginImportProgramForOverWrite"}, + {0x04190000, nullptr, "BeginImportSystemProgram"}, }; AM_U_Interface::AM_U_Interface() { diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 31e5e07b2..615fe31ea 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -458,12 +458,16 @@ void GetStartupArgument(Service::Interface* self) { return; } - LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x , " - "parameter_value=0x%08x", - startup_argument_type, parameter_size, Memory::Read32(cmd_buff[41])); + u32 addr = cmd_buff[65]; + if (addr && parameter_size) { + Memory::ZeroBlock(addr, parameter_size); + } + + LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", + startup_argument_type, parameter_size); cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = (parameter_size > 0) ? 1 : 0; + cmd_buff[2] = 0; } void CheckNew3DSApp(Service::Interface* self) { diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 44dbd8757..80325361f 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -14,6 +14,9 @@ class Interface; namespace APT { +/// Each APT service can only have up to 2 sessions connected at the same time. +static const u32 MaxAPTSessions = 2; + /// Holds information about the parameters used in Send/Glance/ReceiveParameter struct MessageParameter { u32 sender_id = 0; @@ -407,9 +410,11 @@ void CancelLibraryApplet(Service::Interface* self); * Inputs: * 1 : Parameter Size (capped to 0x300) * 2 : StartupArgumentType + * 65 : Output buffer for startup argument * Outputs: * 0 : Return header - * 1 : u8, Exists (0 = does not exist, 1 = exists) + * 1 : Result of function, 0 on success, otherwise error code + * 2 : u8, Exists (0 = does not exist, 1 = exists) */ void GetStartupArgument(Service::Interface* self); diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index a7a0c8a41..62dc2d61d 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -9,37 +9,100 @@ namespace Service { namespace APT { const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, GetLockHandle, "GetLockHandle?"}, - {0x00020080, Initialize, "Initialize?"}, - {0x00030040, Enable, "Enable?"}, - {0x00040040, nullptr, "Finalize?"}, + {0x00010040, GetLockHandle, "GetLockHandle"}, + {0x00020080, Initialize, "Initialize"}, + {0x00030040, Enable, "Enable"}, + {0x00040040, nullptr, "Finalize"}, {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, {0x00060040, GetAppletInfo, "GetAppletInfo"}, + {0x00070000, nullptr, "GetLastSignaledAppletId"}, + {0x00080000, nullptr, "CountRegisteredApplet"}, {0x00090040, IsRegistered, "IsRegistered"}, + {0x000A0040, nullptr, "GetAttribute"}, {0x000B0040, InquireNotification, "InquireNotification"}, {0x000C0104, SendParameter, "SendParameter"}, {0x000D0080, ReceiveParameter, "ReceiveParameter"}, {0x000E0080, GlanceParameter, "GlanceParameter"}, {0x000F0100, CancelParameter, "CancelParameter"}, + {0x001000C2, nullptr, "DebugFunc"}, + {0x001100C0, nullptr, "MapProgramIdForDebug"}, + {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, + {0x00130000, nullptr, "GetPreparationState"}, + {0x00140040, nullptr, "SetPreparationState"}, {0x00150140, PrepareToStartApplication, "PrepareToStartApplication"}, {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, + {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, + {0x00190040, nullptr, "PrepareToStartSystemApplet"}, + {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, + {0x001B00C4, nullptr, "StartApplication"}, + {0x001C0000, nullptr, "WakeupApplication"}, + {0x001D0000, nullptr, "CancelApplication"}, {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, + {0x001F0084, nullptr, "StartSystemApplet"}, + {0x00200044, nullptr, "StartNewestHomeMenu"}, + {0x00210000, nullptr, "OrderToCloseApplication"}, + {0x00220040, nullptr, "PrepareToCloseApplication"}, + {0x00230040, nullptr, "PrepareToJumpToApplication"}, + {0x00240044, nullptr, "JumpToApplication"}, + {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, + {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, + {0x00270044, nullptr, "CloseApplication"}, + {0x00280044, nullptr, "CloseLibraryApplet"}, + {0x00290044, nullptr, "CloseSystemApplet"}, + {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, + {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, + {0x002C0044, nullptr, "JumpToHomeMenu"}, + {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, + {0x002E0044, nullptr, "LeaveHomeMenu"}, + {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, + {0x00300044, nullptr, "LeaveResidentApplet"}, + {0x00310100, nullptr, "PrepareToDoApplicationJump"}, + {0x00320084, nullptr, "DoApplicationJump"}, + {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, + {0x00340084, nullptr, "SendDeliverArg"}, + {0x00350080, nullptr, "ReceiveDeliverArg"}, + {0x00360040, nullptr, "LoadSysMenuArg"}, + {0x00370042, nullptr, "StoreSysMenuArg"}, + {0x00380040, nullptr, "PreloadResidentApplet"}, + {0x00390040, nullptr, "PrepareToStartResidentApplet"}, + {0x003A0044, nullptr, "StartResidentApplet"}, {0x003B0040, CancelLibraryApplet, "CancelLibraryApplet"}, + {0x003C0042, nullptr, "SendDspSleep"}, + {0x003D0042, nullptr, "SendDspWakeUp"}, {0x003E0080, nullptr, "ReplySleepQuery"}, - {0x00430040, NotifyToWait, "NotifyToWait?"}, - {0x00440000, GetSharedFont, "GetSharedFont?"}, - {0x004B00C2, AppletUtility, "AppletUtility?"}, + {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, + {0x00400042, nullptr, "SendCaptureBufferInfo"}, + {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, + {0x00420080, nullptr, "SleepSystem"}, + {0x00430040, NotifyToWait, "NotifyToWait"}, + {0x00440000, GetSharedFont, "GetSharedFont"}, + {0x00450040, nullptr, "GetWirelessRebootInfo"}, + {0x00460104, nullptr, "Wrap"}, + {0x00470104, nullptr, "Unwrap"}, + {0x00480100, nullptr, "GetProgramInfo"}, + {0x00490180, nullptr, "Reboot"}, + {0x004A0040, nullptr, "GetCaptureInfo"}, + {0x004B00C2, AppletUtility, "AppletUtility"}, + {0x004C0000, nullptr, "SetFatalErrDispMode"}, + {0x004D0080, nullptr, "GetAppletProgramInfo"}, + {0x004E0000, nullptr, "HardwareResetAsync"}, {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, {0x00510080, GetStartupArgument, "GetStartupArgument"}, + {0x00520104, nullptr, "Wrap1"}, + {0x00530104, nullptr, "Unwrap1"}, {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, + {0x00570044, nullptr, "WakeupApplication2"}, + {0x00580002, nullptr, "GetProgramID"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"}, + {0x01040000, nullptr, "IsStandardMemoryLayout"}, + {0x01050100, nullptr, "IsTitleAllowed"}, }; -APT_A_Interface::APT_A_Interface() { +APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index c4556a5de..effd23dce 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -94,12 +94,15 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00530104, nullptr, "Unwrap1"}, {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, + {0x00570044, nullptr, "WakeupApplication2"}, {0x00580002, nullptr, "GetProgramID"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"}, + {0x01040000, nullptr, "IsStandardMemoryLayout"}, + {0x01050100, nullptr, "IsTitleAllowed"}, }; -APT_S_Interface::APT_S_Interface() { +APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index a731c39f6..e06084a1e 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x01020000, CheckNew3DS, "CheckNew3DS"}, }; -APT_U_Interface::APT_U_Interface() { +APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp index dfee8d055..ee941e228 100644 --- a/src/core/hle/service/boss/boss_p.cpp +++ b/src/core/hle/service/boss/boss_p.cpp @@ -2,16 +2,81 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/service/boss/boss.h" #include "core/hle/service/boss/boss_p.h" namespace Service { namespace BOSS { -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; +const Interface::FunctionInfo FunctionTable[] = { + // boss:u shared commands + {0x00010082, InitializeSession, "InitializeSession"}, + {0x00020100, RegisterStorage, "RegisterStorage"}, + {0x00030000, UnregisterStorage, "UnregisterStorage"}, + {0x00040000, GetStorageInfo, "GetStorageInfo"}, + {0x00050042, RegisterPrivateRootCa, "RegisterPrivateRootCa"}, + {0x00060084, RegisterPrivateClientCert, "RegisterPrivateClientCert"}, + {0x00070000, GetNewArrivalFlag, "GetNewArrivalFlag"}, + {0x00080002, RegisterNewArrivalEvent, "RegisterNewArrivalEvent"}, + {0x00090040, SetOptoutFlag, "SetOptoutFlag"}, + {0x000A0000, GetOptoutFlag, "GetOptoutFlag"}, + {0x000B00C2, RegisterTask, "RegisterTask"}, + {0x000C0082, UnregisterTask, "UnregisterTask"}, + {0x000D0082, ReconfigureTask, "ReconfigureTask"}, + {0x000E0000, GetTaskIdList, "GetTaskIdList"}, + {0x000F0042, GetStepIdList, "GetStepIdList"}, + {0x00100102, GetNsDataIdList, "GetNsDataIdList"}, + {0x00110102, GetOwnNsDataIdList, "GetOwnNsDataIdList"}, + {0x00120102, GetNewDataNsDataIdList, "GetNewDataNsDataIdList"}, + {0x00130102, GetOwnNewDataNsDataIdList, "GetOwnNewDataNsDataIdList"}, + {0x00140082, SendProperty, "SendProperty"}, + {0x00150042, SendPropertyHandle, "SendPropertyHandle"}, + {0x00160082, ReceiveProperty, "ReceiveProperty"}, + {0x00170082, UpdateTaskInterval, "UpdateTaskInterval"}, + {0x00180082, UpdateTaskCount, "UpdateTaskCount"}, + {0x00190042, GetTaskInterval, "GetTaskInterval"}, + {0x001A0042, GetTaskCount, "GetTaskCount"}, + {0x001B0042, GetTaskServiceStatus, "GetTaskServiceStatus"}, + {0x001C0042, StartTask, "StartTask"}, + {0x001D0042, StartTaskImmediate, "StartTaskImmediate"}, + {0x001E0042, CancelTask, "CancelTask"}, + {0x001F0000, GetTaskFinishHandle, "GetTaskFinishHandle"}, + {0x00200082, GetTaskState, "GetTaskState"}, + {0x00210042, GetTaskResult, "GetTaskResult"}, + {0x00220042, GetTaskCommErrorCode, "GetTaskCommErrorCode"}, + {0x002300C2, GetTaskStatus, "GetTaskStatus"}, + {0x00240082, GetTaskError, "GetTaskError"}, + {0x00250082, GetTaskInfo, "GetTaskInfo"}, + {0x00260040, DeleteNsData, "DeleteNsData"}, + {0x002700C2, GetNsDataHeaderInfo, "GetNsDataHeaderInfo"}, + {0x00280102, ReadNsData, "ReadNsData"}, + {0x00290080, SetNsDataAdditionalInfo, "SetNsDataAdditionalInfo"}, + {0x002A0040, GetNsDataAdditionalInfo, "GetNsDataAdditionalInfo"}, + {0x002B0080, SetNsDataNewFlag, "SetNsDataNewFlag"}, + {0x002C0040, GetNsDataNewFlag, "GetNsDataNewFlag"}, + {0x002D0040, GetNsDataLastUpdate, "GetNsDataLastUpdate"}, + {0x002E0040, GetErrorCode, "GetErrorCode"}, + {0x002F0140, RegisterStorageEntry, "RegisterStorageEntry"}, + {0x00300000, GetStorageEntryInfo, "GetStorageEntryInfo"}, + {0x00310100, SetStorageOption, "SetStorageOption"}, + {0x00320000, GetStorageOption, "GetStorageOption"}, + {0x00330042, StartBgImmediate, "StartBgImmediate"}, + {0x00340042, GetTaskActivePriority, "GetTaskActivePriority"}, + {0x003500C2, RegisterImmediateTask, "RegisterImmediateTask"}, + {0x00360084, SetTaskQuery, "SetTaskQuery"}, + {0x00370084, GetTaskQuery, "GetTaskQuery"}, + // boss:p + {0x04040080, nullptr, "GetAppNewFlag"}, + {0x04130082, nullptr, "SendPropertyPrivileged"}, + {0x041500C0, nullptr, "DeleteNsDataPrivileged"}, + {0x04160142, nullptr, "GetNsDataHeaderInfoPrivileged"}, + {0x04170182, nullptr, "ReadNsDataPrivileged"}, + {0x041A0100, nullptr, "SetNsDataNewFlagPrivileged"}, + {0x041B00C0, nullptr, "GetNsDataNewFlagPrivileged"}, +}; BOSS_P_Interface::BOSS_P_Interface() { - // Register(FunctionTable); + Register(FunctionTable); } } // namespace BOSS diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 515b344e6..eb04273db 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -5,6 +5,7 @@ #include "common/logging/log.h" #include "core/hle/kernel/event.h" #include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_ndm.h" #include "core/hle/service/cecd/cecd_s.h" #include "core/hle/service/cecd/cecd_u.h" #include "core/hle/service/service.h" @@ -43,12 +44,13 @@ void GetChangeStateEventHandle(Service::Interface* self) { } void Init() { - AddService(new CECD_S_Interface); - AddService(new CECD_U_Interface); + AddService(new CECD_NDM); + AddService(new CECD_S); + AddService(new CECD_U); - cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::cecinfo_event"); + cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::cecinfo_event"); change_state_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::change_state_event"); + Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::change_state_event"); } void Shutdown() { diff --git a/src/core/hle/service/cecd/cecd_ndm.cpp b/src/core/hle/service/cecd/cecd_ndm.cpp new file mode 100644 index 000000000..7baf93750 --- /dev/null +++ b/src/core/hle/service/cecd/cecd_ndm.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_ndm.h" + +namespace Service { +namespace CECD { + +static const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "Initialize"}, + {0x00020000, nullptr, "Deinitialize"}, + {0x00030000, nullptr, "ResumeDaemon"}, + {0x00040040, nullptr, "SuspendDaemon"}, +}; + +CECD_NDM::CECD_NDM() { + Register(FunctionTable); +} + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_ndm.h b/src/core/hle/service/cecd/cecd_ndm.h new file mode 100644 index 000000000..2e2e50ada --- /dev/null +++ b/src/core/hle/service/cecd/cecd_ndm.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CECD { + +class CECD_NDM : public Interface { +public: + CECD_NDM(); + + std::string GetPortName() const override { + return "cecd:ndm"; + } +}; + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp index 7477b9320..eacda7d41 100644 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -2,16 +2,34 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/service/cecd/cecd.h" #include "core/hle/service/cecd/cecd_s.h" namespace Service { namespace CECD { -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; +static const Interface::FunctionInfo FunctionTable[] = { + // cecd:u shared commands + {0x000100C2, nullptr, "OpenRawFile"}, + {0x00020042, nullptr, "ReadRawFile"}, + {0x00030104, nullptr, "ReadMessage"}, + {0x00040106, nullptr, "ReadMessageWithHMAC"}, + {0x00050042, nullptr, "WriteRawFile"}, + {0x00060104, nullptr, "WriteMessage"}, + {0x00070106, nullptr, "WriteMessageWithHMAC"}, + {0x00080102, nullptr, "Delete"}, + {0x000A00C4, nullptr, "GetSystemInfo"}, + {0x000B0040, nullptr, "RunCommand"}, + {0x000C0040, nullptr, "RunCommandAlt"}, + {0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"}, + {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"}, + {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"}, + {0x00110104, nullptr, "OpenAndWrite"}, + {0x00120104, nullptr, "OpenAndRead"}, +}; -CECD_S_Interface::CECD_S_Interface() { - // Register(FunctionTable); +CECD_S::CECD_S() { + Register(FunctionTable); } } // namespace CECD diff --git a/src/core/hle/service/cecd/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h index df5c01849..ab6c6789a 100644 --- a/src/core/hle/service/cecd/cecd_s.h +++ b/src/core/hle/service/cecd/cecd_s.h @@ -9,9 +9,9 @@ namespace Service { namespace CECD { -class CECD_S_Interface : public Interface { +class CECD_S : public Interface { public: - CECD_S_Interface(); + CECD_S(); std::string GetPortName() const override { return "cecd:s"; diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp index 4b747de7b..3ed864f0b 100644 --- a/src/core/hle/service/cecd/cecd_u.cpp +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -9,13 +9,26 @@ namespace Service { namespace CECD { static const Interface::FunctionInfo FunctionTable[] = { + // cecd:u shared commands + {0x000100C2, nullptr, "OpenRawFile"}, + {0x00020042, nullptr, "ReadRawFile"}, + {0x00030104, nullptr, "ReadMessage"}, + {0x00040106, nullptr, "ReadMessageWithHMAC"}, + {0x00050042, nullptr, "WriteRawFile"}, + {0x00060104, nullptr, "WriteMessage"}, + {0x00070106, nullptr, "WriteMessageWithHMAC"}, + {0x00080102, nullptr, "Delete"}, + {0x000A00C4, nullptr, "GetSystemInfo"}, + {0x000B0040, nullptr, "RunCommand"}, + {0x000C0040, nullptr, "RunCommandAlt"}, {0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"}, {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"}, {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"}, - {0x00120104, nullptr, "ReadSavedData"}, + {0x00110104, nullptr, "OpenAndWrite"}, + {0x00120104, nullptr, "OpenAndRead"}, }; -CECD_U_Interface::CECD_U_Interface() { +CECD_U::CECD_U() { Register(FunctionTable); } diff --git a/src/core/hle/service/cecd/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h index 394030ffc..16e874ff5 100644 --- a/src/core/hle/service/cecd/cecd_u.h +++ b/src/core/hle/service/cecd/cecd_u.h @@ -9,9 +9,9 @@ namespace Service { namespace CECD { -class CECD_U_Interface : public Interface { +class CECD_U : public Interface { public: - CECD_U_Interface(); + CECD_U(); std::string GetPortName() const override { return "cecd:u"; diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 5e340f4c8..0bf59eb76 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -12,6 +12,7 @@ #include "core/hle/result.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg_i.h" +#include "core/hle/service/cfg/cfg_nor.h" #include "core/hle/service/cfg/cfg_s.h" #include "core/hle/service/cfg/cfg_u.h" #include "core/hle/service/fs/archive.h" @@ -574,9 +575,10 @@ ResultCode LoadConfigNANDSaveFile() { } void Init() { - AddService(new CFG_I_Interface); - AddService(new CFG_S_Interface); - AddService(new CFG_U_Interface); + AddService(new CFG_I); + AddService(new CFG_NOR); + AddService(new CFG_S); + AddService(new CFG_U); LoadConfigNANDSaveFile(); diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp index 2ff52c8b8..e8db0fc42 100644 --- a/src/core/hle/service/cfg/cfg_i.cpp +++ b/src/core/hle/service/cfg/cfg_i.cpp @@ -20,6 +20,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00080080, nullptr, "GoThroughTable"}, {0x00090040, GetCountryCodeString, "GetCountryCodeString"}, {0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, + {0x000B0000, nullptr, "IsFangateSupported"}, // cfg:i {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, {0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, @@ -55,7 +56,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08180042, nullptr, "SecureInfoGetSerialNo"}, }; -CFG_I_Interface::CFG_I_Interface() { +CFG_I::CFG_I() { Register(FunctionTable); } diff --git a/src/core/hle/service/cfg/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h index d0a2cce39..8cfd47633 100644 --- a/src/core/hle/service/cfg/cfg_i.h +++ b/src/core/hle/service/cfg/cfg_i.h @@ -9,9 +9,9 @@ namespace Service { namespace CFG { -class CFG_I_Interface : public Service::Interface { +class CFG_I final : public Interface { public: - CFG_I_Interface(); + CFG_I(); std::string GetPortName() const override { return "cfg:i"; diff --git a/src/core/hle/service/cfg/cfg_nor.cpp b/src/core/hle/service/cfg/cfg_nor.cpp new file mode 100644 index 000000000..4ce02d115 --- /dev/null +++ b/src/core/hle/service/cfg/cfg_nor.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/cfg/cfg.h" +#include "core/hle/service/cfg/cfg_nor.h" + +namespace Service { +namespace CFG { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, nullptr, "Initialize"}, + {0x00020000, nullptr, "Shutdown"}, + {0x00050082, nullptr, "ReadData"}, + {0x00060082, nullptr, "WriteData"}, +}; + +CFG_NOR::CFG_NOR() { + Register(FunctionTable); +} + +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/cfg/cfg_nor.h b/src/core/hle/service/cfg/cfg_nor.h new file mode 100644 index 000000000..c337718e7 --- /dev/null +++ b/src/core/hle/service/cfg/cfg_nor.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CFG { + +class CFG_NOR final : public Interface { +public: + CFG_NOR(); + + std::string GetPortName() const override { + return "cfg:nor"; + } +}; + +} // namespace CFG +} // namespace Service diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index eed26dec7..9386fe33d 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp @@ -20,6 +20,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00080080, nullptr, "GoThroughTable"}, {0x00090040, GetCountryCodeString, "GetCountryCodeString"}, {0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, + {0x000B0000, nullptr, "IsFangateSupported"}, // cfg:s {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, {0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"}, @@ -32,7 +33,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x04090000, nullptr, "UpdateConfigBlk00040003"}, }; -CFG_S_Interface::CFG_S_Interface() { +CFG_S::CFG_S() { Register(FunctionTable); } diff --git a/src/core/hle/service/cfg/cfg_s.h b/src/core/hle/service/cfg/cfg_s.h index 5568d6485..99fea46ee 100644 --- a/src/core/hle/service/cfg/cfg_s.h +++ b/src/core/hle/service/cfg/cfg_s.h @@ -9,9 +9,9 @@ namespace Service { namespace CFG { -class CFG_S_Interface : public Service::Interface { +class CFG_S final : public Interface { public: - CFG_S_Interface(); + CFG_S(); std::string GetPortName() const override { return "cfg:s"; diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp index f28217134..7b66fee22 100644 --- a/src/core/hle/service/cfg/cfg_u.cpp +++ b/src/core/hle/service/cfg/cfg_u.cpp @@ -20,9 +20,10 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00080080, nullptr, "GoThroughTable"}, {0x00090040, GetCountryCodeString, "GetCountryCodeString"}, {0x000A0040, GetCountryCodeID, "GetCountryCodeID"}, + {0x000B0000, nullptr, "IsFangateSupported"}, }; -CFG_U_Interface::CFG_U_Interface() { +CFG_U::CFG_U() { Register(FunctionTable); } diff --git a/src/core/hle/service/cfg/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h index 5303d8ac6..fc7844714 100644 --- a/src/core/hle/service/cfg/cfg_u.h +++ b/src/core/hle/service/cfg/cfg_u.h @@ -9,9 +9,9 @@ namespace Service { namespace CFG { -class CFG_U_Interface : public Service::Interface { +class CFG_U final : public Interface { public: - CFG_U_Interface(); + CFG_U(); std::string GetPortName() const override { return "cfg:u"; diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp index 20c759ad7..6cf62f9bc 100644 --- a/src/core/hle/service/csnd_snd.cpp +++ b/src/core/hle/service/csnd_snd.cpp @@ -4,85 +4,137 @@ #include <cstring> #include "common/alignment.h" -#include "core/hle/hle.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/csnd_snd.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CSND_SND +namespace Service { +namespace CSND { -namespace CSND_SND { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010140, Initialize, "Initialize"}, - {0x00020000, Shutdown, "Shutdown"}, - {0x00030040, ExecuteType0Commands, "ExecuteType0Commands"}, - {0x00040080, nullptr, "ExecuteType1Commands"}, - {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"}, - {0x00060000, nullptr, "ReleaseSoundChannels"}, - {0x00070000, nullptr, "AcquireCaptureDevice"}, - {0x00080040, nullptr, "ReleaseCaptureDevice"}, - {0x00090082, nullptr, "FlushDataCache"}, - {0x000A0082, nullptr, "StoreDataCache"}, - {0x000B0082, nullptr, "InvalidateDataCache"}, - {0x000C0000, nullptr, "Reset"}, +struct Type0Command { + // command id and next command offset + u32 command_id; + u32 finished; + u32 flags; + u8 parameters[20]; }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} +static_assert(sizeof(Type0Command) == 0x20, "Type0Command structure size is wrong"); static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr; static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr; -void Initialize(Service::Interface* self) { +/** + * CSND_SND::Initialize service function + * Inputs: + * 0 : Header Code[0x00010140] + * 1 : Shared memory block size, for mem-block creation + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Handle-list header + * 3 : Mutex handle + * 4 : Shared memory block handle + */ +static void Initialize(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE); + using Kernel::MemoryPermission; shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory"); - mutex = Kernel::Mutex::Create(false); + mutex = Kernel::Mutex::Create(false, "CSND:mutex"); cmd_buff[1] = RESULT_SUCCESS.raw; cmd_buff[2] = IPC::CopyHandleDesc(2); cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom(); cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom(); + + LOG_WARNING(Service_CSND, "(STUBBED) called"); } -void ExecuteType0Commands(Service::Interface* self) { - u32* const cmd_buff = Kernel::GetCommandBuffer(); - u8* const ptr = shared_memory->GetPointer(cmd_buff[1]); +/** + * CSND_SND::Shutdown service function + * Inputs: + * 0 : Header Code[0x00020000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void Shutdown(Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); - if (shared_memory != nullptr && ptr != nullptr) { - Type0Command command; - std::memcpy(&command, ptr, sizeof(Type0Command)); + shared_memory = nullptr; + mutex = nullptr; - LOG_WARNING(Service, "(STUBBED) CSND_SND::ExecuteType0Commands"); - command.finished |= 1; - cmd_buff[1] = 0; + cmd_buff[1] = RESULT_SUCCESS.raw; + LOG_WARNING(Service_CSND, "(STUBBED) called"); +} - std::memcpy(ptr, &command, sizeof(Type0Command)); - } else { +/** + * CSND_SND::ExecuteCommands service function + * Inputs: + * 0 : Header Code[0x00030040] + * 1 : Command offset in shared memory. + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Available channel bit mask + */ +static void ExecuteCommands(Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + if (shared_memory == nullptr) { cmd_buff[1] = 1; + LOG_ERROR(Service_CSND, "called, shared memory not allocated"); + return; } + + VAddr addr = cmd_buff[1]; + u8* ptr = shared_memory->GetPointer(addr); + + Type0Command command; + std::memcpy(&command, ptr, sizeof(Type0Command)); + command.finished |= 1; + std::memcpy(ptr, &command, sizeof(Type0Command)); + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CSND, "(STUBBED) called, addr=0x%08X", addr); } -void AcquireSoundChannels(Service::Interface* self) { +/** + * CSND_SND::AcquireSoundChannels service function + * Inputs: + * 0 : Header Code[0x00050000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Available channel bit mask + */ +static void AcquireSoundChannels(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[1] = 0; + cmd_buff[1] = RESULT_SUCCESS.raw; cmd_buff[2] = 0xFFFFFF00; + LOG_WARNING(Service_CSND, "(STUBBED) called"); } -void Shutdown(Service::Interface* self) { - shared_memory = nullptr; - mutex = nullptr; +const Interface::FunctionInfo FunctionTable[] = { + {0x00010140, Initialize, "Initialize"}, + {0x00020000, Shutdown, "Shutdown"}, + {0x00030040, ExecuteCommands, "ExecuteCommands"}, + {0x00040080, nullptr, "ExecuteType1Commands"}, + {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"}, + {0x00060000, nullptr, "ReleaseSoundChannels"}, + {0x00070000, nullptr, "AcquireCaptureDevice"}, + {0x00080040, nullptr, "ReleaseCaptureDevice"}, + {0x00090082, nullptr, "FlushDataCache"}, + {0x000A0082, nullptr, "StoreDataCache"}, + {0x000B0082, nullptr, "InvalidateDataCache"}, + {0x000C0000, nullptr, "Reset"}, +}; + +CSND_SND::CSND_SND() { + Register(FunctionTable); } -} // namespace +} // namespace CSND +} // namespace Service diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h index a146d116b..ca6d4513e 100644 --- a/src/core/hle/service/csnd_snd.h +++ b/src/core/hle/service/csnd_snd.h @@ -6,31 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CSND_SND +namespace Service { +namespace CSND { -namespace CSND_SND { - -class Interface : public Service::Interface { +class CSND_SND final : public Interface { public: - Interface(); + CSND_SND(); std::string GetPortName() const override { return "csnd:SND"; } }; -struct Type0Command { - // command id and next command offset - u32 command_id; - u32 finished; - u32 flags; - u8 parameters[20]; -}; - -void Initialize(Service::Interface* self); -void ExecuteType0Commands(Service::Interface* self); -void AcquireSoundChannels(Service::Interface* self); -void Shutdown(Service::Interface* self); - -} // namespace +} // namespace CSND +} // namespace Service diff --git a/src/core/hle/service/dlp/dlp.h b/src/core/hle/service/dlp/dlp.h index ec2fe46e8..3185fe322 100644 --- a/src/core/hle/service/dlp/dlp.h +++ b/src/core/hle/service/dlp/dlp.h @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#pragma once + namespace Service { namespace DLP { diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp index 49d5b8d1c..25c07f401 100644 --- a/src/core/hle/service/dlp/dlp_srvr.cpp +++ b/src/core/hle/service/dlp/dlp_srvr.cpp @@ -22,7 +22,14 @@ static void unk_0x000E0040(Interface* self) { const Interface::FunctionInfo FunctionTable[] = { {0x00010183, nullptr, "Initialize"}, {0x00020000, nullptr, "Finalize"}, + {0x00030000, nullptr, "GetServerState"}, + {0x00050080, nullptr, "StartAccepting"}, + {0x00070000, nullptr, "StartDistribution"}, {0x000800C0, nullptr, "SendWirelessRebootPassphrase"}, + {0x00090040, nullptr, "AcceptClient"}, + {0x000B0042, nullptr, "GetConnectingClients"}, + {0x000C0040, nullptr, "GetClientInfo"}, + {0x000D0040, nullptr, "GetClientState"}, {0x000E0040, unk_0x000E0040, "unk_0x000E0040"}, }; diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index a15aa3696..fe8a6c2d6 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -12,9 +12,7 @@ using DspPipe = DSP::HLE::DspPipe; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace DSP_DSP - +namespace Service { namespace DSP_DSP { static Kernel::SharedPtr<Kernel::Event> semaphore_event; @@ -582,4 +580,5 @@ Interface::~Interface() { interrupt_events = {}; } -} // namespace +} // namespace DSP_DSP +} // namespace Service diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h index 3e97da6eb..691d6f716 100644 --- a/src/core/hle/service/dsp_dsp.h +++ b/src/core/hle/service/dsp_dsp.h @@ -13,12 +13,10 @@ enum class DspPipe; } } -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace DSP_DSP - +namespace Service { namespace DSP_DSP { -class Interface : public Service::Interface { +class Interface final : public Service::Interface { public: Interface(); ~Interface() override; @@ -35,3 +33,4 @@ public: void SignalPipeInterrupt(DSP::HLE::DspPipe pipe); } // namespace DSP_DSP +} // namespace Service diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 9905757c7..cd0a1a598 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp @@ -13,10 +13,8 @@ #include "core/hle/result.h" #include "core/hle/service/err_f.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace ERR_F - -namespace ERR_F { +namespace Service { +namespace ERR { enum class FatalErrType : u32 { Generic = 0, @@ -167,7 +165,7 @@ static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) { * 0 : Header code * 1 : Result code */ -static void ThrowFatalError(Service::Interface* self) { +static void ThrowFatalError(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); LOG_CRITICAL(Service_ERR, "Fatal error"); @@ -256,11 +254,9 @@ const Interface::FunctionInfo FunctionTable[] = { // clang-format on }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +ERR_F::ERR_F() { Register(FunctionTable); } -} // namespace +} // namespace ERR +} // namespace Service diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h index 892d8af9b..5b27fc871 100644 --- a/src/core/hle/service/err_f.h +++ b/src/core/hle/service/err_f.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace ERR_F +namespace Service { +namespace ERR { -namespace ERR_F { - -class Interface : public Service::Interface { +class ERR_F final : public Interface { public: - Interface(); + ERR_F(); std::string GetPortName() const override { return "err:f"; } }; -} // namespace +} // namespace ERR +} // namespace Service diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index bef75f5df..6cddc1fdb 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -23,7 +23,7 @@ #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" #include "core/file_sys/file_backend.h" -#include "core/hle/hle.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -45,9 +45,7 @@ struct hash<Service::FS::ArchiveIdCode> { }; } -/// TODO(Subv): Confirm length of these strings -const std::string SYSTEM_ID = "00000000000000000000000000000000"; -const std::string SDCARD_ID = "00000000000000000000000000000000"; +static constexpr Kernel::Handle INVALID_HANDLE{}; namespace Service { namespace FS { @@ -93,7 +91,7 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& File::~File() {} -ResultVal<bool> File::SyncRequest() { +void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); switch (cmd) { @@ -103,8 +101,8 @@ ResultVal<bool> File::SyncRequest() { u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32; u32 length = cmd_buff[3]; u32 address = cmd_buff[5]; - LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address); + LOG_TRACE(Service_FS, "Read %s: offset=0x%llx length=%d address=0x%x", GetName().c_str(), + offset, length, address); if (offset + length > backend->GetSize()) { LOG_ERROR(Service_FS, @@ -116,7 +114,7 @@ ResultVal<bool> File::SyncRequest() { ResultVal<size_t> read = backend->Read(offset, data.size(), data.data()); if (read.Failed()) { cmd_buff[1] = read.Code().raw; - return read.Code(); + return; } Memory::WriteBlock(address, data.data(), *read); cmd_buff[2] = static_cast<u32>(*read); @@ -129,22 +127,22 @@ ResultVal<bool> File::SyncRequest() { u32 length = cmd_buff[3]; u32 flush = cmd_buff[4]; u32 address = cmd_buff[6]; - LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); + LOG_TRACE(Service_FS, "Write %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", + GetName().c_str(), offset, length, address, flush); std::vector<u8> data(length); Memory::ReadBlock(address, data.data(), data.size()); ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); if (written.Failed()) { cmd_buff[1] = written.Code().raw; - return written.Code(); + return; } cmd_buff[2] = static_cast<u32>(*written); break; } case FileCommand::GetSize: { - LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); + LOG_TRACE(Service_FS, "GetSize %s", GetName().c_str()); u64 size = backend->GetSize(); cmd_buff[2] = (u32)size; cmd_buff[3] = size >> 32; @@ -153,14 +151,13 @@ ResultVal<bool> File::SyncRequest() { case FileCommand::SetSize: { u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), - size); + LOG_TRACE(Service_FS, "SetSize %s size=%llu", GetName().c_str(), size); backend->SetSize(size); break; } case FileCommand::Close: { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + LOG_TRACE(Service_FS, "Close %s", GetName().c_str()); backend->Close(); break; } @@ -173,7 +170,11 @@ ResultVal<bool> File::SyncRequest() { case FileCommand::OpenLinkFile: { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); - cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE); + auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); + ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .ValueOr(INVALID_HANDLE); break; } @@ -194,10 +195,9 @@ ResultVal<bool> File::SyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return error; + return; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return MakeResult<bool>(false); } Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, @@ -206,18 +206,16 @@ Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, Directory::~Directory() {} -ResultVal<bool> Directory::SyncRequest() { +void Directory::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); switch (cmd) { - // Read from directory... case DirectoryCommand::Read: { u32 count = cmd_buff[1]; u32 address = cmd_buff[3]; std::vector<FileSys::Entry> entries(count); - LOG_TRACE(Service_FS, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), - count); + LOG_TRACE(Service_FS, "Read %s: count=%d", GetName().c_str(), count); // Number of entries actually read u32 read = backend->Read(entries.size(), entries.data()); @@ -227,7 +225,7 @@ ResultVal<bool> Directory::SyncRequest() { } case DirectoryCommand::Close: { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + LOG_TRACE(Service_FS, "Close %s", GetName().c_str()); backend->Close(); break; } @@ -237,10 +235,9 @@ ResultVal<bool> Directory::SyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return MakeResult<bool>(false); + return; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return MakeResult<bool>(false); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -307,9 +304,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor return RESULT_SUCCESS; } -ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode) { +ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, + const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; @@ -318,8 +315,8 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han if (backend.Failed()) return backend.Code(); - auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path)); - return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); + auto file = std::shared_ptr<File>(new File(backend.MoveFrom(), path)); + return MakeResult<std::shared_ptr<File>>(std::move(file)); } ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { @@ -398,8 +395,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, } } -ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path) { +ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; @@ -408,8 +405,8 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a if (backend.Failed()) return backend.Code(); - auto directory = Kernel::SharedPtr<Directory>(new Directory(backend.MoveFrom(), path)); - return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); + auto directory = std::shared_ptr<Directory>(new Directory(backend.MoveFrom(), path)); + return MakeResult<std::shared_ptr<Directory>>(std::move(directory)); } ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 87089bd92..519c1f3a9 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -8,7 +8,7 @@ #include <string> #include "common/common_types.h" #include "core/file_sys/archive_backend.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" namespace FileSys { @@ -17,9 +17,9 @@ class FileBackend; } /// The unique system identifier hash, also known as ID0 -extern const std::string SYSTEM_ID; +static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"}; /// The scrambled SD card CID, also known as ID1 -extern const std::string SDCARD_ID; +static constexpr char SDCARD_ID[]{"00000000000000000000000000000000"}; namespace Service { namespace FS { @@ -43,33 +43,37 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; typedef u64 ArchiveHandle; -class File : public Kernel::Session { +class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> { public: File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); ~File(); - std::string GetName() const override { + std::string GetName() const { return "Path: " + path.DebugStr(); } - ResultVal<bool> SyncRequest() override; FileSys::Path path; ///< Path of the file u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface + +protected: + void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; }; -class Directory : public Kernel::Session { +class Directory final : public SessionRequestHandler { public: Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); ~Directory(); - std::string GetName() const override { + std::string GetName() const { return "Directory: " + path.DebugStr(); } - ResultVal<bool> SyncRequest() override; FileSys::Path path; ///< Path of the directory std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface + +protected: + void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; }; /** @@ -99,11 +103,11 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor * @param archive_handle Handle to an open Archive object * @param path Path to the File inside of the Archive * @param mode Mode under which to open the File - * @return The opened File object as a Session + * @return The opened File object */ -ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode); +ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, + const FileSys::Mode mode); /** * Delete a File from an Archive @@ -178,10 +182,10 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return The opened Directory object as a Session + * @return The opened Directory object */ -ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path); +ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path); /** * Get the free space in an Archive diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 9ec17b395..337da1387 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -8,6 +8,7 @@ #include "common/logging/log.h" #include "common/scope_exit.h" #include "common/string_util.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -17,7 +18,7 @@ // Namespace FS_User using Kernel::SharedPtr; -using Kernel::Session; +using Kernel::ServerSession; namespace Service { namespace FS { @@ -67,10 +68,16 @@ static void OpenFile(Service::Interface* self) { LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode); + ResultVal<std::shared_ptr<File>> file_res = + OpenFileFromArchive(archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); + std::shared_ptr<File> file = *file_res; + auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -127,10 +134,16 @@ static void OpenFileDirectly(Service::Interface* self) { } SCOPE_EXIT({ CloseArchive(*archive_handle); }); - ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); + ResultVal<std::shared_ptr<File>> file_res = + OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); + std::shared_ptr<File> file = *file_res; + auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", @@ -388,10 +401,16 @@ static void OpenDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size, dir_path.DebugStr().c_str()); - ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); + ResultVal<std::shared_ptr<Directory>> dir_res = + OpenDirectoryFromArchive(archive_handle, dir_path); cmd_buff[1] = dir_res.Code().raw; if (dir_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); + std::shared_ptr<Directory> directory = *dir_res; + auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); + directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) + .MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); @@ -1003,6 +1022,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08680000, nullptr, "GetMediaType"}, {0x08690000, nullptr, "GetNandEraseCount"}, {0x086A0082, nullptr, "ReadNandReport"}, + {0x087A0180, nullptr, "AddSeed"}, + {0x088600C0, nullptr, "CheckUpdatedDat"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 78cb761be..947958703 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -18,13 +18,11 @@ // Main graphics debugger object - TODO: Here is probably not the best place for this GraphicsDebugger g_debugger; -// Beginning address of HW regs -const static u32 REGS_BEGIN = 0x1EB00000; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace GSP_GPU +namespace Service { +namespace GSP { -namespace GSP_GPU { +// Beginning address of HW regs +const u32 REGS_BEGIN = 0x1EB00000; const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED( ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX, ErrorSummary::InvalidArgument, @@ -179,7 +177,7 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr * 2 : number of registers to write sequentially * 4 : pointer to source data array */ -static void WriteHWRegs(Service::Interface* self) { +static void WriteHWRegs(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; @@ -199,7 +197,7 @@ static void WriteHWRegs(Service::Interface* self) { * 4 : pointer to source data array * 6 : pointer to mask array */ -static void WriteHWRegsWithMask(Service::Interface* self) { +static void WriteHWRegsWithMask(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; @@ -211,7 +209,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) { } /// Read a GSP GPU hardware register -static void ReadHWRegs(Service::Interface* self) { +static void ReadHWRegs(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; @@ -298,7 +296,7 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { * Outputs: * 1: Result code */ -static void SetBufferSwap(Service::Interface* self) { +static void SetBufferSwap(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 screen_id = cmd_buff[1]; FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2]; @@ -319,7 +317,7 @@ static void SetBufferSwap(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void FlushDataCache(Service::Interface* self) { +static void FlushDataCache(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 address = cmd_buff[1]; u32 size = cmd_buff[2]; @@ -340,7 +338,7 @@ static void FlushDataCache(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetAxiConfigQoSMode(Service::Interface* self) { +static void SetAxiConfigQoSMode(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 mode = cmd_buff[1]; @@ -359,7 +357,7 @@ static void SetAxiConfigQoSMode(Service::Interface* self) { * 2 : Thread index into GSP command buffer * 4 : Handle to GSP shared memory */ -static void RegisterInterruptRelayQueue(Service::Interface* self) { +static void RegisterInterruptRelayQueue(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 flags = cmd_buff[1]; @@ -391,7 +389,7 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void UnregisterInterruptRelayQueue(Service::Interface* self) { +static void UnregisterInterruptRelayQueue(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); g_thread_id = 0; @@ -592,7 +590,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { * Outputs: * 1: Result code */ -static void SetLcdForceBlack(Service::Interface* self) { +static void SetLcdForceBlack(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); bool enable_black = cmd_buff[1] != 0; @@ -609,7 +607,7 @@ static void SetLcdForceBlack(Service::Interface* self) { } /// This triggers handling of the GX command written to the command buffer in shared memory. -static void TriggerCmdReqQueue(Service::Interface* self) { +static void TriggerCmdReqQueue(Interface* self) { // Iterate through each thread's command queue... for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) { CommandBuffer* command_buffer = (CommandBuffer*)GetCommandBuffer(thread_id); @@ -638,6 +636,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) { * Inputs: * 0: Header 0x00180000 * Outputs: + * 0: Header Code[0x00180240] * 1: Result code * 2: Left framebuffer virtual address for the main screen * 3: Right framebuffer virtual address for the main screen @@ -648,7 +647,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) { * 8: Bottom screen framebuffer format * 9: Bottom screen framebuffer width */ -static void ImportDisplayCaptureInfo(Service::Interface* self) { +static void ImportDisplayCaptureInfo(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0, @@ -660,18 +659,19 @@ static void ImportDisplayCaptureInfo(Service::Interface* self) { FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0); FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1); + cmd_buff[0] = IPC::MakeHeader(0x18, 0x9, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + // Top Screen cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left; cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right; cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format; cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride; - + // Bottom Screen cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left; cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right; cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format; cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride; - cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_GSP, "called"); } @@ -680,7 +680,7 @@ static void ImportDisplayCaptureInfo(Service::Interface* self) { * Outputs: * 1: Result code */ -static void AcquireRight(Service::Interface* self) { +static void AcquireRight(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); gpu_right_acquired = true; @@ -695,7 +695,7 @@ static void AcquireRight(Service::Interface* self) { * Outputs: * 1: Result code */ -static void ReleaseRight(Service::Interface* self) { +static void ReleaseRight(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); gpu_right_acquired = false; @@ -739,10 +739,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x001F0082, nullptr, "StoreDataCache"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +GSP_GPU::GSP_GPU() { Register(FunctionTable); g_interrupt_event = nullptr; @@ -757,10 +754,11 @@ Interface::Interface() { first_initialization = true; } -Interface::~Interface() { +GSP_GPU::~GSP_GPU() { g_interrupt_event = nullptr; g_shared_memory = nullptr; gpu_right_acquired = false; } -} // namespace +} // namespace GSP +} // namespace Service diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h index 79a72f77d..c6e24073b 100644 --- a/src/core/hle/service/gsp_gpu.h +++ b/src/core/hle/service/gsp_gpu.h @@ -11,10 +11,8 @@ #include "core/hle/result.h" #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace GSP_GPU - -namespace GSP_GPU { +namespace Service { +namespace GSP { /// GSP interrupt ID enum class InterruptId : u8 { @@ -176,11 +174,10 @@ struct CommandBuffer { }; static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size"); -/// Interface to "srv:" service -class Interface : public Service::Interface { +class GSP_GPU final : public Interface { public: - Interface(); - ~Interface() override; + GSP_GPU(); + ~GSP_GPU() override; std::string GetPortName() const override { return "gsp::Gpu"; @@ -203,4 +200,6 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info); * @returns FramebufferUpdate Information about the specified framebuffer. */ FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index); -} // namespace + +} // namespace GSP +} // namespace Service diff --git a/src/core/hle/service/gsp_lcd.cpp b/src/core/hle/service/gsp_lcd.cpp index b916dd759..89cb4a3cc 100644 --- a/src/core/hle/service/gsp_lcd.cpp +++ b/src/core/hle/service/gsp_lcd.cpp @@ -4,26 +4,26 @@ #include "core/hle/service/gsp_lcd.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace GSP_LCD - -namespace GSP_LCD { +namespace Service { +namespace GSP { const Interface::FunctionInfo FunctionTable[] = { // clang-format off + {0x000A0080, nullptr, "SetBrightnessRaw"}, + {0x000B0080, nullptr, "SetBrightness"}, {0x000F0000, nullptr, "PowerOnAllBacklights"}, {0x00100000, nullptr, "PowerOffAllBacklights"}, {0x00110040, nullptr, "PowerOnBacklight"}, {0x00120040, nullptr, "PowerOffBacklight"}, {0x00130040, nullptr, "SetLedForceOff"}, + {0x00140000, nullptr, "GetVendor"}, + {0x00150040, nullptr, "GetBrightness"}, // clang-format on }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +GSP_LCD::GSP_LCD() { Register(FunctionTable); } -} // namespace +} // namespace GSP +} // namespace Service diff --git a/src/core/hle/service/gsp_lcd.h b/src/core/hle/service/gsp_lcd.h index 56b3cfe86..e9686a5e7 100644 --- a/src/core/hle/service/gsp_lcd.h +++ b/src/core/hle/service/gsp_lcd.h @@ -6,19 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace GSP_LCD +namespace Service { +namespace GSP { -namespace GSP_LCD { - -/// Interface to "gsp::Lcd" service -class Interface : public Service::Interface { +class GSP_LCD final : public Interface { public: - Interface(); + GSP_LCD(); std::string GetPortName() const override { return "gsp::Lcd"; } }; -} // namespace +} // namespace GSP +} // namespace Service diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 99baded11..676154bd4 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -3,9 +3,9 @@ // Refer to the license.txt file included. #include <cmath> -#include "common/emu_window.h" #include "common/logging/log.h" #include "core/core_timing.h" +#include "core/frontend/emu_window.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" @@ -37,7 +37,8 @@ static int enable_gyroscope_count = 0; // positive means enabled static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { // 30 degree and 60 degree are angular thresholds for directions - constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; + constexpr float TAN30 = 0.577350269f; + constexpr float TAN60 = 1 / TAN30; // a circle pad radius greater than 40 will trigger circle pad direction constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; PadState state; diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp index 3cf62a4b8..b01d6e031 100644 --- a/src/core/hle/service/http_c.cpp +++ b/src/core/hle/service/http_c.cpp @@ -4,10 +4,8 @@ #include "core/hle/service/http_c.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HTTP_C - -namespace HTTP_C { +namespace Service { +namespace HTTP { const Interface::FunctionInfo FunctionTable[] = { {0x00010044, nullptr, "Initialize"}, @@ -55,6 +53,10 @@ const Interface::FunctionInfo FunctionTable[] = { {0x002E0040, nullptr, "DestroyRootCertChain"}, {0x002F0082, nullptr, "RootCertChainAddCert"}, {0x00300080, nullptr, "RootCertChainAddDefaultCert"}, + {0x00310080, nullptr, "RootCertChainRemoveCert"}, + {0x00320084, nullptr, "OpenClientCertContext"}, + {0x00330040, nullptr, "OpenDefaultClientCertContext"}, + {0x00340040, nullptr, "CloseClientCertContext"}, {0x00350186, nullptr, "SetDefaultProxy"}, {0x00360000, nullptr, "ClearDNSCache"}, {0x00370080, nullptr, "SetKeepAlive"}, @@ -62,11 +64,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00390000, nullptr, "Finalize"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +HTTP_C::HTTP_C() { Register(FunctionTable); } -} // namespace +} // namespace HTTP +} // namespace Service diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h index 5ea3d1df3..cff279c02 100644 --- a/src/core/hle/service/http_c.h +++ b/src/core/hle/service/http_c.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HTTP_C +namespace Service { +namespace HTTP { -namespace HTTP_C { - -class Interface : public Service::Interface { +class HTTP_C final : public Interface { public: - Interface(); + HTTP_C(); std::string GetPortName() const override { return "http:C"; } }; -} // namespace +} // namespace HTTP +} // namespace Service diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp index 4d6639ded..7f1731a50 100644 --- a/src/core/hle/service/ir/ir.cpp +++ b/src/core/hle/service/ir/ir.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/ir/ir.h" #include "core/hle/service/ir/ir_rst.h" @@ -36,7 +37,7 @@ void InitializeIrNopShared(Interface* self) { u32 send_buff_size = cmd_buff[4]; u32 unk2 = cmd_buff[5]; u8 baud_rate = cmd_buff[6] & 0xFF; - Handle handle = cmd_buff[8]; + Kernel::Handle handle = cmd_buff[8]; if (Kernel::g_handle_table.IsValid(handle)) { transfer_shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle); diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp index 4f0aa77eb..f78545f37 100644 --- a/src/core/hle/service/ldr_ro/cro_helper.cpp +++ b/src/core/hle/service/ldr_ro/cro_helper.cpp @@ -7,10 +7,8 @@ #include "common/scope_exit.h" #include "core/hle/service/ldr_ro/cro_helper.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace LDR_RO - -namespace LDR_RO { +namespace Service { +namespace LDR { static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument, @@ -1493,4 +1491,5 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const { return std::make_tuple(0, 0); } -} // namespace +} // namespace LDR +} // namespace Service diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h index 6a0d0d3bf..060d5a55f 100644 --- a/src/core/hle/service/ldr_ro/cro_helper.h +++ b/src/core/hle/service/ldr_ro/cro_helper.h @@ -11,10 +11,8 @@ #include "core/hle/result.h" #include "core/memory.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace LDR_RO - -namespace LDR_RO { +namespace Service { +namespace LDR { // GCC versions < 5.0 do not implement std::is_trivially_copyable. // Excluding MSVC because it has weird behaviour for std::is_trivially_copyable. @@ -710,4 +708,5 @@ private: ResultCode ApplyExitRelocations(VAddr crs_address); }; -} // namespace +} // namespace LDR +} // namespace Service diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp index ec183d1f5..8d00a7577 100644 --- a/src/core/hle/service/ldr_ro/ldr_ro.cpp +++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp @@ -12,10 +12,8 @@ #include "core/hle/service/ldr_ro/ldr_ro.h" #include "core/hle/service/ldr_ro/memory_synchronizer.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace LDR_RO - -namespace LDR_RO { +namespace Service { +namespace LDR { static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9 ResultCode(ErrorDescription::AlreadyInitialized, ErrorModule::RO, ErrorSummary::Internal, @@ -71,7 +69,7 @@ static bool VerifyBufferState(VAddr buffer_ptr, u32 size) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void Initialize(Service::Interface* self) { +static void Initialize(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); VAddr crs_buffer_ptr = cmd_buff[1]; u32 crs_size = cmd_buff[2]; @@ -196,7 +194,7 @@ static void Initialize(Service::Interface* self) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void LoadCRR(Service::Interface* self) { +static void LoadCRR(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 crr_buffer_ptr = cmd_buff[1]; u32 crr_size = cmd_buff[2]; @@ -229,7 +227,7 @@ static void LoadCRR(Service::Interface* self) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void UnloadCRR(Service::Interface* self) { +static void UnloadCRR(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 crr_buffer_ptr = cmd_buff[1]; u32 descriptor = cmd_buff[2]; @@ -276,7 +274,7 @@ static void UnloadCRR(Service::Interface* self) { * unified one of two, with an additional parameter link_on_load_bug_fix. * There is a dispatcher template below. */ -static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) { +static void LoadCRO(Interface* self, bool link_on_load_bug_fix) { u32* cmd_buff = Kernel::GetCommandBuffer(); VAddr cro_buffer_ptr = cmd_buff[1]; VAddr cro_address = cmd_buff[2]; @@ -459,7 +457,7 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) { } } - Core::g_app_core->ClearInstructionCache(); + Core::CPU().ClearInstructionCache(); LOG_INFO(Service_LDR, "CRO \"%s\" loaded at 0x%08X, fixed_end=0x%08X", cro.ModuleName().data(), cro_address, cro_address + fix_size); @@ -469,7 +467,7 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) { } template <bool link_on_load_bug_fix> -static void LoadCRO(Service::Interface* self) { +static void LoadCRO(Interface* self) { LoadCRO(self, link_on_load_bug_fix); } @@ -486,7 +484,7 @@ static void LoadCRO(Service::Interface* self) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void UnloadCRO(Service::Interface* self) { +static void UnloadCRO(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); VAddr cro_address = cmd_buff[1]; u32 zero = cmd_buff[2]; @@ -564,7 +562,7 @@ static void UnloadCRO(Service::Interface* self) { memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr); } - Core::g_app_core->ClearInstructionCache(); + Core::CPU().ClearInstructionCache(); cmd_buff[1] = result.raw; } @@ -580,7 +578,7 @@ static void UnloadCRO(Service::Interface* self) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void LinkCRO(Service::Interface* self) { +static void LinkCRO(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); VAddr cro_address = cmd_buff[1]; u32 descriptor = cmd_buff[2]; @@ -626,7 +624,7 @@ static void LinkCRO(Service::Interface* self) { } memory_synchronizer.SynchronizeOriginalMemory(); - Core::g_app_core->ClearInstructionCache(); + Core::CPU().ClearInstructionCache(); cmd_buff[1] = result.raw; } @@ -642,7 +640,7 @@ static void LinkCRO(Service::Interface* self) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void UnlinkCRO(Service::Interface* self) { +static void UnlinkCRO(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); VAddr cro_address = cmd_buff[1]; u32 descriptor = cmd_buff[2]; @@ -688,7 +686,7 @@ static void UnlinkCRO(Service::Interface* self) { } memory_synchronizer.SynchronizeOriginalMemory(); - Core::g_app_core->ClearInstructionCache(); + Core::CPU().ClearInstructionCache(); cmd_buff[1] = result.raw; } @@ -704,7 +702,7 @@ static void UnlinkCRO(Service::Interface* self) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void Shutdown(Service::Interface* self) { +static void Shutdown(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); VAddr crs_buffer_ptr = cmd_buff[1]; u32 descriptor = cmd_buff[2]; @@ -762,14 +760,12 @@ const Interface::FunctionInfo FunctionTable[] = { // clang-format on }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +LDR_RO::LDR_RO() { Register(FunctionTable); loaded_crs = 0; memory_synchronizer.Clear(); } -} // namespace +} // namespace LDR +} // namespace Service diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h index 331637cde..0f6fe7b60 100644 --- a/src/core/hle/service/ldr_ro/ldr_ro.h +++ b/src/core/hle/service/ldr_ro/ldr_ro.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace LDR_RO +namespace Service { +namespace LDR { -namespace LDR_RO { - -class Interface : public Service::Interface { +class LDR_RO final : public Interface { public: - Interface(); + LDR_RO(); std::string GetPortName() const override { return "ldr:ro"; } }; -} // namespace +} // namespace LDR +} // namespace Service diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp index 989887264..0d44bf6bd 100644 --- a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp +++ b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp @@ -6,10 +6,8 @@ #include "common/assert.h" #include "core/hle/service/ldr_ro/memory_synchronizer.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace LDR_RO - -namespace LDR_RO { +namespace Service { +namespace LDR { auto MemorySynchronizer::FindMemoryBlock(VAddr mapping, VAddr original) { auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(), @@ -40,4 +38,5 @@ void MemorySynchronizer::SynchronizeOriginalMemory() { } } -} // namespace +} // namespace LDR +} // namespace Service diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.h b/src/core/hle/service/ldr_ro/memory_synchronizer.h index 883ee4acf..438293a58 100644 --- a/src/core/hle/service/ldr_ro/memory_synchronizer.h +++ b/src/core/hle/service/ldr_ro/memory_synchronizer.h @@ -7,10 +7,8 @@ #include <vector> #include "core/memory.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace LDR_RO - -namespace LDR_RO { +namespace Service { +namespace LDR { /** * This is a work-around before we implement memory aliasing. @@ -40,4 +38,5 @@ private: auto FindMemoryBlock(VAddr mapping, VAddr original); }; -} // namespace +} // namespace LDR +} // namespace Service diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp index 1f851d328..4f1dd2fce 100644 --- a/src/core/hle/service/mic_u.cpp +++ b/src/core/hle/service/mic_u.cpp @@ -4,13 +4,12 @@ #include "common/logging/log.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/mic_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace MIC_U - -namespace MIC_U { +namespace Service { +namespace MIC { enum class Encoding : u8 { PCM8 = 0, @@ -49,10 +48,10 @@ static bool audio_buffer_loop; * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void MapSharedMem(Service::Interface* self) { +static void MapSharedMem(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 size = cmd_buff[1]; - Handle mem_handle = cmd_buff[3]; + Kernel::Handle mem_handle = cmd_buff[3]; shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(mem_handle); if (shared_memory) { shared_memory->name = "MIC_U:shared_memory"; @@ -68,7 +67,7 @@ static void MapSharedMem(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void UnmapSharedMem(Service::Interface* self) { +static void UnmapSharedMem(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -87,7 +86,7 @@ static void UnmapSharedMem(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void StartSampling(Service::Interface* self) { +static void StartSampling(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); encoding = static_cast<Encoding>(cmd_buff[1] & 0xFF); @@ -111,7 +110,7 @@ static void StartSampling(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void AdjustSampling(Service::Interface* self) { +static void AdjustSampling(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); sample_rate = static_cast<SampleRate>(cmd_buff[1] & 0xFF); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -125,7 +124,7 @@ static void AdjustSampling(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void StopSampling(Service::Interface* self) { +static void StopSampling(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error is_sampling = false; @@ -140,7 +139,7 @@ static void StopSampling(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : 0 = sampling, non-zero = sampling */ -static void IsSampling(Service::Interface* self) { +static void IsSampling(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = is_sampling; @@ -155,7 +154,7 @@ static void IsSampling(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 3 : Event handle */ -static void GetBufferFullEvent(Service::Interface* self) { +static void GetBufferFullEvent(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[3] = Kernel::g_handle_table.Create(buffer_full_event).MoveFrom(); @@ -170,7 +169,7 @@ static void GetBufferFullEvent(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetGain(Service::Interface* self) { +static void SetGain(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); mic_gain = cmd_buff[1] & 0xFF; cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -185,7 +184,7 @@ static void SetGain(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : Gain */ -static void GetGain(Service::Interface* self) { +static void GetGain(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = mic_gain; @@ -200,7 +199,7 @@ static void GetGain(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetPower(Service::Interface* self) { +static void SetPower(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); mic_power = static_cast<bool>(cmd_buff[1] & 0xFF); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -215,7 +214,7 @@ static void SetPower(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : Power */ -static void GetPower(Service::Interface* self) { +static void GetPower(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = mic_power; @@ -232,7 +231,7 @@ static void GetPower(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetIirFilterMic(Service::Interface* self) { +static void SetIirFilterMic(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 size = cmd_buff[1]; @@ -250,7 +249,7 @@ static void SetIirFilterMic(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetClamp(Service::Interface* self) { +static void SetClamp(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); clamp = static_cast<bool>(cmd_buff[1] & 0xFF); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -265,7 +264,7 @@ static void SetClamp(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : Clamp (0 = don't clamp, non-zero = clamp) */ -static void GetClamp(Service::Interface* self) { +static void GetClamp(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = clamp; @@ -280,7 +279,7 @@ static void GetClamp(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetAllowShellClosed(Service::Interface* self) { +static void SetAllowShellClosed(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); allow_shell_closed = static_cast<bool>(cmd_buff[1] & 0xFF); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -294,7 +293,7 @@ static void SetAllowShellClosed(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetClientVersion(Service::Interface* self) { +static void SetClientVersion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); const u32 version = cmd_buff[1]; @@ -324,10 +323,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00100040, SetClientVersion, "SetClientVersion"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +MIC_U::MIC_U() { Register(FunctionTable); shared_memory = nullptr; buffer_full_event = @@ -338,9 +334,10 @@ Interface::Interface() { clamp = false; } -Interface::~Interface() { +MIC_U::~MIC_U() { shared_memory = nullptr; buffer_full_event = nullptr; } -} // namespace +} // namespace MIC +} // namespace Service diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h index 1cff7390e..ec2b67ab8 100644 --- a/src/core/hle/service/mic_u.h +++ b/src/core/hle/service/mic_u.h @@ -6,21 +6,18 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace MIC_U +namespace Service { +namespace MIC { -// mic service - -namespace MIC_U { - -class Interface : public Service::Interface { +class MIC_U final : public Interface { public: - Interface(); - ~Interface(); + MIC_U(); + ~MIC_U(); std::string GetPortName() const override { return "mic:u"; } }; -} // namespace +} // namespace MIC +} // namespace Service diff --git a/src/core/hle/service/mvd/mvd.cpp b/src/core/hle/service/mvd/mvd.cpp new file mode 100644 index 000000000..9416fe5d6 --- /dev/null +++ b/src/core/hle/service/mvd/mvd.cpp @@ -0,0 +1,17 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/mvd/mvd.h" +#include "core/hle/service/mvd/mvd_std.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace MVD { + +void Init() { + AddService(new MVD_STD()); +} + +} // namespace MVD +} // namespace Service diff --git a/src/core/hle/service/mvd/mvd.h b/src/core/hle/service/mvd/mvd.h new file mode 100644 index 000000000..7b212e839 --- /dev/null +++ b/src/core/hle/service/mvd/mvd.h @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service { +namespace MVD { + +/// Initializes all MVD services. +void Init(); + +} // namespace MVD +} // namespace Service diff --git a/src/core/hle/service/mvd/mvd_std.cpp b/src/core/hle/service/mvd/mvd_std.cpp new file mode 100644 index 000000000..fd7ca87d3 --- /dev/null +++ b/src/core/hle/service/mvd/mvd_std.cpp @@ -0,0 +1,32 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/mvd/mvd_std.h" + +namespace Service { +namespace MVD { + +const Interface::FunctionInfo FunctionTable[] = { + // clang-format off + {0x00010082, nullptr, "Initialize"}, + {0x00020000, nullptr, "Shutdown"}, + {0x00030300, nullptr, "CalculateWorkBufSize"}, + {0x000400C0, nullptr, "CalculateImageSize"}, + {0x00080142, nullptr, "ProcessNALUnit"}, + {0x00090042, nullptr, "ControlFrameRendering"}, + {0x000A0000, nullptr, "GetStatus"}, + {0x000B0000, nullptr, "GetStatusOther"}, + {0x001D0042, nullptr, "GetConfig"}, + {0x001E0044, nullptr, "SetConfig"}, + {0x001F0902, nullptr, "SetOutputBuffer"}, + {0x00210100, nullptr, "OverrideOutputBuffers"} + // clang-format on +}; + +MVD_STD::MVD_STD() { + Register(FunctionTable); +} + +} // namespace MVD +} // namespace Service diff --git a/src/core/hle/service/mvd/mvd_std.h b/src/core/hle/service/mvd/mvd_std.h new file mode 100644 index 000000000..7db9e2e50 --- /dev/null +++ b/src/core/hle/service/mvd/mvd_std.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace MVD { + +class MVD_STD final : public Interface { +public: + MVD_STD(); + + std::string GetPortName() const override { + return "mvd:std"; + } +}; + +} // namespace MVD +} // namespace Service diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp new file mode 100644 index 000000000..d9738c6a1 --- /dev/null +++ b/src/core/hle/service/nfc/nfc.cpp @@ -0,0 +1,18 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nfc/nfc.h" +#include "core/hle/service/nfc/nfc_m.h" +#include "core/hle/service/nfc/nfc_u.h" + +namespace Service { +namespace NFC { + +void Init() { + AddService(new NFC_M()); + AddService(new NFC_U()); +} + +} // namespace NFC +} // namespace Service diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h new file mode 100644 index 000000000..cd65a5fdc --- /dev/null +++ b/src/core/hle/service/nfc/nfc.h @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service { +namespace NFC { + +/// Initialize all NFC services. +void Init(); + +} // namespace NFC +} // namespace Service diff --git a/src/core/hle/service/nfc/nfc_m.cpp b/src/core/hle/service/nfc/nfc_m.cpp new file mode 100644 index 000000000..717335c11 --- /dev/null +++ b/src/core/hle/service/nfc/nfc_m.cpp @@ -0,0 +1,44 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nfc/nfc_m.h" + +namespace Service { +namespace NFC { + +const Interface::FunctionInfo FunctionTable[] = { + // clang-format off + // nfc:u shared commands + {0x00010040, nullptr, "Initialize"}, + {0x00020040, nullptr, "Shutdown"}, + {0x00030000, nullptr, "StartCommunication"}, + {0x00040000, nullptr, "StopCommunication"}, + {0x00050040, nullptr, "StartTagScanning"}, + {0x00060000, nullptr, "StopTagScanning"}, + {0x00070000, nullptr, "LoadAmiiboData"}, + {0x00080000, nullptr, "ResetTagScanState"}, + {0x00090002, nullptr, "UpdateStoredAmiiboData"}, + {0x000D0000, nullptr, "GetTagState"}, + {0x000F0000, nullptr, "CommunicationGetStatus"}, + {0x00100000, nullptr, "GetTagInfo2"}, + {0x00110000, nullptr, "GetTagInfo"}, + {0x00120000, nullptr, "CommunicationGetResult"}, + {0x00130040, nullptr, "OpenAppData"}, + {0x00140384, nullptr, "InitializeWriteAppData"}, + {0x00150040, nullptr, "ReadAppData"}, + {0x00160242, nullptr, "WriteAppData"}, + {0x00170000, nullptr, "GetAmiiboSettings"}, + {0x00180000, nullptr, "GetAmiiboConfig"}, + {0x00190000, nullptr, "GetAppDataInitStruct"}, + // nfc:m + {0x04040A40, nullptr, "SetAmiiboSettings"} + // clang-format on +}; + +NFC_M::NFC_M() { + Register(FunctionTable); +} + +} // namespace NFC +} // namespace Service diff --git a/src/core/hle/service/nfc/nfc_m.h b/src/core/hle/service/nfc/nfc_m.h new file mode 100644 index 000000000..fae75535b --- /dev/null +++ b/src/core/hle/service/nfc/nfc_m.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NFC { + +class NFC_M final : public Interface { +public: + NFC_M(); + + std::string GetPortName() const override { + return "nfc:m"; + } +}; + +} // namespace NFC +} // namespace Service diff --git a/src/core/hle/service/nfc/nfc_u.cpp b/src/core/hle/service/nfc/nfc_u.cpp new file mode 100644 index 000000000..deffb0b4f --- /dev/null +++ b/src/core/hle/service/nfc/nfc_u.cpp @@ -0,0 +1,41 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nfc/nfc_u.h" + +namespace Service { +namespace NFC { + +const Interface::FunctionInfo FunctionTable[] = { + // clang-format off + {0x00010040, nullptr, "Initialize"}, + {0x00020040, nullptr, "Shutdown"}, + {0x00030000, nullptr, "StartCommunication"}, + {0x00040000, nullptr, "StopCommunication"}, + {0x00050040, nullptr, "StartTagScanning"}, + {0x00060000, nullptr, "StopTagScanning"}, + {0x00070000, nullptr, "LoadAmiiboData"}, + {0x00080000, nullptr, "ResetTagScanState"}, + {0x00090002, nullptr, "UpdateStoredAmiiboData"}, + {0x000D0000, nullptr, "GetTagState"}, + {0x000F0000, nullptr, "CommunicationGetStatus"}, + {0x00100000, nullptr, "GetTagInfo2"}, + {0x00110000, nullptr, "GetTagInfo"}, + {0x00120000, nullptr, "CommunicationGetResult"}, + {0x00130040, nullptr, "OpenAppData"}, + {0x00140384, nullptr, "InitializeWriteAppData"}, + {0x00150040, nullptr, "ReadAppData"}, + {0x00160242, nullptr, "WriteAppData"}, + {0x00170000, nullptr, "GetAmiiboSettings"}, + {0x00180000, nullptr, "GetAmiiboConfig"}, + {0x00190000, nullptr, "GetAppDataInitStruct"}, + // clang-format on +}; + +NFC_U::NFC_U() { + Register(FunctionTable); +} + +} // namespace NFC +} // namespace Service diff --git a/src/core/hle/service/nfc/nfc_u.h b/src/core/hle/service/nfc/nfc_u.h new file mode 100644 index 000000000..eb7507314 --- /dev/null +++ b/src/core/hle/service/nfc/nfc_u.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NFC { + +class NFC_U final : public Interface { +public: + NFC_U(); + + std::string GetPortName() const override { + return "nfc:u"; + } +}; + +} // namespace NFC +} // namespace Service diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp index e2ba693c9..28b87e6f7 100644 --- a/src/core/hle/service/nim/nim_s.cpp +++ b/src/core/hle/service/nim/nim_s.cpp @@ -10,6 +10,7 @@ namespace NIM { const Interface::FunctionInfo FunctionTable[] = { {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"}, {0x0016020A, nullptr, "ListTitles"}, + {0x00290000, nullptr, "AccountCheckBalanceSOAP"}, {0x002D0042, nullptr, "DownloadTickets"}, {0x00420240, nullptr, "StartDownload"}, }; diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp index 7e07d02e8..7664bad60 100644 --- a/src/core/hle/service/nim/nim_u.cpp +++ b/src/core/hle/service/nim/nim_u.cpp @@ -15,6 +15,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00050000, nullptr, "CheckForSysUpdateEvent"}, {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, {0x000A0000, nullptr, "GetState"}, + {0x000B0000, nullptr, "GetSystemTitleHash"}, }; NIM_U_Interface::NIM_U_Interface() { diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp index 6693f7c08..215c9aacc 100644 --- a/src/core/hle/service/ns_s.cpp +++ b/src/core/hle/service/ns_s.cpp @@ -4,10 +4,8 @@ #include "core/hle/service/ns_s.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NS_S - -namespace NS_S { +namespace Service { +namespace NS { const Interface::FunctionInfo FunctionTable[] = { {0x000100C0, nullptr, "LaunchFIRM"}, @@ -27,11 +25,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00160000, nullptr, "RebootSystemClean"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +NS_S::NS_S() { Register(FunctionTable); } -} // namespace +} // namespace NS +} // namespace Service diff --git a/src/core/hle/service/ns_s.h b/src/core/hle/service/ns_s.h index 8d8e849b8..90288a521 100644 --- a/src/core/hle/service/ns_s.h +++ b/src/core/hle/service/ns_s.h @@ -6,19 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NS_S +namespace Service { +namespace NS { -namespace NS_S { - -/// Interface to "NS:S" service -class Interface : public Service::Interface { +class NS_S final : public Interface { public: - Interface(); + NS_S(); std::string GetPortName() const override { return "ns:s"; } }; -} // namespace +} // namespace NS +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm.cpp b/src/core/hle/service/nwm/nwm.cpp new file mode 100644 index 000000000..9f1994dc3 --- /dev/null +++ b/src/core/hle/service/nwm/nwm.cpp @@ -0,0 +1,28 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm.h" +#include "core/hle/service/nwm/nwm_cec.h" +#include "core/hle/service/nwm/nwm_ext.h" +#include "core/hle/service/nwm/nwm_inf.h" +#include "core/hle/service/nwm/nwm_sap.h" +#include "core/hle/service/nwm/nwm_soc.h" +#include "core/hle/service/nwm/nwm_tst.h" +#include "core/hle/service/nwm/nwm_uds.h" + +namespace Service { +namespace NWM { + +void Init() { + AddService(new NWM_CEC); + AddService(new NWM_EXT); + AddService(new NWM_INF); + AddService(new NWM_SAP); + AddService(new NWM_SOC); + AddService(new NWM_TST); + AddService(new NWM_UDS); +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm.h b/src/core/hle/service/nwm/nwm.h new file mode 100644 index 000000000..6926b29a6 --- /dev/null +++ b/src/core/hle/service/nwm/nwm.h @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service { +namespace NWM { + +/// Initialize all NWM services +void Init(); + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_cec.cpp b/src/core/hle/service/nwm/nwm_cec.cpp new file mode 100644 index 000000000..7f03987df --- /dev/null +++ b/src/core/hle/service/nwm/nwm_cec.cpp @@ -0,0 +1,19 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm_cec.h" + +namespace Service { +namespace NWM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000D0082, nullptr, "SendProbeRequest"}, +}; + +NWM_CEC::NWM_CEC() { + Register(FunctionTable); +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_cec.h b/src/core/hle/service/nwm/nwm_cec.h new file mode 100644 index 000000000..07b6addb5 --- /dev/null +++ b/src/core/hle/service/nwm/nwm_cec.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +class NWM_CEC final : public Interface { +public: + NWM_CEC(); + + std::string GetPortName() const override { + return "nwm::CEC"; + } +}; + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_ext.cpp b/src/core/hle/service/nwm/nwm_ext.cpp new file mode 100644 index 000000000..605640a13 --- /dev/null +++ b/src/core/hle/service/nwm/nwm_ext.cpp @@ -0,0 +1,19 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm_ext.h" + +namespace Service { +namespace NWM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00080040, nullptr, "ControlWirelessEnabled"}, +}; + +NWM_EXT::NWM_EXT() { + Register(FunctionTable); +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_ext.h b/src/core/hle/service/nwm/nwm_ext.h new file mode 100644 index 000000000..51d39d9ea --- /dev/null +++ b/src/core/hle/service/nwm/nwm_ext.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +class NWM_EXT final : public Interface { +public: + NWM_EXT(); + + std::string GetPortName() const override { + return "nwm::EXT"; + } +}; + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_inf.cpp b/src/core/hle/service/nwm/nwm_inf.cpp new file mode 100644 index 000000000..c8470589b --- /dev/null +++ b/src/core/hle/service/nwm/nwm_inf.cpp @@ -0,0 +1,21 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm_inf.h" + +namespace Service { +namespace NWM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000603C4, nullptr, "RecvBeaconBroadcastData"}, + {0x00070742, nullptr, "ConnectToEncryptedAP"}, + {0x00080302, nullptr, "ConnectToAP"}, +}; + +NWM_INF::NWM_INF() { + Register(FunctionTable); +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_inf.h b/src/core/hle/service/nwm/nwm_inf.h new file mode 100644 index 000000000..0043d769c --- /dev/null +++ b/src/core/hle/service/nwm/nwm_inf.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +class NWM_INF final : public Interface { +public: + NWM_INF(); + + std::string GetPortName() const override { + return "nwm::INF"; + } +}; + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_sap.cpp b/src/core/hle/service/nwm/nwm_sap.cpp new file mode 100644 index 000000000..fd29ed761 --- /dev/null +++ b/src/core/hle/service/nwm/nwm_sap.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm_sap.h" + +namespace Service { +namespace NWM { + +/* +const Interface::FunctionInfo FunctionTable[] = { +}; +*/ + +NWM_SAP::NWM_SAP() { + // Register(FunctionTable); +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_sap.h b/src/core/hle/service/nwm/nwm_sap.h new file mode 100644 index 000000000..f692e06d4 --- /dev/null +++ b/src/core/hle/service/nwm/nwm_sap.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +class NWM_SAP final : public Interface { +public: + NWM_SAP(); + + std::string GetPortName() const override { + return "nwm::SAP"; + } +}; + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_soc.cpp b/src/core/hle/service/nwm/nwm_soc.cpp new file mode 100644 index 000000000..fdffcb925 --- /dev/null +++ b/src/core/hle/service/nwm/nwm_soc.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm_soc.h" + +namespace Service { +namespace NWM { + +/* +const Interface::FunctionInfo FunctionTable[] = { +}; +*/ + +NWM_SOC::NWM_SOC() { + // Register(FunctionTable); +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_soc.h b/src/core/hle/service/nwm/nwm_soc.h new file mode 100644 index 000000000..594941d7e --- /dev/null +++ b/src/core/hle/service/nwm/nwm_soc.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +class NWM_SOC final : public Interface { +public: + NWM_SOC(); + + std::string GetPortName() const override { + return "nwm::SOC"; + } +}; + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_tst.cpp b/src/core/hle/service/nwm/nwm_tst.cpp new file mode 100644 index 000000000..5f292e5db --- /dev/null +++ b/src/core/hle/service/nwm/nwm_tst.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm_tst.h" + +namespace Service { +namespace NWM { + +/* +const Interface::FunctionInfo FunctionTable[] = { +}; +*/ + +NWM_TST::NWM_TST() { + // Register(FunctionTable); +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/nwm_tst.h b/src/core/hle/service/nwm/nwm_tst.h new file mode 100644 index 000000000..8deca3216 --- /dev/null +++ b/src/core/hle/service/nwm/nwm_tst.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +class NWM_TST final : public Interface { +public: + NWM_TST(); + + std::string GetPortName() const override { + return "nwm::TST"; + } +}; + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 80081aae2..08fade320 100644 --- a/src/core/hle/service/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -5,14 +5,12 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/kernel/event.h" -#include "core/hle/service/nwm_uds.h" +#include "core/hle/service/nwm/nwm_uds.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NWM_UDS +namespace Service { +namespace NWM { -namespace NWM_UDS { - -static Kernel::SharedPtr<Kernel::Event> handle_event; +static Kernel::SharedPtr<Kernel::Event> uds_handle_event; /** * NWM_UDS::Shutdown service function @@ -22,7 +20,7 @@ static Kernel::SharedPtr<Kernel::Event> handle_event; * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void Shutdown(Service::Interface* self) { +static void Shutdown(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(purpasmart): Verify return header on HW @@ -50,7 +48,7 @@ static void Shutdown(Service::Interface* self) { * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code */ -static void RecvBeaconBroadcastData(Service::Interface* self) { +static void RecvBeaconBroadcastData(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 out_buffer_size = cmd_buff[1]; u32 unk1 = cmd_buff[2]; @@ -90,7 +88,7 @@ static void RecvBeaconBroadcastData(Service::Interface* self) { * 2 : Value 0 * 3 : Output handle */ -static void Initialize(Service::Interface* self) { +static void InitializeWithVersion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 unk1 = cmd_buff[1]; u32 unk2 = cmd_buff[12]; @@ -103,7 +101,7 @@ static void Initialize(Service::Interface* self) { /* cmd_buff[1] = RESULT_SUCCESS.raw; cmd_buff[2] = 0; - cmd_buff[3] = Kernel::g_handle_table.Create(handle_event) + cmd_buff[3] = Kernel::g_handle_table.Create(uds_handle_event) .MoveFrom(); // TODO(purpasmart): Verify if this is a event handle */ cmd_buff[0] = IPC::MakeHeader(0x1B, 1, 2); @@ -118,26 +116,29 @@ static void Initialize(Service::Interface* self) { } const Interface::FunctionInfo FunctionTable[] = { + {0x00010442, nullptr, "Initialize (deprecated)"}, {0x00020000, nullptr, "Scrap"}, {0x00030000, Shutdown, "Shutdown"}, - {0x00040402, nullptr, "CreateNetwork"}, + {0x00040402, nullptr, "CreateNetwork (deprecated)"}, {0x00050040, nullptr, "EjectClient"}, {0x00060000, nullptr, "EjectSpectator"}, {0x00070080, nullptr, "UpdateNetworkAttribute"}, {0x00080000, nullptr, "DestroyNetwork"}, + {0x00090442, nullptr, "ConnectNetwork (deprecated)"}, {0x000A0000, nullptr, "DisconnectNetwork"}, {0x000B0000, nullptr, "GetConnectionStatus"}, {0x000D0040, nullptr, "GetNodeInformation"}, + {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"}, {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, - {0x00100042, nullptr, "SetBeaconAdditionalData"}, + {0x00100042, nullptr, "SetApplicationData"}, {0x00110040, nullptr, "GetApplicationData"}, {0x00120100, nullptr, "Bind"}, {0x00130040, nullptr, "Unbind"}, - {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, + {0x001400C0, nullptr, "PullPacket"}, {0x00150080, nullptr, "SetMaxSendDelay"}, {0x00170182, nullptr, "SendTo"}, {0x001A0000, nullptr, "GetChannel"}, - {0x001B0302, Initialize, "Initialize"}, + {0x001B0302, InitializeWithVersion, "InitializeWithVersion"}, {0x001D0044, nullptr, "BeginHostingNetwork"}, {0x001E0084, nullptr, "ConnectToNetwork"}, {0x001F0006, nullptr, "DecryptBeaconData"}, @@ -146,17 +147,15 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00220402, nullptr, "ScanOnConnection"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - handle_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM_UDS::handle_event"); +NWM_UDS::NWM_UDS() { + uds_handle_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::uds_handle_event"); Register(FunctionTable); } -Interface::~Interface() { - handle_event = nullptr; +NWM_UDS::~NWM_UDS() { + uds_handle_event = nullptr; } -} // namespace +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index 0ced2359c..55db748f6 100644 --- a/src/core/hle/service/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -6,21 +6,20 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NWM_UDS +// Local-WLAN service -// local-WLAN service +namespace Service { +namespace NWM { -namespace NWM_UDS { - -class Interface : public Service::Interface { +class NWM_UDS final : public Interface { public: - Interface(); - ~Interface() override; + NWM_UDS(); + ~NWM_UDS() override; std::string GetPortName() const override { return "nwm::UDS"; } }; -} // namespace +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp index 7d91694f6..caa16f952 100644 --- a/src/core/hle/service/pm_app.cpp +++ b/src/core/hle/service/pm_app.cpp @@ -4,31 +4,30 @@ #include "core/hle/service/pm_app.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PM_APP - -namespace PM_APP { +namespace Service { +namespace PM { const Interface::FunctionInfo FunctionTable[] = { + // clang-format off {0x00010140, nullptr, "LaunchTitle"}, - {0x00020082, nullptr, "LaunchFIRMSetParams"}, - {0x00030080, nullptr, "TerminateProcesse"}, - {0x00040100, nullptr, "TerminateProcessTID"}, - {0x000500C0, nullptr, "TerminateProcessTID_unknown"}, + {0x00020082, nullptr, "LaunchFIRM"}, + {0x00030080, nullptr, "TerminateApplication"}, + {0x00040100, nullptr, "TerminateTitle"}, + {0x000500C0, nullptr, "TerminateProcess"}, + {0x00060082, nullptr, "PrepareForReboot"}, {0x00070042, nullptr, "GetFIRMLaunchParams"}, {0x00080100, nullptr, "GetTitleExheaderFlags"}, {0x00090042, nullptr, "SetFIRMLaunchParams"}, - {0x000A0140, nullptr, "SetResourceLimit"}, - {0x000B0140, nullptr, "GetResourceLimitMax"}, + {0x000A0140, nullptr, "SetAppResourceLimit"}, + {0x000B0140, nullptr, "GetAppResourceLimit"}, {0x000C0080, nullptr, "UnregisterProcess"}, {0x000D0240, nullptr, "LaunchTitleUpdate"}, + // clang-format on }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +PM_APP::PM_APP() { Register(FunctionTable); } -} // namespace +} // namespace PM +} // namespace Service diff --git a/src/core/hle/service/pm_app.h b/src/core/hle/service/pm_app.h index c1fb1f9da..151c69f3d 100644 --- a/src/core/hle/service/pm_app.h +++ b/src/core/hle/service/pm_app.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace PM_APP +namespace Service { +namespace PM { -namespace PM_APP { - -class Interface : public Service::Interface { +class PM_APP final : public Interface { public: - Interface(); + PM_APP(); std::string GetPortName() const override { return "pm:app"; } }; -} // namespace +} // namespace PM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index cc859c14c..8ff808fd9 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp @@ -6,7 +6,9 @@ #include "core/file_sys/file_backend.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/ptm/ptm.h" +#include "core/hle/service/ptm/ptm_gets.h" #include "core/hle/service/ptm/ptm_play.h" +#include "core/hle/service/ptm/ptm_sets.h" #include "core/hle/service/ptm/ptm_sysm.h" #include "core/hle/service/ptm/ptm_u.h" #include "core/hle/service/service.h" @@ -81,7 +83,7 @@ void GetTotalStepCount(Service::Interface* self) { LOG_WARNING(Service_PTM, "(STUBBED) called"); } -void IsLegacyPowerOff(Service::Interface* self) { +void GetSoftwareClosedFlag(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; @@ -106,9 +108,12 @@ void CheckNew3DS(Service::Interface* self) { } void Init() { - AddService(new PTM_Play_Interface); - AddService(new PTM_Sysm_Interface); - AddService(new PTM_U_Interface); + AddService(new PTM_Gets); + AddService(new PTM_Play); + AddService(new PTM_S); + AddService(new PTM_Sets); + AddService(new PTM_Sysm); + AddService(new PTM_U); shell_open = true; battery_is_charging = true; @@ -137,7 +142,7 @@ void Init() { Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); if (gamecoin_result.Succeeded()) { auto gamecoin = gamecoin_result.MoveFrom(); - gamecoin->backend->Write(0, sizeof(GameCoin), 1, + gamecoin->backend->Write(0, sizeof(GameCoin), true, reinterpret_cast<const u8*>(&default_game_coin)); gamecoin->backend->Close(); } diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index 6e163a6f9..a1a628012 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h @@ -82,12 +82,13 @@ void GetBatteryChargeState(Interface* self); void GetTotalStepCount(Interface* self); /** - * PTM::IsLegacyPowerOff service function + * PTM::GetSoftwareClosedFlag service function * Outputs: * 1: Result code, 0 on success, otherwise error code - * 2: Whether the system is going through a power off + * 2: Whether or not the "software closed" dialog was requested by the last FIRM + * and should be displayed. */ -void IsLegacyPowerOff(Interface* self); +void GetSoftwareClosedFlag(Interface* self); /** * PTM::CheckNew3DS service function diff --git a/src/core/hle/service/ptm/ptm_gets.cpp b/src/core/hle/service/ptm/ptm_gets.cpp new file mode 100644 index 000000000..b23e508d6 --- /dev/null +++ b/src/core/hle/service/ptm/ptm_gets.cpp @@ -0,0 +1,37 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/ptm/ptm.h" +#include "core/hle/service/ptm/ptm_gets.h" + +namespace Service { +namespace PTM { + +const Interface::FunctionInfo FunctionTable[] = { + // ptm:u common commands + {0x00010002, nullptr, "RegisterAlarmClient"}, + {0x00020080, nullptr, "SetRtcAlarm"}, + {0x00030000, nullptr, "GetRtcAlarm"}, + {0x00040000, nullptr, "CancelRtcAlarm"}, + {0x00050000, GetAdapterState, "GetAdapterState"}, + {0x00060000, GetShellState, "GetShellState"}, + {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, + {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, + {0x00090000, nullptr, "GetPedometerState"}, + {0x000A0042, nullptr, "GetStepHistoryEntry"}, + {0x000B00C2, nullptr, "GetStepHistory"}, + {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, + {0x000D0040, nullptr, "SetPedometerRecordingMode"}, + {0x000E0000, nullptr, "GetPedometerRecordingMode"}, + {0x000F0084, nullptr, "GetStepHistoryAll"}, + // ptm:gets + {0x04010000, nullptr, "GetSystemTime"}, +}; + +PTM_Gets::PTM_Gets() { + Register(FunctionTable); +} + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm_gets.h b/src/core/hle/service/ptm/ptm_gets.h new file mode 100644 index 000000000..5552c9eff --- /dev/null +++ b/src/core/hle/service/ptm/ptm_gets.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace PTM { + +class PTM_Gets final : public Interface { +public: + PTM_Gets(); + + std::string GetPortName() const override { + return "ptm:gets"; + } +}; + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp index 2e0c6e1a3..bcb00e0d4 100644 --- a/src/core/hle/service/ptm/ptm_play.cpp +++ b/src/core/hle/service/ptm/ptm_play.cpp @@ -2,19 +2,37 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/service/ptm/ptm.h" #include "core/hle/service/ptm/ptm_play.h" namespace Service { namespace PTM { const Interface::FunctionInfo FunctionTable[] = { + // ptm:u common commands + {0x00010002, nullptr, "RegisterAlarmClient"}, + {0x00020080, nullptr, "SetRtcAlarm"}, + {0x00030000, nullptr, "GetRtcAlarm"}, + {0x00040000, nullptr, "CancelRtcAlarm"}, + {0x00050000, GetAdapterState, "GetAdapterState"}, + {0x00060000, GetShellState, "GetShellState"}, + {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, + {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, + {0x00090000, nullptr, "GetPedometerState"}, + {0x000A0042, nullptr, "GetStepHistoryEntry"}, + {0x000B00C2, nullptr, "GetStepHistory"}, + {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, + {0x000D0040, nullptr, "SetPedometerRecordingMode"}, + {0x000E0000, nullptr, "GetPedometerRecordingMode"}, + {0x000F0084, nullptr, "GetStepHistoryAll"}, + // ptm:play {0x08070082, nullptr, "GetPlayHistory"}, {0x08080000, nullptr, "GetPlayHistoryStart"}, {0x08090000, nullptr, "GetPlayHistoryLength"}, {0x080B0080, nullptr, "CalcPlayHistoryStart"}, }; -PTM_Play_Interface::PTM_Play_Interface() { +PTM_Play::PTM_Play() { Register(FunctionTable); } diff --git a/src/core/hle/service/ptm/ptm_play.h b/src/core/hle/service/ptm/ptm_play.h index 47f229581..663faabee 100644 --- a/src/core/hle/service/ptm/ptm_play.h +++ b/src/core/hle/service/ptm/ptm_play.h @@ -9,9 +9,9 @@ namespace Service { namespace PTM { -class PTM_Play_Interface : public Service::Interface { +class PTM_Play final : public Interface { public: - PTM_Play_Interface(); + PTM_Play(); std::string GetPortName() const override { return "ptm:play"; diff --git a/src/core/hle/service/ptm/ptm_sets.cpp b/src/core/hle/service/ptm/ptm_sets.cpp new file mode 100644 index 000000000..a8c6cf227 --- /dev/null +++ b/src/core/hle/service/ptm/ptm_sets.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/ptm/ptm_sets.h" + +namespace Service { +namespace PTM { + +const Interface::FunctionInfo FunctionTable[] = { + // Note that this service does not have access to ptm:u's common commands + {0x00010080, nullptr, "SetSystemTime"}, +}; + +PTM_Sets::PTM_Sets() { + Register(FunctionTable); +} + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm_sets.h b/src/core/hle/service/ptm/ptm_sets.h new file mode 100644 index 000000000..d33b047e5 --- /dev/null +++ b/src/core/hle/service/ptm/ptm_sets.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace PTM { + +class PTM_Sets final : public Interface { +public: + PTM_Sets(); + + std::string GetPortName() const override { + return "ptm:sets"; + } +}; + +} // namespace PTM +} // namespace Service diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp index 693158dbf..f95dfdbb1 100644 --- a/src/core/hle/service/ptm/ptm_sysm.cpp +++ b/src/core/hle/service/ptm/ptm_sysm.cpp @@ -9,6 +9,23 @@ namespace Service { namespace PTM { const Interface::FunctionInfo FunctionTable[] = { + // ptm:u common commands + {0x00010002, nullptr, "RegisterAlarmClient"}, + {0x00020080, nullptr, "SetRtcAlarm"}, + {0x00030000, nullptr, "GetRtcAlarm"}, + {0x00040000, nullptr, "CancelRtcAlarm"}, + {0x00050000, GetAdapterState, "GetAdapterState"}, + {0x00060000, GetShellState, "GetShellState"}, + {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, + {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, + {0x00090000, nullptr, "GetPedometerState"}, + {0x000A0042, nullptr, "GetStepHistoryEntry"}, + {0x000B00C2, nullptr, "GetStepHistory"}, + {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, + {0x000D0040, nullptr, "SetPedometerRecordingMode"}, + {0x000E0000, nullptr, "GetPedometerRecordingMode"}, + {0x000F0084, nullptr, "GetStepHistoryAll"}, + // ptm:sysm {0x040100C0, nullptr, "SetRtcAlarmEx"}, {0x04020042, nullptr, "ReplySleepQuery"}, {0x04030042, nullptr, "NotifySleepPreparationComplete"}, @@ -33,8 +50,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x080C0080, nullptr, "SetUserTime"}, {0x080D0000, nullptr, "InvalidateSystemTime"}, {0x080E0140, nullptr, "NotifyPlayEvent"}, - {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"}, - {0x08100000, nullptr, "ClearLegacyPowerOff"}, + {0x080F0000, GetSoftwareClosedFlag, "GetSoftwareClosedFlag"}, + {0x08100000, nullptr, "ClearSoftwareClosedFlag"}, {0x08110000, GetShellState, "GetShellState"}, {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, {0x08130000, nullptr, "FormatSavedata"}, @@ -42,7 +59,11 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08180040, nullptr, "ConfigureNew3DSCPU"}, }; -PTM_Sysm_Interface::PTM_Sysm_Interface() { +PTM_S::PTM_S() { + Register(FunctionTable); +} + +PTM_Sysm::PTM_Sysm() { Register(FunctionTable); } diff --git a/src/core/hle/service/ptm/ptm_sysm.h b/src/core/hle/service/ptm/ptm_sysm.h index e37f20546..8afcebbba 100644 --- a/src/core/hle/service/ptm/ptm_sysm.h +++ b/src/core/hle/service/ptm/ptm_sysm.h @@ -9,9 +9,18 @@ namespace Service { namespace PTM { -class PTM_Sysm_Interface : public Interface { +class PTM_S final : public Interface { public: - PTM_Sysm_Interface(); + PTM_S(); + + std::string GetPortName() const override { + return "ptm:s"; + } +}; + +class PTM_Sysm final : public Interface { +public: + PTM_Sysm(); std::string GetPortName() const override { return "ptm:sysm"; diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp index 65e868393..e0b65ba89 100644 --- a/src/core/hle/service/ptm/ptm_u.cpp +++ b/src/core/hle/service/ptm/ptm_u.cpp @@ -26,7 +26,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000F0084, nullptr, "GetStepHistoryAll"}, }; -PTM_U_Interface::PTM_U_Interface() { +PTM_U::PTM_U() { Register(FunctionTable); } diff --git a/src/core/hle/service/ptm/ptm_u.h b/src/core/hle/service/ptm/ptm_u.h index bf132f610..7b75d6e49 100644 --- a/src/core/hle/service/ptm/ptm_u.h +++ b/src/core/hle/service/ptm/ptm_u.h @@ -9,9 +9,9 @@ namespace Service { namespace PTM { -class PTM_U_Interface : public Interface { +class PTM_U final : public Interface { public: - PTM_U_Interface(); + PTM_U(); std::string GetPortName() const override { return "ptm:u"; diff --git a/src/core/hle/service/qtm/qtm.cpp b/src/core/hle/service/qtm/qtm.cpp new file mode 100644 index 000000000..f11542263 --- /dev/null +++ b/src/core/hle/service/qtm/qtm.cpp @@ -0,0 +1,21 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/qtm/qtm.h" +#include "core/hle/service/qtm/qtm_s.h" +#include "core/hle/service/qtm/qtm_sp.h" +#include "core/hle/service/qtm/qtm_u.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace QTM { + +void Init() { + AddService(new QTM_S()); + AddService(new QTM_SP()); + AddService(new QTM_U()); +} + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/qtm/qtm.h b/src/core/hle/service/qtm/qtm.h new file mode 100644 index 000000000..33b774c79 --- /dev/null +++ b/src/core/hle/service/qtm/qtm.h @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service { +namespace QTM { + +/// Initializes all QTM services. +void Init(); + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/qtm/qtm_s.cpp b/src/core/hle/service/qtm/qtm_s.cpp new file mode 100644 index 000000000..ad7df24a0 --- /dev/null +++ b/src/core/hle/service/qtm/qtm_s.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/qtm/qtm_s.h" + +namespace Service { +namespace QTM { + +const Interface::FunctionInfo FunctionTable[] = { + // clang-format off + // qtm common commands + {0x00010080, nullptr, "GetHeadtrackingInfoRaw"}, + {0x00020080, nullptr, "GetHeadtrackingInfo"}, + // clang-format on +}; + +QTM_S::QTM_S() { + Register(FunctionTable); +} + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/qtm/qtm_s.h b/src/core/hle/service/qtm/qtm_s.h new file mode 100644 index 000000000..e66138ed0 --- /dev/null +++ b/src/core/hle/service/qtm/qtm_s.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace QTM { + +class QTM_S final : public Interface { +public: + QTM_S(); + + std::string GetPortName() const override { + return "qtm:s"; + } +}; + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/qtm/qtm_sp.cpp b/src/core/hle/service/qtm/qtm_sp.cpp new file mode 100644 index 000000000..6e0695d34 --- /dev/null +++ b/src/core/hle/service/qtm/qtm_sp.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/qtm/qtm_sp.h" + +namespace Service { +namespace QTM { + +const Interface::FunctionInfo FunctionTable[] = { + // clang-format off + // qtm common commands + {0x00010080, nullptr, "GetHeadtrackingInfoRaw"}, + {0x00020080, nullptr, "GetHeadtrackingInfo"}, + // clang-format on +}; + +QTM_SP::QTM_SP() { + Register(FunctionTable); +} + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/qtm/qtm_sp.h b/src/core/hle/service/qtm/qtm_sp.h new file mode 100644 index 000000000..0ae0618fc --- /dev/null +++ b/src/core/hle/service/qtm/qtm_sp.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace QTM { + +class QTM_SP final : public Interface { +public: + QTM_SP(); + + std::string GetPortName() const override { + return "qtm:sp"; + } +}; + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/qtm/qtm_u.cpp b/src/core/hle/service/qtm/qtm_u.cpp new file mode 100644 index 000000000..a0f808432 --- /dev/null +++ b/src/core/hle/service/qtm/qtm_u.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/qtm/qtm_u.h" + +namespace Service { +namespace QTM { + +const Interface::FunctionInfo FunctionTable[] = { + // clang-format off + // qtm common commands + {0x00010080, nullptr, "GetHeadtrackingInfoRaw"}, + {0x00020080, nullptr, "GetHeadtrackingInfo"}, + // clang-format on +}; + +QTM_U::QTM_U() { + Register(FunctionTable); +} + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/qtm/qtm_u.h b/src/core/hle/service/qtm/qtm_u.h new file mode 100644 index 000000000..1ed4c0adc --- /dev/null +++ b/src/core/hle/service/qtm/qtm_u.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace QTM { + +class QTM_U final : public Interface { +public: + QTM_U(); + + std::string GetPortName() const override { + return "qtm:u"; + } +}; + +} // namespace QTM +} // namespace Service diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index ca7eeac8a..7e52a05d9 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -2,11 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <boost/range/algorithm_ext/erase.hpp> + #include "common/logging/log.h" #include "common/string_util.h" + +#include "core/hle/kernel/server_port.h" #include "core/hle/service/ac_u.h" -#include "core/hle/service/act_a.h" -#include "core/hle/service/act_u.h" +#include "core/hle/service/act/act.h" #include "core/hle/service/am/am.h" #include "core/hle/service/apt/apt.h" #include "core/hle/service/boss/boss.h" @@ -26,13 +29,16 @@ #include "core/hle/service/ir/ir.h" #include "core/hle/service/ldr_ro/ldr_ro.h" #include "core/hle/service/mic_u.h" +#include "core/hle/service/mvd/mvd.h" #include "core/hle/service/ndm/ndm.h" #include "core/hle/service/news/news.h" +#include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nim/nim.h" #include "core/hle/service/ns_s.h" -#include "core/hle/service/nwm_uds.h" +#include "core/hle/service/nwm/nwm.h" #include "core/hle/service/pm_app.h" #include "core/hle/service/ptm/ptm.h" +#include "core/hle/service/qtm/qtm.h" #include "core/hle/service/service.h" #include "core/hle/service/soc_u.h" #include "core/hle/service/srv.h" @@ -41,8 +47,8 @@ namespace Service { -std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; -std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; +std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; +std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; /** * Creates a function string for logging, complete with the name (or header code, depending @@ -61,7 +67,23 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -ResultVal<bool> Interface::SyncRequest() { +void SessionRequestHandler::ClientConnected( + Kernel::SharedPtr<Kernel::ServerSession> server_session) { + connected_sessions.push_back(server_session); +} + +void SessionRequestHandler::ClientDisconnected( + Kernel::SharedPtr<Kernel::ServerSession> server_session) { + boost::range::remove_erase(connected_sessions, server_session); +} + +Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} +Interface::~Interface() = default; + +void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { + // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which + // session triggered each command. + u32* cmd_buff = Kernel::GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -75,14 +97,12 @@ ResultVal<bool> Interface::SyncRequest() { // TODO(bunnei): Hack - ignore error cmd_buff[1] = 0; - return MakeResult<bool>(false); + return; } LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); itr->second.func(this); - - return MakeResult<bool>(false); // TODO: Implement return from actual function } void Interface::Register(const FunctionInfo* functions, size_t n) { @@ -97,72 +117,81 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); + auto ports = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr<Interface>(interface_)); + auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); + g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); } void AddService(Interface* interface_) { - g_srv_services.emplace(interface_->GetPortName(), interface_); + auto ports = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr<Interface>(interface_)); + auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); + g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); } /// Initialize ServiceManager void Init() { - AddNamedPort(new SRV::Interface); - AddNamedPort(new ERR_F::Interface); - - Service::FS::ArchiveInit(); - Service::AM::Init(); - Service::APT::Init(); - Service::BOSS::Init(); - Service::CAM::Init(); - Service::CECD::Init(); - Service::CFG::Init(); - Service::DLP::Init(); - Service::FRD::Init(); - Service::HID::Init(); - Service::IR::Init(); - Service::NEWS::Init(); - Service::NDM::Init(); - Service::NIM::Init(); - Service::PTM::Init(); - - AddService(new AC_U::Interface); - AddService(new ACT_A::Interface); - AddService(new ACT_U::Interface); - AddService(new CSND_SND::Interface); + AddNamedPort(new SRV::SRV); + AddNamedPort(new ERR::ERR_F); + + FS::ArchiveInit(); + ACT::Init(); + AM::Init(); + APT::Init(); + BOSS::Init(); + CAM::Init(); + CECD::Init(); + CFG::Init(); + DLP::Init(); + FRD::Init(); + HID::Init(); + IR::Init(); + MVD::Init(); + NDM::Init(); + NEWS::Init(); + NFC::Init(); + NIM::Init(); + NWM::Init(); + PTM::Init(); + QTM::Init(); + + AddService(new AC::AC_U); + AddService(new CSND::CSND_SND); AddService(new DSP_DSP::Interface); - AddService(new GSP_GPU::Interface); - AddService(new GSP_LCD::Interface); - AddService(new HTTP_C::Interface); - AddService(new LDR_RO::Interface); - AddService(new MIC_U::Interface); - AddService(new NS_S::Interface); - AddService(new NWM_UDS::Interface); - AddService(new PM_APP::Interface); - AddService(new SOC_U::Interface); - AddService(new SSL_C::Interface); - AddService(new Y2R_U::Interface); + AddService(new GSP::GSP_GPU); + AddService(new GSP::GSP_LCD); + AddService(new HTTP::HTTP_C); + AddService(new LDR::LDR_RO); + AddService(new MIC::MIC_U); + AddService(new NS::NS_S); + AddService(new PM::PM_APP); + AddService(new SOC::SOC_U); + AddService(new SSL::SSL_C); + AddService(new Y2R::Y2R_U); LOG_DEBUG(Service, "initialized OK"); } /// Shutdown ServiceManager void Shutdown() { - - Service::PTM::Shutdown(); - Service::NDM::Shutdown(); - Service::NIM::Shutdown(); - Service::NEWS::Shutdown(); - Service::IR::Shutdown(); - Service::HID::Shutdown(); - Service::FRD::Shutdown(); - Service::DLP::Shutdown(); - Service::CFG::Shutdown(); - Service::CECD::Shutdown(); - Service::CAM::Shutdown(); - Service::BOSS::Shutdown(); - Service::APT::Shutdown(); - Service::AM::Shutdown(); - Service::FS::ArchiveShutdown(); + PTM::Shutdown(); + NIM::Shutdown(); + NEWS::Shutdown(); + NDM::Shutdown(); + IR::Shutdown(); + HID::Shutdown(); + FRD::Shutdown(); + DLP::Shutdown(); + CFG::Shutdown(); + CECD::Shutdown(); + CAM::Shutdown(); + BOSS::Shutdown(); + APT::Shutdown(); + AM::Shutdown(); + FS::ArchiveShutdown(); g_srv_services.clear(); g_kernel_named_ports.clear(); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 29daacfc4..a7ba7688f 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -9,8 +9,15 @@ #include <unordered_map> #include <boost/container/flat_map.hpp> #include "common/common_types.h" -#include "core/hle/kernel/session.h" +#include "core/hle/ipc.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/thread.h" #include "core/hle/result.h" +#include "core/memory.h" + +namespace Kernel { +class ServerSession; +} //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service @@ -18,14 +25,63 @@ namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) +/// Arbitrary default number of maximum connections to an HLE service. +static const u32 DefaultMaxSessions = 10; + +/** + * Interface implemented by HLE Session handlers. + * This can be provided to a ServerSession in order to hook into several relevant events + * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. + */ +class SessionRequestHandler { +public: + /** + * Handles a sync request from the emulated application. + * @param server_session The ServerSession that was triggered for this sync request, + * it should be used to differentiate which client (As in ClientSession) we're answering to. + * TODO(Subv): Use a wrapper structure to hold all the information relevant to + * this request (ServerSession, Originator thread, Translated command buffer, etc). + * @returns ResultCode the result code of the translate operation. + */ + virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0; + + /** + * Signals that a client has just connected to this HLE handler and keeps the + * associated ServerSession alive for the duration of the connection. + * @param server_session Owning pointer to the ServerSession associated with the connection. + */ + void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); + + /** + * Signals that a client has just disconnected from this HLE handler and releases the + * associated ServerSession. + * @param server_session ServerSession associated with the connection. + */ + void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); -/// Interface to a CTROS service -class Interface : public Kernel::Session { - // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be - // just something that encapsulates a session and acts as a helper to implement service - // processes. +protected: + /// List of sessions that are connected to this handler. + /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list + // for the duration of the connection. + std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions; +}; + +/** + * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a + * table mapping header ids to handler functions. + */ +class Interface : public SessionRequestHandler { public: - std::string GetName() const override { + /** + * Creates an HLE interface with the specified max sessions. + * @param max_sessions Maximum number of sessions that can be + * connected to this service at the same time. + */ + Interface(u32 max_sessions = DefaultMaxSessions); + + virtual ~Interface(); + + std::string GetName() const { return GetPortName(); } @@ -33,6 +89,15 @@ public: version.raw = raw_version; } + /** + * Gets the maximum allowed number of sessions that can be connected to this service + * at the same time. + * @returns The maximum number of connections allowed. + */ + u32 GetMaxSessions() const { + return max_sessions; + } + typedef void (*Function)(Interface*); struct FunctionInfo { @@ -49,9 +114,9 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultVal<bool> SyncRequest() override; - protected: + void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; + /** * Registers the functions in the service */ @@ -71,6 +136,7 @@ protected: } version = {}; private: + u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle. boost::container::flat_map<u32, FunctionInfo> m_functions; }; @@ -81,9 +147,9 @@ void Init(); void Shutdown(); /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. -extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; +extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; +extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; /// Adds a service to the services table void AddService(Interface* interface_); diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 46b75db25..c3918cdd0 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/scope_exit.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" #include "core/hle/service/soc_u.h" #include "core/memory.h" @@ -53,12 +53,10 @@ #define closesocket(x) close(x) #endif -static const s32 SOCKET_ERROR_VALUE = -1; +namespace Service { +namespace SOC { -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace SOC_U - -namespace SOC_U { +const s32 SOCKET_ERROR_VALUE = -1; /// Holds the translation from system network errors to 3DS network errors static const std::unordered_map<int, int> error_map = {{ @@ -339,7 +337,7 @@ static void CleanupSockets() { open_sockets.clear(); } -static void Socket(Service::Interface* self) { +static void Socket(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 domain = cmd_buffer[1]; // Address family u32 type = cmd_buffer[2]; @@ -378,7 +376,7 @@ static void Socket(Service::Interface* self) { cmd_buffer[2] = socket_handle; } -static void Bind(Service::Interface* self) { +static void Bind(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; u32 len = cmd_buffer[2]; @@ -406,7 +404,7 @@ static void Bind(Service::Interface* self) { cmd_buffer[2] = res; } -static void Fcntl(Service::Interface* self) { +static void Fcntl(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; u32 ctr_cmd = cmd_buffer[2]; @@ -475,7 +473,7 @@ static void Fcntl(Service::Interface* self) { } } -static void Listen(Service::Interface* self) { +static void Listen(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; u32 backlog = cmd_buffer[2]; @@ -490,7 +488,7 @@ static void Listen(Service::Interface* self) { cmd_buffer[2] = ret; } -static void Accept(Service::Interface* self) { +static void Accept(Interface* self) { // TODO(Subv): Calling this function on a blocking socket will block the emu thread, // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available @@ -518,7 +516,7 @@ static void Accept(Service::Interface* self) { cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0); } -static void GetHostId(Service::Interface* self) { +static void GetHostId(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); char name[128]; @@ -536,7 +534,7 @@ static void GetHostId(Service::Interface* self) { freeaddrinfo(res); } -static void Close(Service::Interface* self) { +static void Close(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; @@ -553,7 +551,7 @@ static void Close(Service::Interface* self) { cmd_buffer[1] = result; } -static void SendTo(Service::Interface* self) { +static void SendTo(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; u32 len = cmd_buffer[2]; @@ -597,7 +595,7 @@ static void SendTo(Service::Interface* self) { cmd_buffer[1] = result; } -static void RecvFrom(Service::Interface* self) { +static void RecvFrom(Interface* self) { // TODO(Subv): Calling this function on a blocking socket will block the emu thread, // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available @@ -654,7 +652,7 @@ static void RecvFrom(Service::Interface* self) { cmd_buffer[3] = total_received; } -static void Poll(Service::Interface* self) { +static void Poll(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 nfds = cmd_buffer[1]; int timeout = cmd_buffer[2]; @@ -692,7 +690,7 @@ static void Poll(Service::Interface* self) { cmd_buffer[2] = ret; } -static void GetSockName(Service::Interface* self) { +static void GetSockName(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; socklen_t ctr_len = cmd_buffer[2]; @@ -720,7 +718,7 @@ static void GetSockName(Service::Interface* self) { cmd_buffer[1] = result; } -static void Shutdown(Service::Interface* self) { +static void Shutdown(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; int how = cmd_buffer[2]; @@ -733,7 +731,7 @@ static void Shutdown(Service::Interface* self) { cmd_buffer[1] = result; } -static void GetPeerName(Service::Interface* self) { +static void GetPeerName(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; socklen_t len = cmd_buffer[2]; @@ -761,7 +759,7 @@ static void GetPeerName(Service::Interface* self) { cmd_buffer[1] = result; } -static void Connect(Service::Interface* self) { +static void Connect(Interface* self) { // TODO(Subv): Calling this function on a blocking socket will block the emu thread, // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available @@ -790,7 +788,7 @@ static void Connect(Service::Interface* self) { cmd_buffer[2] = ret; } -static void InitializeSockets(Service::Interface* self) { +static void InitializeSockets(Interface* self) { // TODO(Subv): Implement #ifdef _WIN32 WSADATA data; @@ -802,7 +800,7 @@ static void InitializeSockets(Service::Interface* self) { cmd_buffer[1] = RESULT_SUCCESS.raw; } -static void ShutdownSockets(Service::Interface* self) { +static void ShutdownSockets(Interface* self) { // TODO(Subv): Implement CleanupSockets(); @@ -814,7 +812,7 @@ static void ShutdownSockets(Service::Interface* self) { cmd_buffer[1] = 0; } -static void GetSockOpt(Service::Interface* self) { +static void GetSockOpt(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; u32 level = cmd_buffer[2]; @@ -849,7 +847,7 @@ static void GetSockOpt(Service::Interface* self) { cmd_buffer[3] = optlen; } -static void SetSockOpt(Service::Interface* self) { +static void SetSockOpt(Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; u32 level = cmd_buffer[2]; @@ -916,18 +914,16 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00230040, nullptr, "AddGlobalSocket"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +SOC_U::SOC_U() { Register(FunctionTable); } -Interface::~Interface() { +SOC_U::~SOC_U() { CleanupSockets(); #ifdef _WIN32 WSACleanup(); #endif } -} // namespace +} // namespace SOC +} // namespace Service diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h index 8d02ed30f..5f829fc1c 100644 --- a/src/core/hle/service/soc_u.h +++ b/src/core/hle/service/soc_u.h @@ -7,19 +7,18 @@ #include <string> #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace SOC_U +namespace Service { +namespace SOC { -namespace SOC_U { - -class Interface : public Service::Interface { +class SOC_U final : public Interface { public: - Interface(); - ~Interface(); + SOC_U(); + ~SOC_U(); std::string GetPortName() const override { return "soc:U"; } }; -} // namespace +} // namespace SOC +} // namespace Service diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index b25be413a..3bd787147 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -2,14 +2,16 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <tuple> + #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/service/srv.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace SRV - +namespace Service { namespace SRV { static Kernel::SharedPtr<Kernel::Event> event_handle; @@ -23,7 +25,7 @@ static Kernel::SharedPtr<Kernel::Event> event_handle; * 0: 0x00010040 * 1: ResultCode */ -static void RegisterClient(Service::Interface* self) { +static void RegisterClient(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); if (cmd_buff[1] != IPC::CallingPidDesc()) { @@ -48,7 +50,7 @@ static void RegisterClient(Service::Interface* self) { * 2: Translation descriptor: 0x20 * 3: Handle to semaphore signaled on process notification */ -static void EnableNotification(Service::Interface* self) { +static void EnableNotification(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(bunnei): Change to a semaphore once these have been implemented @@ -73,7 +75,7 @@ static void EnableNotification(Service::Interface* self) { * 1: ResultCode * 3: Service handle */ -static void GetServiceHandle(Service::Interface* self) { +static void GetServiceHandle(Interface* self) { ResultCode res = RESULT_SUCCESS; u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -81,7 +83,15 @@ static void GetServiceHandle(Service::Interface* self) { auto it = Service::g_srv_services.find(port_name); if (it != Service::g_srv_services.end()) { - cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom(); + auto client_port = it->second; + + auto client_session = client_port->Connect(); + res = client_session.Code(); + + if (client_session.Succeeded()) { + // Return the client session + cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); + } LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); } else { LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); @@ -99,7 +109,7 @@ static void GetServiceHandle(Service::Interface* self) { * 0: 0x00090040 * 1: ResultCode */ -static void Subscribe(Service::Interface* self) { +static void Subscribe(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 notification_id = cmd_buff[1]; @@ -118,7 +128,7 @@ static void Subscribe(Service::Interface* self) { * 0: 0x000A0040 * 1: ResultCode */ -static void Unsubscribe(Service::Interface* self) { +static void Unsubscribe(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 notification_id = cmd_buff[1]; @@ -138,7 +148,7 @@ static void Unsubscribe(Service::Interface* self) { * 0: 0x000C0040 * 1: ResultCode */ -static void PublishToSubscriber(Service::Interface* self) { +static void PublishToSubscriber(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 notification_id = cmd_buff[1]; @@ -167,16 +177,14 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000E00C0, nullptr, "IsServiceRegistered"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +SRV::SRV() { Register(FunctionTable); event_handle = nullptr; } -Interface::~Interface() { +SRV::~SRV() { event_handle = nullptr; } } // namespace SRV +} // namespace Service diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 96c89b025..d3a9de879 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h @@ -2,22 +2,23 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/service/service.h" +#pragma once -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace SRV +#include "core/hle/service/service.h" +namespace Service { namespace SRV { /// Interface to "srv:" service -class Interface : public Service::Interface { +class SRV final : public Interface { public: - Interface(); - ~Interface() override; + SRV(); + ~SRV() override; std::string GetPortName() const override { return "srv:"; } }; -} // namespace +} // namespace SRV +} // namespace Service diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp index abab1d271..09ced9d7a 100644 --- a/src/core/hle/service/ssl_c.cpp +++ b/src/core/hle/service/ssl_c.cpp @@ -6,15 +6,13 @@ #include "common/common_types.h" #include "core/hle/service/ssl_c.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace SSL_C - -namespace SSL_C { +namespace Service { +namespace SSL { // TODO: Implement a proper CSPRNG in the future when actual security is needed static std::mt19937 rand_gen; -static void Initialize(Service::Interface* self) { +static void Initialize(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // Seed random number generator when the SSL service is initialized @@ -25,7 +23,7 @@ static void Initialize(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; } -static void GenerateRandomData(Service::Interface* self) { +static void GenerateRandomData(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 size = cmd_buff[1]; @@ -66,6 +64,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00050082, nullptr, "AddTrustedRootCA"}, {0x00060080, nullptr, "RootCertChainAddDefaultCert"}, {0x00070080, nullptr, "RootCertChainRemoveCert"}, + {0x000D0084, nullptr, "OpenClientCertContext"}, {0x000E0040, nullptr, "OpenDefaultClientCertContext"}, {0x000F0040, nullptr, "CloseClientCertContext"}, {0x00110042, GenerateRandomData, "GenerateRandomData"}, @@ -73,19 +72,19 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00130040, nullptr, "StartConnection"}, {0x00140040, nullptr, "StartConnectionGetOut"}, {0x00150082, nullptr, "Read"}, + {0x00160082, nullptr, "ReadPeek"}, {0x00170082, nullptr, "Write"}, {0x00180080, nullptr, "ContextSetRootCertChain"}, {0x00190080, nullptr, "ContextSetClientCert"}, {0x001B0080, nullptr, "ContextClearOpt"}, + {0x001C00C4, nullptr, "ContextGetProtocolCipher"}, {0x001E0040, nullptr, "DestroyContext"}, {0x001F0082, nullptr, "ContextInitSharedmem"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +SSL_C::SSL_C() { Register(FunctionTable); } -} // namespace +} // namespace SSL_C +} // namespace Service diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h index 58e87c1cb..fc50a2eb2 100644 --- a/src/core/hle/service/ssl_c.h +++ b/src/core/hle/service/ssl_c.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace SSL_C +namespace Service { +namespace SSL { -namespace SSL_C { - -class Interface : public Service::Interface { +class SSL_C final : public Interface { public: - Interface(); + SSL_C(); std::string GetPortName() const override { return "ssl:C"; } }; -} // namespace +} // namespace SSL +} // namespace Service diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index 097e09d28..a20194107 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -11,10 +11,8 @@ #include "core/hle/service/y2r_u.h" #include "core/hw/y2r.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace Y2R_U - -namespace Y2R_U { +namespace Service { +namespace Y2R { struct ConversionParameters { InputFormat input_format; @@ -83,7 +81,7 @@ ResultCode ConversionConfiguration::SetStandardCoefficient( return RESULT_SUCCESS; } -static void SetInputFormat(Service::Interface* self) { +static void SetInputFormat(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.input_format = static_cast<InputFormat>(cmd_buff[1]); @@ -94,7 +92,7 @@ static void SetInputFormat(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format); } -static void GetInputFormat(Service::Interface* self) { +static void GetInputFormat(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x2, 2, 0); @@ -104,7 +102,7 @@ static void GetInputFormat(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format); } -static void SetOutputFormat(Service::Interface* self) { +static void SetOutputFormat(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.output_format = static_cast<OutputFormat>(cmd_buff[1]); @@ -115,7 +113,7 @@ static void SetOutputFormat(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format); } -static void GetOutputFormat(Service::Interface* self) { +static void GetOutputFormat(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x4, 2, 0); @@ -125,7 +123,7 @@ static void GetOutputFormat(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format); } -static void SetRotation(Service::Interface* self) { +static void SetRotation(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.rotation = static_cast<Rotation>(cmd_buff[1]); @@ -136,7 +134,7 @@ static void SetRotation(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation); } -static void GetRotation(Service::Interface* self) { +static void GetRotation(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x6, 2, 0); @@ -146,7 +144,7 @@ static void GetRotation(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation); } -static void SetBlockAlignment(Service::Interface* self) { +static void SetBlockAlignment(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.block_alignment = static_cast<BlockAlignment>(cmd_buff[1]); @@ -157,7 +155,7 @@ static void SetBlockAlignment(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment); } -static void GetBlockAlignment(Service::Interface* self) { +static void GetBlockAlignment(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0); @@ -174,7 +172,7 @@ static void GetBlockAlignment(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetSpacialDithering(Service::Interface* self) { +static void SetSpacialDithering(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); spacial_dithering_enabled = cmd_buff[1] & 0xF; @@ -190,7 +188,7 @@ static void SetSpacialDithering(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : u8, 0 = Disabled, 1 = Enabled */ -static void GetSpacialDithering(Service::Interface* self) { +static void GetSpacialDithering(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0); @@ -207,7 +205,7 @@ static void GetSpacialDithering(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetTemporalDithering(Service::Interface* self) { +static void SetTemporalDithering(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); temporal_dithering_enabled = cmd_buff[1] & 0xF; @@ -223,7 +221,7 @@ static void SetTemporalDithering(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : u8, 0 = Disabled, 1 = Enabled */ -static void GetTemporalDithering(Service::Interface* self) { +static void GetTemporalDithering(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0); @@ -240,7 +238,7 @@ static void GetTemporalDithering(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -static void SetTransferEndInterrupt(Service::Interface* self) { +static void SetTransferEndInterrupt(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); transfer_end_interrupt_enabled = cmd_buff[1] & 0xf; @@ -256,7 +254,7 @@ static void SetTransferEndInterrupt(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : u8, 0 = Disabled, 1 = Enabled */ -static void GetTransferEndInterrupt(Service::Interface* self) { +static void GetTransferEndInterrupt(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0xE, 2, 0); @@ -272,7 +270,7 @@ static void GetTransferEndInterrupt(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 3 : The handle of the completion event */ -static void GetTransferEndEvent(Service::Interface* self) { +static void GetTransferEndEvent(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0); @@ -282,7 +280,7 @@ static void GetTransferEndEvent(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called"); } -static void SetSendingY(Service::Interface* self) { +static void SetSendingY(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.src_Y.address = cmd_buff[1]; @@ -299,7 +297,7 @@ static void SetSendingY(Service::Interface* self) { cmd_buff[6]); } -static void SetSendingU(Service::Interface* self) { +static void SetSendingU(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.src_U.address = cmd_buff[1]; @@ -316,7 +314,7 @@ static void SetSendingU(Service::Interface* self) { cmd_buff[6]); } -static void SetSendingV(Service::Interface* self) { +static void SetSendingV(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.src_V.address = cmd_buff[1]; @@ -333,7 +331,7 @@ static void SetSendingV(Service::Interface* self) { cmd_buff[6]); } -static void SetSendingYUYV(Service::Interface* self) { +static void SetSendingYUYV(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.src_YUYV.address = cmd_buff[1]; @@ -356,7 +354,7 @@ static void SetSendingYUYV(Service::Interface* self) { * 1 : Result of the function, 0 on success, otherwise error code * 2 : u8, 0 = Not Finished, 1 = Finished */ -static void IsFinishedSendingYuv(Service::Interface* self) { +static void IsFinishedSendingYuv(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x14, 2, 0); @@ -372,7 +370,7 @@ static void IsFinishedSendingYuv(Service::Interface* self) { * 1 : Result of the function, 0 on success, otherwise error code * 2 : u8, 0 = Not Finished, 1 = Finished */ -static void IsFinishedSendingY(Service::Interface* self) { +static void IsFinishedSendingY(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x15, 2, 0); @@ -388,7 +386,7 @@ static void IsFinishedSendingY(Service::Interface* self) { * 1 : Result of the function, 0 on success, otherwise error code * 2 : u8, 0 = Not Finished, 1 = Finished */ -static void IsFinishedSendingU(Service::Interface* self) { +static void IsFinishedSendingU(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0); @@ -404,7 +402,7 @@ static void IsFinishedSendingU(Service::Interface* self) { * 1 : Result of the function, 0 on success, otherwise error code * 2 : u8, 0 = Not Finished, 1 = Finished */ -static void IsFinishedSendingV(Service::Interface* self) { +static void IsFinishedSendingV(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x17, 2, 0); @@ -414,7 +412,7 @@ static void IsFinishedSendingV(Service::Interface* self) { LOG_WARNING(Service_Y2R, "(STUBBED) called"); } -static void SetReceiving(Service::Interface* self) { +static void SetReceiving(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.dst.address = cmd_buff[1]; @@ -437,7 +435,7 @@ static void SetReceiving(Service::Interface* self) { * 1 : Result of the function, 0 on success, otherwise error code * 2 : u8, 0 = Not Finished, 1 = Finished */ -static void IsFinishedReceiving(Service::Interface* self) { +static void IsFinishedReceiving(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x19, 2, 0); @@ -447,7 +445,7 @@ static void IsFinishedReceiving(Service::Interface* self) { LOG_WARNING(Service_Y2R, "(STUBBED) called"); } -static void SetInputLineWidth(Service::Interface* self) { +static void SetInputLineWidth(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x1A, 1, 0); @@ -456,7 +454,7 @@ static void SetInputLineWidth(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called input_line_width=%u", cmd_buff[1]); } -static void GetInputLineWidth(Service::Interface* self) { +static void GetInputLineWidth(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x1B, 2, 0); @@ -466,7 +464,7 @@ static void GetInputLineWidth(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called input_line_width=%u", conversion.input_line_width); } -static void SetInputLines(Service::Interface* self) { +static void SetInputLines(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x1C, 1, 0); @@ -475,7 +473,7 @@ static void SetInputLines(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called input_lines=%u", cmd_buff[1]); } -static void GetInputLines(Service::Interface* self) { +static void GetInputLines(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x1D, 2, 0); @@ -485,7 +483,7 @@ static void GetInputLines(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called input_lines=%u", conversion.input_lines); } -static void SetCoefficient(Service::Interface* self) { +static void SetCoefficient(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); const u16* coefficients = reinterpret_cast<const u16*>(&cmd_buff[1]); @@ -499,7 +497,7 @@ static void SetCoefficient(Service::Interface* self) { coefficients[5], coefficients[6], coefficients[7]); } -static void GetCoefficient(Service::Interface* self) { +static void GetCoefficient(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x1F, 5, 0); @@ -509,7 +507,7 @@ static void GetCoefficient(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called"); } -static void SetStandardCoefficient(Service::Interface* self) { +static void SetStandardCoefficient(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 index = cmd_buff[1]; @@ -520,7 +518,7 @@ static void SetStandardCoefficient(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u", index); } -static void GetStandardCoefficient(Service::Interface* self) { +static void GetStandardCoefficient(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 index = cmd_buff[1]; @@ -539,7 +537,7 @@ static void GetStandardCoefficient(Service::Interface* self) { } } -static void SetAlpha(Service::Interface* self) { +static void SetAlpha(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.alpha = cmd_buff[1]; @@ -550,7 +548,7 @@ static void SetAlpha(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha); } -static void GetAlpha(Service::Interface* self) { +static void GetAlpha(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x23, 2, 0); @@ -560,7 +558,7 @@ static void GetAlpha(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha); } -static void SetDitheringWeightParams(Service::Interface* self) { +static void SetDitheringWeightParams(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); std::memcpy(&dithering_weight_params, &cmd_buff[1], sizeof(DitheringWeightParams)); @@ -570,7 +568,7 @@ static void SetDitheringWeightParams(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called"); } -static void GetDitheringWeightParams(Service::Interface* self) { +static void GetDitheringWeightParams(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x25, 9, 0); @@ -580,7 +578,7 @@ static void GetDitheringWeightParams(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called"); } -static void StartConversion(Service::Interface* self) { +static void StartConversion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( @@ -599,7 +597,7 @@ static void StartConversion(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called"); } -static void StopConversion(Service::Interface* self) { +static void StopConversion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x27, 1, 0); @@ -614,7 +612,7 @@ static void StopConversion(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : 1 if there's a conversion running, otherwise 0. */ -static void IsBusyConversion(Service::Interface* self) { +static void IsBusyConversion(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x28, 2, 0); @@ -627,7 +625,7 @@ static void IsBusyConversion(Service::Interface* self) { /** * Y2R_U::SetPackageParameter service function */ -static void SetPackageParameter(Service::Interface* self) { +static void SetPackageParameter(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); auto params = reinterpret_cast<const ConversionParameters*>(&cmd_buff[1]); @@ -668,7 +666,7 @@ cleanup: params->padding, params->alpha); } -static void PingProcess(Service::Interface* self) { +static void PingProcess(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x2A, 2, 0); @@ -678,7 +676,7 @@ static void PingProcess(Service::Interface* self) { LOG_WARNING(Service_Y2R, "(STUBBED) called"); } -static void DriverInitialize(Service::Interface* self) { +static void DriverInitialize(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); conversion.input_format = InputFormat::YUV422_Indiv8; @@ -704,7 +702,7 @@ static void DriverInitialize(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called"); } -static void DriverFinalize(Service::Interface* self) { +static void DriverFinalize(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x2C, 1, 0); @@ -713,7 +711,7 @@ static void DriverFinalize(Service::Interface* self) { LOG_DEBUG(Service_Y2R, "called"); } -static void GetPackageParameter(Service::Interface* self) { +static void GetPackageParameter(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x2D, 4, 0); @@ -771,18 +769,16 @@ const Interface::FunctionInfo FunctionTable[] = { {0x002D0000, GetPackageParameter, "GetPackageParameter"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +Y2R_U::Y2R_U() { completion_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "Y2R:Completed"); std::memset(&conversion, 0, sizeof(conversion)); Register(FunctionTable); } -Interface::~Interface() { +Y2R_U::~Y2R_U() { completion_event = nullptr; } -} // namespace +} // namespace Y2R +} // namespace Service
\ No newline at end of file diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h index 1b47b5322..dddeed0be 100644 --- a/src/core/hle/service/y2r_u.h +++ b/src/core/hle/service/y2r_u.h @@ -10,10 +10,8 @@ #include "core/hle/result.h" #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace Y2R_U - -namespace Y2R_U { +namespace Service { +namespace Y2R { enum class InputFormat : u8 { /// 8-bit input, with YUV components in separate planes and 4:2:2 subsampling. @@ -127,14 +125,15 @@ struct DitheringWeightParams { u16 w3_xOdd_yOdd; }; -class Interface : public Service::Interface { +class Y2R_U final : public Interface { public: - Interface(); - ~Interface() override; + Y2R_U(); + ~Y2R_U() override; std::string GetPortName() const override { return "y2r:u"; } }; -} // namespace +} // namespace Y2R +} // namespace Service diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index c6b80dc50..2ca270de3 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -13,6 +13,7 @@ #include "core/hle/function_wrappers.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/mutex.h" @@ -20,6 +21,7 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -41,6 +43,9 @@ const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E +const ResultCode ERR_SYNC_TIMEOUT(ErrorDescription::Timeout, ErrorModule::OS, + ErrorSummary::StatusChanged, ErrorLevel::Info); + const ResultCode ERR_MISALIGNED_ADDRESS{// 0xE0E01BF1 ErrorDescription::MisalignedAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage}; @@ -161,7 +166,8 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add } /// Maps a memory block to specified address -static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { +static ResultCode MapMemoryBlock(Kernel::Handle handle, u32 addr, u32 permissions, + u32 other_permissions) { using Kernel::SharedMemory; using Kernel::MemoryPermission; @@ -193,7 +199,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o ErrorSummary::InvalidArgument, ErrorLevel::Usage); } -static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { +static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) { using Kernel::SharedMemory; LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X", handle, addr); @@ -208,7 +214,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { } /// Connect to an OS service given the port name, returns the handle to the port to out -static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { +static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) { if (port_name == nullptr) return ERR_NOT_FOUND; if (std::strlen(port_name) > 11) @@ -222,54 +228,66 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { return ERR_NOT_FOUND; } - CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second)); + auto client_port = it->second; + + SharedPtr<Kernel::ClientSession> client_session; + CASCADE_RESULT(client_session, client_port->Connect()); + + // Return the client session + CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session)); return RESULT_SUCCESS; } -/// Synchronize to an OS service -static ResultCode SendSyncRequest(Handle handle) { - SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); +/// Makes a blocking IPC call to an OS service. +static ResultCode SendSyncRequest(Kernel::Handle handle) { + SharedPtr<Kernel::ClientSession> session = + Kernel::g_handle_table.Get<Kernel::ClientSession>(handle); if (session == nullptr) { return ERR_INVALID_HANDLE; } LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); - return session->SyncRequest().Code(); + // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server + // responds and cause a reschedule. + return session->SendSyncRequest(); } /// Close a handle -static ResultCode CloseHandle(Handle handle) { +static ResultCode CloseHandle(Kernel::Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle); return Kernel::g_handle_table.Close(handle); } /// Wait for a handle to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { +static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) { auto object = Kernel::g_handle_table.GetWaitObject(handle); Kernel::Thread* thread = Kernel::GetCurrentThread(); - thread->waitsynch_waited = false; - if (object == nullptr) return ERR_INVALID_HANDLE; LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - HLE::Reschedule(__func__); - - // Check for next thread to schedule if (object->ShouldWait()) { + if (nano_seconds == 0) + return ERR_SYNC_TIMEOUT; + object->AddWaitingThread(thread); - Kernel::WaitCurrentThread_WaitSynchronization({object}, false, false); + // TODO(Subv): Perform things like update the mutex lock owner's priority to + // prevent priority inversion. Currently this is done in Mutex::ShouldWait, + // but it should be moved to a function that is called from here. + thread->status = THREADSTATUS_WAIT_SYNCH; // Create an event to wake the thread up after the specified nanosecond delay has passed thread->WakeAfterDelay(nano_seconds); - // NOTE: output of this SVC will be set later depending on how the thread resumes - return HLE::RESULT_INVALID; + // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread + // resumes due to a signal in its wait objects. + // Otherwise we retain the default value of timeout. + return ERR_SYNC_TIMEOUT; } object->Acquire(); @@ -278,13 +296,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { } /// Wait for the given handles to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, - s64 nano_seconds) { - bool wait_thread = !wait_all; - int handle_index = 0; +static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 handle_count, + bool wait_all, s64 nano_seconds) { Kernel::Thread* thread = Kernel::GetCurrentThread(); - bool was_waiting = thread->waitsynch_waited; - thread->waitsynch_waited = false; // Check if 'handles' is invalid if (handles == nullptr) @@ -300,94 +314,117 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); - // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if - // necessary - if (handle_count != 0) { - bool selected = false; // True once an object has been selected - - Kernel::SharedPtr<Kernel::WaitObject> wait_object; - - for (int i = 0; i < handle_count; ++i) { - auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); - if (object == nullptr) - return ERR_INVALID_HANDLE; - - // Check if the current thread should wait on this object... - if (object->ShouldWait()) { - - // Check we are waiting on all objects... - if (wait_all) - // Wait the thread - wait_thread = true; - } else { - // Do not wait on this object, check if this object should be selected... - if (!wait_all && (!selected || (wait_object == object && was_waiting))) { - // Do not wait the thread - wait_thread = false; - handle_index = i; - wait_object = object; - selected = true; - } - } - } - } else { - // If no handles were passed in, put the thread to sleep only when 'wait_all' is false - // NOTE: This should deadlock the current thread if no timeout was specified - if (!wait_all) { - wait_thread = true; - } + using ObjectPtr = Kernel::SharedPtr<Kernel::WaitObject>; + std::vector<ObjectPtr> objects(handle_count); + + for (int i = 0; i < handle_count; ++i) { + auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); + if (object == nullptr) + return ERR_INVALID_HANDLE; + objects[i] = object; } - SCOPE_EXIT({ - HLE::Reschedule("WaitSynchronizationN"); - }); // Reschedule after putting the threads to sleep. + // Clear the mapping of wait object indices. + // We don't want any lingering state in this map. + // It will be repopulated later in the wait_all = false case. + thread->wait_objects_index.clear(); + + if (wait_all) { + bool all_available = + std::all_of(objects.begin(), objects.end(), + [](const ObjectPtr& object) { return !object->ShouldWait(); }); + if (all_available) { + // We can acquire all objects right now, do so. + for (auto& object : objects) + object->Acquire(); + // Note: In this case, the `out` parameter is not set, + // and retains whatever value it had before. + return RESULT_SUCCESS; + } + + // Not all objects were available right now, prepare to suspend the thread. - // If thread should wait, then set its state to waiting - if (wait_thread) { + // If a timeout value of 0 was provided, just return the Timeout error code instead of + // suspending the thread. + if (nano_seconds == 0) + return ERR_SYNC_TIMEOUT; - // Actually wait the current thread on each object if we decided to wait... - std::vector<SharedPtr<Kernel::WaitObject>> wait_objects; - wait_objects.reserve(handle_count); + // Put the thread to sleep + thread->status = THREADSTATUS_WAIT_SYNCH; - for (int i = 0; i < handle_count; ++i) { - auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); - object->AddWaitingThread(Kernel::GetCurrentThread()); - wait_objects.push_back(object); + // Add the thread to each of the objects' waiting threads. + for (auto& object : objects) { + object->AddWaitingThread(thread); + // TODO(Subv): Perform things like update the mutex lock owner's priority to + // prevent priority inversion. Currently this is done in Mutex::ShouldWait, + // but it should be moved to a function that is called from here. } - Kernel::WaitCurrentThread_WaitSynchronization(std::move(wait_objects), true, wait_all); + // Set the thread's waitlist to the list of objects passed to WaitSynchronizationN + thread->wait_objects = std::move(objects); // Create an event to wake the thread up after the specified nanosecond delay has passed - Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); - - // NOTE: output of this SVC will be set later depending on how the thread resumes - return HLE::RESULT_INVALID; - } + thread->WakeAfterDelay(nano_seconds); - // Acquire objects if we did not wait... - for (int i = 0; i < handle_count; ++i) { - auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); + // This value gets set to -1 by default in this case, it is not modified after this. + *out = -1; + // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to + // a signal in one of its wait objects. + return ERR_SYNC_TIMEOUT; + } else { + // Find the first object that is acquirable in the provided list of objects + auto itr = std::find_if(objects.begin(), objects.end(), + [](const ObjectPtr& object) { return !object->ShouldWait(); }); - // Acquire the object if it is not waiting... - if (!object->ShouldWait()) { + if (itr != objects.end()) { + // We found a ready object, acquire it and set the result value + Kernel::WaitObject* object = itr->get(); object->Acquire(); + *out = std::distance(objects.begin(), itr); + return RESULT_SUCCESS; + } + + // No objects were ready to be acquired, prepare to suspend the thread. + + // If a timeout value of 0 was provided, just return the Timeout error code instead of + // suspending the thread. + if (nano_seconds == 0) + return ERR_SYNC_TIMEOUT; + + // Put the thread to sleep + thread->status = THREADSTATUS_WAIT_SYNCH; - // If this was the first non-waiting object and 'wait_all' is false, don't acquire - // any other objects - if (!wait_all) - break; + // Clear the thread's waitlist, we won't use it for wait_all = false + thread->wait_objects.clear(); + + // Add the thread to each of the objects' waiting threads. + for (size_t i = 0; i < objects.size(); ++i) { + Kernel::WaitObject* object = objects[i].get(); + // Set the index of this object in the mapping of Objects -> index for this thread. + thread->wait_objects_index[object->GetObjectId()] = static_cast<int>(i); + object->AddWaitingThread(thread); + // TODO(Subv): Perform things like update the mutex lock owner's priority to + // prevent priority inversion. Currently this is done in Mutex::ShouldWait, + // but it should be moved to a function that is called from here. } - } - // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does - // not seem to set it to any meaningful value. - *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0; + // Note: If no handles and no timeout were given, then the thread will deadlock, this is + // consistent with hardware behavior. - return RESULT_SUCCESS; + // Create an event to wake the thread up after the specified nanosecond delay has passed + thread->WakeAfterDelay(nano_seconds); + + // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a + // signal in one of its wait objects. + // Otherwise we retain the default value of timeout, and -1 in the out parameter + thread->wait_set_output = true; + *out = -1; + return ERR_SYNC_TIMEOUT; + } } /// Create an address arbiter (to allocate access to shared resources) -static ResultCode CreateAddressArbiter(Handle* out_handle) { +static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) { using Kernel::AddressArbiter; SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create(); @@ -397,7 +434,7 @@ static ResultCode CreateAddressArbiter(Handle* out_handle) { } /// Arbitrate address -static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value, +static ResultCode ArbitrateAddress(Kernel::Handle handle, u32 address, u32 type, u32 value, s64 nanoseconds) { using Kernel::AddressArbiter; @@ -440,7 +477,7 @@ static void OutputDebugString(const char* string) { } /// Get resource limit -static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) { +static ResultCode GetResourceLimit(Kernel::Handle* resource_limit, Kernel::Handle process_handle) { LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); SharedPtr<Kernel::Process> process = @@ -454,7 +491,7 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle } /// Get resource limit current values -static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, +static ResultCode GetResourceLimitCurrentValues(s64* values, Kernel::Handle resource_limit_handle, u32* names, u32 name_count) { LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", resource_limit_handle, names, name_count); @@ -471,8 +508,8 @@ static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_lim } /// Get resource limit max values -static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names, - u32 name_count) { +static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resource_limit_handle, + u32* names, u32 name_count) { LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", resource_limit_handle, names, name_count); @@ -488,7 +525,7 @@ static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit } /// Creates a new thread -static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg, +static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { using Kernel::Thread; @@ -546,13 +583,13 @@ static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point /// Called when a thread exits static void ExitThread() { - LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); + LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::CPU().GetPC()); - Kernel::GetCurrentThread()->Stop(); + Kernel::ExitCurrentThread(); } /// Gets the priority for the specified thread -static ResultCode GetThreadPriority(s32* priority, Handle handle) { +static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) { const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -562,7 +599,7 @@ static ResultCode GetThreadPriority(s32* priority, Handle handle) { } /// Sets the priority for the specified thread -static ResultCode SetThreadPriority(Handle handle, s32 priority) { +static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) { SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -572,11 +609,11 @@ static ResultCode SetThreadPriority(Handle handle, s32 priority) { } /// Create a mutex -static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { +static ResultCode CreateMutex(Kernel::Handle* out_handle, u32 initial_locked) { using Kernel::Mutex; SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0); - mutex->name = Common::StringFromFormat("mutex-%08x", Core::g_app_core->GetReg(14)); + mutex->name = Common::StringFromFormat("mutex-%08x", Core::CPU().GetReg(14)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", @@ -586,7 +623,7 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { } /// Release a mutex -static ResultCode ReleaseMutex(Handle handle) { +static ResultCode ReleaseMutex(Kernel::Handle handle) { using Kernel::Mutex; LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); @@ -601,7 +638,7 @@ static ResultCode ReleaseMutex(Handle handle) { } /// Get the ID of the specified process -static ResultCode GetProcessId(u32* process_id, Handle process_handle) { +static ResultCode GetProcessId(u32* process_id, Kernel::Handle process_handle) { LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); const SharedPtr<Kernel::Process> process = @@ -614,7 +651,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { } /// Get the ID of the process that owns the specified thread -static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { +static ResultCode GetProcessIdOfThread(u32* process_id, Kernel::Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); const SharedPtr<Kernel::Thread> thread = @@ -631,7 +668,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { } /// Get the ID for the specified thread. -static ResultCode GetThreadId(u32* thread_id, Handle handle) { +static ResultCode GetThreadId(u32* thread_id, Kernel::Handle handle) { LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); @@ -643,11 +680,11 @@ static ResultCode GetThreadId(u32* thread_id, Handle handle) { } /// Creates a semaphore -static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { +static ResultCode CreateSemaphore(Kernel::Handle* out_handle, s32 initial_count, s32 max_count) { using Kernel::Semaphore; CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count)); - semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::g_app_core->GetReg(14)); + semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::CPU().GetReg(14)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore))); LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", @@ -656,7 +693,7 @@ static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max } /// Releases a certain number of slots in a semaphore -static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { +static ResultCode ReleaseSemaphore(s32* count, Kernel::Handle handle, s32 release_count) { using Kernel::Semaphore; LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle); @@ -672,7 +709,7 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) /// Query process memory static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, - Handle process_handle, u32 addr) { + Kernel::Handle process_handle, u32 addr) { using Kernel::Process; Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle); if (process == nullptr) @@ -700,11 +737,11 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 } /// Create an event -static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { +static ResultCode CreateEvent(Kernel::Handle* out_handle, u32 reset_type) { using Kernel::Event; SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type)); - evt->name = Common::StringFromFormat("event-%08x", Core::g_app_core->GetReg(14)); + evt->name = Common::StringFromFormat("event-%08x", Core::CPU().GetReg(14)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type, @@ -713,14 +750,14 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { } /// Duplicates a kernel handle -static ResultCode DuplicateHandle(Handle* out, Handle handle) { +static ResultCode DuplicateHandle(Kernel::Handle* out, Kernel::Handle handle) { CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle)); LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); return RESULT_SUCCESS; } /// Signals an event -static ResultCode SignalEvent(Handle handle) { +static ResultCode SignalEvent(Kernel::Handle handle) { using Kernel::Event; LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); @@ -734,7 +771,7 @@ static ResultCode SignalEvent(Handle handle) { } /// Clears an event -static ResultCode ClearEvent(Handle handle) { +static ResultCode ClearEvent(Kernel::Handle handle) { using Kernel::Event; LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); @@ -747,11 +784,11 @@ static ResultCode ClearEvent(Handle handle) { } /// Creates a timer -static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { +static ResultCode CreateTimer(Kernel::Handle* out_handle, u32 reset_type) { using Kernel::Timer; SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type)); - timer->name = Common::StringFromFormat("timer-%08x", Core::g_app_core->GetReg(14)); + timer->name = Common::StringFromFormat("timer-%08x", Core::CPU().GetReg(14)); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type, @@ -760,7 +797,7 @@ static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { } /// Clears a timer -static ResultCode ClearTimer(Handle handle) { +static ResultCode ClearTimer(Kernel::Handle handle) { using Kernel::Timer; LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); @@ -774,7 +811,7 @@ static ResultCode ClearTimer(Handle handle) { } /// Starts a timer -static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { +static ResultCode SetTimer(Kernel::Handle handle, s64 initial, s64 interval) { using Kernel::Timer; LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); @@ -789,7 +826,7 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { } /// Cancels a timer -static ResultCode CancelTimer(Handle handle) { +static ResultCode CancelTimer(Kernel::Handle handle) { using Kernel::Timer; LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); @@ -818,14 +855,13 @@ static void SleepThread(s64 nanoseconds) { static s64 GetSystemTick() { s64 result = CoreTiming::GetTicks(); // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end. - Core::g_app_core->AddTicks( - 150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b + Core::CPU().AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b return result; } /// Creates a memory block at the specified address with the specified permissions and size -static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, - u32 other_permission) { +static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 size, + u32 my_permission, u32 other_permission) { using Kernel::SharedMemory; if (size % Memory::PAGE_SIZE != 0) @@ -876,8 +912,8 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 return RESULT_SUCCESS; } -static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name, - u32 max_sessions) { +static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port, + const char* name, u32 max_sessions) { // TODO(Subv): Implement named ports. ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented"); @@ -942,7 +978,7 @@ static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { return RESULT_SUCCESS; } -static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { +static ResultCode GetProcessInfo(s64* out, Kernel::Handle process_handle, u32 type) { LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type); using Kernel::Process; @@ -1148,6 +1184,8 @@ void CallSVC(u32 immediate) { if (info) { if (info->func) { info->func(); + // TODO(Subv): Not all service functions should cause a reschedule in all cases. + Core::System::GetInstance().PrepareReschedule(); } else { LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name); } diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index cfba82e51..1a1ee90b2 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -430,9 +430,9 @@ inline void Write(u32 addr, const T data) { // TODO: hwtest this if (config.GetStartAddress() != 0) { if (!is_second_filler) { - GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0); + Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PSC0); } else { - GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1); + Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PSC1); } } @@ -473,7 +473,7 @@ inline void Write(u32 addr, const T data) { } g_regs.display_transfer_config.trigger = 0; - GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); + Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PPF); } break; } @@ -487,8 +487,8 @@ inline void Write(u32 addr, const T data) { u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress()); if (Pica::g_debug_context && Pica::g_debug_context->recorder) { - Pica::g_debug_context->recorder->MemoryAccessed( - (u8*)buffer, config.size * sizeof(u32), config.GetPhysicalAddress()); + Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size, + config.GetPhysicalAddress()); } Pica::CommandProcessor::ProcessCommandList(buffer, config.size); @@ -548,8 +548,8 @@ static void VBlankCallback(u64 userdata, int cycles_late) { // screen, or if both use the same interrupts and these two instead determine the // beginning and end of the VBlank period. If needed, split the interrupt firing into // two different intervals. - GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); - GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1); + Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC0); + Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1); // Check for user input updates Service::HID::Update(); diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp index 6a6c707a2..e697f84b3 100644 --- a/src/core/hw/y2r.cpp +++ b/src/core/hw/y2r.cpp @@ -18,7 +18,7 @@ namespace HW { namespace Y2R { -using namespace Y2R_U; +using namespace Service::Y2R; static const size_t MAX_TILES = 1024 / 8; static const size_t TILE_SIZE = 8 * 8; diff --git a/src/core/hw/y2r.h b/src/core/hw/y2r.h index 6b6e71bec..25fcd781c 100644 --- a/src/core/hw/y2r.h +++ b/src/core/hw/y2r.h @@ -2,13 +2,16 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -namespace Y2R_U { +#pragma once + +namespace Service { +namespace Y2R { struct ConversionConfiguration; } +} namespace HW { namespace Y2R { - -void PerformConversion(Y2R_U::ConversionConfiguration& cvt); +void PerformConversion(Service::Y2R::ConversionConfiguration& cvt); } } diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h index cfcc21cc4..3f376778a 100644 --- a/src/core/loader/3dsx.h +++ b/src/core/loader/3dsx.h @@ -27,34 +27,14 @@ public: */ static FileType IdentifyType(FileUtil::IOFile& file); - /** - * Returns the type of this file - * @return FileType corresponding to the loaded file - */ FileType GetFileType() override { return IdentifyType(file); } - /** - * Load the bootable file - * @return ResultStatus result of function - */ ResultStatus Load() override; - /** - * Get the icon (typically icon section) of the application - * @param buffer Reference to buffer to store data - * @return ResultStatus result of function - */ ResultStatus ReadIcon(std::vector<u8>& buffer) override; - /** - * Get the RomFS of the application - * @param romfs_file Reference to buffer to store data - * @param offset Offset in the file to the RomFS - * @param size Size of the RomFS in bytes - * @return ResultStatus result of function - */ ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) override; diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index 584bf6e27..862aa90d8 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h @@ -26,18 +26,10 @@ public: */ static FileType IdentifyType(FileUtil::IOFile& file); - /** - * Returns the type of this file - * @return FileType corresponding to the loaded file - */ FileType GetFileType() override { return IdentifyType(file); } - /** - * Load the bootable file - * @return ResultStatus result of function - */ ResultStatus Load() override; private: diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 5e3d46638..a6c2a745f 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -144,6 +144,15 @@ public: } /** + * Get the program id of the application + * @param out_program_id Reference to store program id into + * @return ResultStatus result of function + */ + virtual ResultStatus ReadProgramId(u64& out_program_id) { + return ResultStatus::ErrorNotImplemented; + } + + /** * Get the RomFS of the application * Since the RomFS can be huge, we return a file reference instead of copying to a buffer * @param romfs_file The file containing the RomFS diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index dce7f50f9..a204dc336 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -366,6 +366,18 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) { return LoadSectionExeFS("logo", buffer); } +ResultStatus AppLoader_NCCH::ReadProgramId(u64& out_program_id) { + if (!file.IsOpen()) + return ResultStatus::Error; + + ResultStatus result = LoadExeFS(); + if (result != ResultStatus::Success) + return result; + + out_program_id = ncch_header.program_id; + return ResultStatus::Success; +} + ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { if (!file.IsOpen()) diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index e9e11727b..fe08f5b45 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h @@ -171,18 +171,10 @@ public: */ static FileType IdentifyType(FileUtil::IOFile& file); - /** - * Returns the type of this file - * @return FileType corresponding to the loaded file - */ FileType GetFileType() override { return IdentifyType(file); } - /** - * Load the application - * @return ResultStatus result of function - */ ResultStatus Load() override; /** @@ -191,33 +183,20 @@ public: */ boost::optional<u32> LoadKernelSystemMode(); - /** - * Get the code (typically .code section) of the application - * @param buffer Reference to buffer to store data - * @return ResultStatus result of function - */ ResultStatus ReadCode(std::vector<u8>& buffer) override; - /** - * Get the icon (typically icon section) of the application - * @param buffer Reference to buffer to store data - * @return ResultStatus result of function - */ ResultStatus ReadIcon(std::vector<u8>& buffer) override; - /** - * Get the banner (typically banner section) of the application - * @param buffer Reference to buffer to store data - * @return ResultStatus result of function - */ ResultStatus ReadBanner(std::vector<u8>& buffer) override; + ResultStatus ReadLogo(std::vector<u8>& buffer) override; + /** - * Get the logo (typically logo section) of the application - * @param buffer Reference to buffer to store data + * Get the program id of the application + * @param out_program_id Reference to store program id into * @return ResultStatus result of function */ - ResultStatus ReadLogo(std::vector<u8>& buffer) override; + ResultStatus ReadProgramId(u64& out_program_id) override; /** * Get the RomFS of the application diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 626e06cd9..5d23c52f9 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -7,7 +7,7 @@ #include "settings.h" #include "video_core/video_core.h" -#include "common/emu_window.h" +#include "core/frontend/emu_window.h" namespace Settings { diff --git a/src/core/system.cpp b/src/core/system.cpp deleted file mode 100644 index a5f763805..000000000 --- a/src/core/system.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "audio_core/audio_core.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/gdbstub/gdbstub.h" -#include "core/hle/hle.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory.h" -#include "core/hw/hw.h" -#include "core/system.h" -#include "video_core/video_core.h" - -namespace System { - -static bool is_powered_on{false}; - -Result Init(EmuWindow* emu_window, u32 system_mode) { - Core::Init(); - CoreTiming::Init(); - Memory::Init(); - HW::Init(); - Kernel::Init(system_mode); - HLE::Init(); - if (!VideoCore::Init(emu_window)) { - return Result::ErrorInitVideoCore; - } - AudioCore::Init(); - GDBStub::Init(); - - is_powered_on = true; - - return Result::Success; -} - -bool IsPoweredOn() { - return is_powered_on; -} - -void Shutdown() { - GDBStub::Shutdown(); - AudioCore::Shutdown(); - VideoCore::Shutdown(); - HLE::Shutdown(); - Kernel::Shutdown(); - HW::Shutdown(); - CoreTiming::Shutdown(); - Core::Shutdown(); - - is_powered_on = false; -} - -} // namespace diff --git a/src/core/system.h b/src/core/system.h deleted file mode 100644 index b41fc088a..000000000 --- a/src/core/system.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -class EmuWindow; - -namespace System { - -enum class Result { - Success, ///< Everything is fine - Error, ///< Something went wrong (no module specified) - ErrorInitCore, ///< Something went wrong during core init - ErrorInitVideoCore, ///< Something went wrong during video core init -}; - -Result Init(EmuWindow* emu_window, u32 system_mode); -bool IsPoweredOn(); -void Shutdown(); -} |