From c6d7da88c7ab125279ea4ccad0e3e839632b2f7a Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 14 Jul 2021 00:52:17 -0400 Subject: service: Append service name prefix to common filenames --- src/core/CMakeLists.txt | 44 +- src/core/core.cpp | 4 +- src/core/hardware_interrupt_manager.cpp | 2 +- src/core/hle/service/acc/acc.cpp | 2 +- src/core/hle/service/acc/acc.h | 2 +- src/core/hle/service/am/am.cpp | 4 +- src/core/hle/service/apm/apm.cpp | 2 +- src/core/hle/service/apm/apm_controller.cpp | 89 ++++ src/core/hle/service/apm/apm_controller.h | 70 +++ src/core/hle/service/apm/apm_interface.cpp | 138 +++++ src/core/hle/service/apm/apm_interface.h | 43 ++ src/core/hle/service/apm/controller.cpp | 89 ---- src/core/hle/service/apm/controller.h | 70 --- src/core/hle/service/apm/interface.cpp | 138 ----- src/core/hle/service/apm/interface.h | 43 -- src/core/hle/service/bcat/bcat.h | 2 +- src/core/hle/service/bcat/bcat_module.cpp | 610 +++++++++++++++++++++++ src/core/hle/service/bcat/bcat_module.h | 48 ++ src/core/hle/service/bcat/module.cpp | 610 ----------------------- src/core/hle/service/bcat/module.h | 48 -- src/core/hle/service/friend/friend.cpp | 2 +- src/core/hle/service/friend/friend_interface.cpp | 21 + src/core/hle/service/friend/friend_interface.h | 17 + src/core/hle/service/friend/interface.cpp | 21 - src/core/hle/service/friend/interface.h | 17 - src/core/hle/service/glue/arp.cpp | 2 +- src/core/hle/service/glue/glue_manager.cpp | 78 +++ src/core/hle/service/glue/glue_manager.h | 63 +++ src/core/hle/service/glue/manager.cpp | 78 --- src/core/hle/service/glue/manager.h | 63 --- src/core/hle/service/mii/manager.cpp | 465 ----------------- src/core/hle/service/mii/manager.h | 333 ------------- src/core/hle/service/mii/mii.cpp | 2 +- src/core/hle/service/mii/mii_manager.cpp | 465 +++++++++++++++++ src/core/hle/service/mii/mii_manager.h | 333 +++++++++++++ src/core/hle/service/mii/raw_data.h | 2 +- src/core/hle/service/nvdrv/interface.cpp | 259 ---------- src/core/hle/service/nvdrv/interface.h | 45 -- src/core/hle/service/nvdrv/nvdrv.cpp | 2 +- src/core/hle/service/nvdrv/nvdrv_interface.cpp | 259 ++++++++++ src/core/hle/service/nvdrv/nvdrv_interface.h | 45 ++ src/core/hle/service/pctl/module.cpp | 406 --------------- src/core/hle/service/pctl/module.h | 49 -- src/core/hle/service/pctl/pctl.h | 2 +- src/core/hle/service/pctl/pctl_module.cpp | 406 +++++++++++++++ src/core/hle/service/pctl/pctl_module.h | 49 ++ src/core/hle/service/service.cpp | 6 +- src/core/hle/service/sm/controller.cpp | 80 --- src/core/hle/service/sm/controller.h | 27 - src/core/hle/service/sm/sm.cpp | 2 +- src/core/hle/service/sm/sm_controller.cpp | 80 +++ src/core/hle/service/sm/sm_controller.h | 27 + src/core/hle/service/spl/csrng.h | 2 +- src/core/hle/service/spl/module.cpp | 175 ------- src/core/hle/service/spl/module.h | 48 -- src/core/hle/service/spl/spl.h | 2 +- src/core/hle/service/spl/spl_module.cpp | 175 +++++++ src/core/hle/service/spl/spl_module.h | 48 ++ src/core/hle/service/time/interface.cpp | 42 -- src/core/hle/service/time/interface.h | 21 - src/core/hle/service/time/time.cpp | 2 +- src/core/hle/service/time/time_interface.cpp | 42 ++ src/core/hle/service/time/time_interface.h | 21 + 63 files changed, 3171 insertions(+), 3171 deletions(-) create mode 100644 src/core/hle/service/apm/apm_controller.cpp create mode 100644 src/core/hle/service/apm/apm_controller.h create mode 100644 src/core/hle/service/apm/apm_interface.cpp create mode 100644 src/core/hle/service/apm/apm_interface.h delete mode 100644 src/core/hle/service/apm/controller.cpp delete mode 100644 src/core/hle/service/apm/controller.h delete mode 100644 src/core/hle/service/apm/interface.cpp delete mode 100644 src/core/hle/service/apm/interface.h create mode 100644 src/core/hle/service/bcat/bcat_module.cpp create mode 100644 src/core/hle/service/bcat/bcat_module.h delete mode 100644 src/core/hle/service/bcat/module.cpp delete mode 100644 src/core/hle/service/bcat/module.h create mode 100644 src/core/hle/service/friend/friend_interface.cpp create mode 100644 src/core/hle/service/friend/friend_interface.h delete mode 100644 src/core/hle/service/friend/interface.cpp delete mode 100644 src/core/hle/service/friend/interface.h create mode 100644 src/core/hle/service/glue/glue_manager.cpp create mode 100644 src/core/hle/service/glue/glue_manager.h delete mode 100644 src/core/hle/service/glue/manager.cpp delete mode 100644 src/core/hle/service/glue/manager.h delete mode 100644 src/core/hle/service/mii/manager.cpp delete mode 100644 src/core/hle/service/mii/manager.h create mode 100644 src/core/hle/service/mii/mii_manager.cpp create mode 100644 src/core/hle/service/mii/mii_manager.h delete mode 100644 src/core/hle/service/nvdrv/interface.cpp delete mode 100644 src/core/hle/service/nvdrv/interface.h create mode 100644 src/core/hle/service/nvdrv/nvdrv_interface.cpp create mode 100644 src/core/hle/service/nvdrv/nvdrv_interface.h delete mode 100644 src/core/hle/service/pctl/module.cpp delete mode 100644 src/core/hle/service/pctl/module.h create mode 100644 src/core/hle/service/pctl/pctl_module.cpp create mode 100644 src/core/hle/service/pctl/pctl_module.h delete mode 100644 src/core/hle/service/sm/controller.cpp delete mode 100644 src/core/hle/service/sm/controller.h create mode 100644 src/core/hle/service/sm/sm_controller.cpp create mode 100644 src/core/hle/service/sm/sm_controller.h delete mode 100644 src/core/hle/service/spl/module.cpp delete mode 100644 src/core/hle/service/spl/module.h create mode 100644 src/core/hle/service/spl/spl_module.cpp create mode 100644 src/core/hle/service/spl/spl_module.h delete mode 100644 src/core/hle/service/time/interface.cpp delete mode 100644 src/core/hle/service/time/interface.h create mode 100644 src/core/hle/service/time/time_interface.cpp create mode 100644 src/core/hle/service/time/time_interface.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 48b16f8f7..c7b899131 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -300,10 +300,10 @@ add_library(core STATIC hle/service/aoc/aoc_u.h hle/service/apm/apm.cpp hle/service/apm/apm.h - hle/service/apm/controller.cpp - hle/service/apm/controller.h - hle/service/apm/interface.cpp - hle/service/apm/interface.h + hle/service/apm/apm_controller.cpp + hle/service/apm/apm_controller.h + hle/service/apm/apm_interface.cpp + hle/service/apm/apm_interface.h hle/service/audio/audctl.cpp hle/service/audio/audctl.h hle/service/audio/auddbg.cpp @@ -335,8 +335,8 @@ add_library(core STATIC hle/service/bcat/backend/backend.h hle/service/bcat/bcat.cpp hle/service/bcat/bcat.h - hle/service/bcat/module.cpp - hle/service/bcat/module.h + hle/service/bcat/bcat_module.cpp + hle/service/bcat/bcat_module.h hle/service/bpc/bpc.cpp hle/service/bpc/bpc.h hle/service/btdrv/btdrv.cpp @@ -382,8 +382,8 @@ add_library(core STATIC hle/service/friend/errors.h hle/service/friend/friend.cpp hle/service/friend/friend.h - hle/service/friend/interface.cpp - hle/service/friend/interface.h + hle/service/friend/friend_interface.cpp + hle/service/friend/friend_interface.h hle/service/glue/arp.cpp hle/service/glue/arp.h hle/service/glue/bgtc.cpp @@ -393,8 +393,8 @@ add_library(core STATIC hle/service/glue/errors.h hle/service/glue/glue.cpp hle/service/glue/glue.h - hle/service/glue/manager.cpp - hle/service/glue/manager.h + hle/service/glue/glue_manager.cpp + hle/service/glue/glue_manager.h hle/service/grc/grc.cpp hle/service/grc/grc.h hle/service/hid/hid.cpp @@ -435,10 +435,10 @@ add_library(core STATIC hle/service/lm/lm.h hle/service/mig/mig.cpp hle/service/mig/mig.h - hle/service/mii/manager.cpp - hle/service/mii/manager.h hle/service/mii/mii.cpp hle/service/mii/mii.h + hle/service/mii/mii_manager.cpp + hle/service/mii/mii_manager.h hle/service/mii/raw_data.cpp hle/service/mii/raw_data.h hle/service/mii/types.h @@ -486,11 +486,11 @@ add_library(core STATIC hle/service/nvdrv/devices/nvhost_vic.h hle/service/nvdrv/devices/nvmap.cpp hle/service/nvdrv/devices/nvmap.h - hle/service/nvdrv/interface.cpp - hle/service/nvdrv/interface.h hle/service/nvdrv/nvdata.h hle/service/nvdrv/nvdrv.cpp hle/service/nvdrv/nvdrv.h + hle/service/nvdrv/nvdrv_interface.cpp + hle/service/nvdrv/nvdrv_interface.h hle/service/nvdrv/nvmemp.cpp hle/service/nvdrv/nvmemp.h hle/service/nvdrv/syncpoint_manager.cpp @@ -503,10 +503,10 @@ add_library(core STATIC hle/service/olsc/olsc.h hle/service/pcie/pcie.cpp hle/service/pcie/pcie.h - hle/service/pctl/module.cpp - hle/service/pctl/module.h hle/service/pctl/pctl.cpp hle/service/pctl/pctl.h + hle/service/pctl/pctl_module.cpp + hle/service/pctl/pctl_module.h hle/service/pcv/pcv.cpp hle/service/pcv/pcv.h hle/service/pm/pm.cpp @@ -529,10 +529,10 @@ add_library(core STATIC hle/service/set/set_sys.h hle/service/set/settings.cpp hle/service/set/settings.h - hle/service/sm/controller.cpp - hle/service/sm/controller.h hle/service/sm/sm.cpp hle/service/sm/sm.h + hle/service/sm/sm_controller.cpp + hle/service/sm/sm_controller.h hle/service/sockets/bsd.cpp hle/service/sockets/bsd.h hle/service/sockets/ethc.cpp @@ -547,10 +547,10 @@ add_library(core STATIC hle/service/sockets/sockets_translate.h hle/service/spl/csrng.cpp hle/service/spl/csrng.h - hle/service/spl/module.cpp - hle/service/spl/module.h hle/service/spl/spl.cpp hle/service/spl/spl.h + hle/service/spl/spl_module.cpp + hle/service/spl/spl_module.h hle/service/spl/spl_results.h hle/service/spl/spl_types.h hle/service/ssl/ssl.cpp @@ -559,8 +559,6 @@ add_library(core STATIC hle/service/time/ephemeral_network_system_clock_context_writer.h hle/service/time/ephemeral_network_system_clock_core.h hle/service/time/errors.h - hle/service/time/interface.cpp - hle/service/time/interface.h hle/service/time/local_system_clock_context_writer.h hle/service/time/network_system_clock_context_writer.h hle/service/time/standard_local_system_clock_core.h @@ -578,6 +576,8 @@ add_library(core STATIC hle/service/time/tick_based_steady_clock_core.h hle/service/time/time.cpp hle/service/time/time.h + hle/service/time/time_interface.cpp + hle/service/time/time_interface.h hle/service/time/time_manager.cpp hle/service/time/time_manager.h hle/service/time/time_sharedmemory.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 891f1cb49..406320ed6 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -35,9 +35,9 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/service/am/applets/applets.h" -#include "core/hle/service/apm/controller.h" +#include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/glue/manager.h" +#include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp index 645f26e91..290db505e 100644 --- a/src/core/hardware_interrupt_manager.cpp +++ b/src/core/hardware_interrupt_manager.cpp @@ -5,7 +5,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hardware_interrupt_manager.h" -#include "core/hle/service/nvdrv/interface.h" +#include "core/hle/service/nvdrv/nvdrv_interface.h" #include "core/hle/service/sm/sm.h" namespace Core::Hardware { diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index d1c1fb71d..2e969f2a8 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -26,7 +26,7 @@ #include "core/hle/service/acc/errors.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/glue/arp.h" -#include "core/hle/service/glue/manager.h" +#include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/sm/sm.h" #include "core/loader/loader.h" diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 0e3ad8ec6..a83a480cd 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -5,7 +5,7 @@ #pragma once #include "common/uuid.h" -#include "core/hle/service/glue/manager.h" +#include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/service.h" namespace Service::Account { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 41f1e6b68..a538f82e3 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -32,8 +32,8 @@ #include "core/hle/service/am/omm.h" #include "core/hle/service/am/spsm.h" #include "core/hle/service/am/tcap.h" -#include "core/hle/service/apm/controller.h" -#include "core/hle/service/apm/interface.h" +#include "core/hle/service/apm/apm_controller.h" +#include "core/hle/service/apm/apm_interface.h" #include "core/hle/service/bcat/backend/backend.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/ns.h" diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index 97d6619dd..f5ebfe8d6 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -5,7 +5,7 @@ #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/apm/apm.h" -#include "core/hle/service/apm/interface.h" +#include "core/hle/service/apm/apm_interface.h" namespace Service::APM { diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp new file mode 100644 index 000000000..98839fe97 --- /dev/null +++ b/src/core/hle/service/apm/apm_controller.cpp @@ -0,0 +1,89 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include + +#include "common/logging/log.h" +#include "common/settings.h" +#include "core/core_timing.h" +#include "core/hle/service/apm/apm_controller.h" + +namespace Service::APM { + +constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7; + +Controller::Controller(Core::Timing::CoreTiming& core_timing_) + : core_timing{core_timing_}, configs{ + {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, + {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, + } {} + +Controller::~Controller() = default; + +void Controller::SetPerformanceConfiguration(PerformanceMode mode, + PerformanceConfiguration config) { + static constexpr std::array, 16> config_to_speed{{ + {PerformanceConfiguration::Config1, 1020}, + {PerformanceConfiguration::Config2, 1020}, + {PerformanceConfiguration::Config3, 1224}, + {PerformanceConfiguration::Config4, 1020}, + {PerformanceConfiguration::Config5, 1020}, + {PerformanceConfiguration::Config6, 1224}, + {PerformanceConfiguration::Config7, 1020}, + {PerformanceConfiguration::Config8, 1020}, + {PerformanceConfiguration::Config9, 1020}, + {PerformanceConfiguration::Config10, 1020}, + {PerformanceConfiguration::Config11, 1020}, + {PerformanceConfiguration::Config12, 1020}, + {PerformanceConfiguration::Config13, 1785}, + {PerformanceConfiguration::Config14, 1785}, + {PerformanceConfiguration::Config15, 1020}, + {PerformanceConfiguration::Config16, 1020}, + }}; + + const auto iter = std::find_if(config_to_speed.cbegin(), config_to_speed.cend(), + [config](const auto& entry) { return entry.first == config; }); + + if (iter == config_to_speed.cend()) { + LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}", config); + return; + } + + SetClockSpeed(iter->second); + configs.insert_or_assign(mode, config); +} + +void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { + constexpr std::array BOOST_MODE_TO_CONFIG_MAP{{ + PerformanceConfiguration::Config7, + PerformanceConfiguration::Config13, + PerformanceConfiguration::Config15, + }}; + + SetPerformanceConfiguration(PerformanceMode::Docked, + BOOST_MODE_TO_CONFIG_MAP.at(static_cast(mode))); +} + +PerformanceMode Controller::GetCurrentPerformanceMode() const { + return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked + : PerformanceMode::Handheld; +} + +PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { + if (configs.find(mode) == configs.end()) { + configs.insert_or_assign(mode, DEFAULT_PERFORMANCE_CONFIGURATION); + } + + return configs[mode]; +} + +void Controller::SetClockSpeed(u32 mhz) { + LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); + // TODO(DarkLordZach): Actually signal core_timing to change clock speed. + // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used. +} + +} // namespace Service::APM diff --git a/src/core/hle/service/apm/apm_controller.h b/src/core/hle/service/apm/apm_controller.h new file mode 100644 index 000000000..8d48e0104 --- /dev/null +++ b/src/core/hle/service/apm/apm_controller.h @@ -0,0 +1,70 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/common_types.h" + +namespace Core::Timing { +class CoreTiming; +} + +namespace Service::APM { + +enum class PerformanceConfiguration : u32 { + Config1 = 0x00010000, + Config2 = 0x00010001, + Config3 = 0x00010002, + Config4 = 0x00020000, + Config5 = 0x00020001, + Config6 = 0x00020002, + Config7 = 0x00020003, + Config8 = 0x00020004, + Config9 = 0x00020005, + Config10 = 0x00020006, + Config11 = 0x92220007, + Config12 = 0x92220008, + Config13 = 0x92220009, + Config14 = 0x9222000A, + Config15 = 0x9222000B, + Config16 = 0x9222000C, +}; + +enum class CpuBoostMode : u32 { + Disabled = 0, + Full = 1, // CPU + GPU -> Config 13, 14, 15, or 16 + Partial = 2, // GPU Only -> Config 15 or 16 +}; + +enum class PerformanceMode : u8 { + Handheld = 0, + Docked = 1, +}; + +// Class to manage the state and change of the emulated system performance. +// Specifically, this deals with PerformanceMode, which corresponds to the system being docked or +// undocked, and PerformanceConfig which specifies the exact CPU, GPU, and Memory clocks to operate +// at. Additionally, this manages 'Boost Mode', which allows games to temporarily overclock the +// system during times of high load -- this simply maps to different PerformanceConfigs to use. +class Controller { +public: + explicit Controller(Core::Timing::CoreTiming& core_timing_); + ~Controller(); + + void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); + void SetFromCpuBoostMode(CpuBoostMode mode); + + PerformanceMode GetCurrentPerformanceMode() const; + PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode); + +private: + void SetClockSpeed(u32 mhz); + + [[maybe_unused]] Core::Timing::CoreTiming& core_timing; + + std::map configs; +}; + +} // namespace Service::APM diff --git a/src/core/hle/service/apm/apm_interface.cpp b/src/core/hle/service/apm/apm_interface.cpp new file mode 100644 index 000000000..e58bad083 --- /dev/null +++ b/src/core/hle/service/apm/apm_interface.cpp @@ -0,0 +1,138 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/apm/apm.h" +#include "core/hle/service/apm/apm_controller.h" +#include "core/hle/service/apm/apm_interface.h" + +namespace Service::APM { + +class ISession final : public ServiceFramework { +public: + explicit ISession(Core::System& system_, Controller& controller_) + : ServiceFramework{system_, "ISession"}, controller{controller_} { + static const FunctionInfo functions[] = { + {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, + {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, + {2, nullptr, "SetCpuOverclockEnabled"}, + }; + RegisterHandlers(functions); + } + +private: + void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto mode = rp.PopEnum(); + const auto config = rp.PopEnum(); + LOG_DEBUG(Service_APM, "called mode={} config={}", mode, config); + + controller.SetPerformanceConfiguration(mode, config); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto mode = rp.PopEnum(); + LOG_DEBUG(Service_APM, "called mode={}", mode); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode)); + } + + Controller& controller; +}; + +APM::APM(Core::System& system_, std::shared_ptr apm_, Controller& controller_, + const char* name) + : ServiceFramework{system_, name}, apm(std::move(apm_)), controller{controller_} { + static const FunctionInfo functions[] = { + {0, &APM::OpenSession, "OpenSession"}, + {1, &APM::GetPerformanceMode, "GetPerformanceMode"}, + {6, &APM::IsCpuOverclockEnabled, "IsCpuOverclockEnabled"}, + }; + RegisterHandlers(functions); +} + +APM::~APM() = default; + +void APM::OpenSession(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_APM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, controller); +} + +void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_APM, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.PushEnum(controller.GetCurrentPerformanceMode()); +} + +void APM::IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_APM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(false); +} + +APM_Sys::APM_Sys(Core::System& system_, Controller& controller_) + : ServiceFramework{system_, "apm:sys"}, controller{controller_} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RequestPerformanceMode"}, + {1, &APM_Sys::GetPerformanceEvent, "GetPerformanceEvent"}, + {2, nullptr, "GetThrottlingState"}, + {3, nullptr, "GetLastThrottlingState"}, + {4, nullptr, "ClearLastThrottlingState"}, + {5, nullptr, "LoadAndApplySettings"}, + {6, &APM_Sys::SetCpuBoostMode, "SetCpuBoostMode"}, + {7, &APM_Sys::GetCurrentPerformanceConfiguration, "GetCurrentPerformanceConfiguration"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +APM_Sys::~APM_Sys() = default; + +void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_APM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, controller); +} + +void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto mode = rp.PopEnum(); + + LOG_DEBUG(Service_APM, "called, mode={:08X}", mode); + + controller.SetFromCpuBoostMode(mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void APM_Sys::GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_APM, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum( + controller.GetCurrentPerformanceConfiguration(controller.GetCurrentPerformanceMode())); +} + +} // namespace Service::APM diff --git a/src/core/hle/service/apm/apm_interface.h b/src/core/hle/service/apm/apm_interface.h new file mode 100644 index 000000000..063ad5308 --- /dev/null +++ b/src/core/hle/service/apm/apm_interface.h @@ -0,0 +1,43 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::APM { + +class Controller; +class Module; + +class APM final : public ServiceFramework { +public: + explicit APM(Core::System& system_, std::shared_ptr apm_, Controller& controller_, + const char* name); + ~APM() override; + +private: + void OpenSession(Kernel::HLERequestContext& ctx); + void GetPerformanceMode(Kernel::HLERequestContext& ctx); + void IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx); + + std::shared_ptr apm; + Controller& controller; +}; + +class APM_Sys final : public ServiceFramework { +public: + explicit APM_Sys(Core::System& system_, Controller& controller); + ~APM_Sys() override; + + void SetCpuBoostMode(Kernel::HLERequestContext& ctx); + +private: + void GetPerformanceEvent(Kernel::HLERequestContext& ctx); + void GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx); + + Controller& controller; +}; + +} // namespace Service::APM diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp deleted file mode 100644 index 8bfa7c0e4..000000000 --- a/src/core/hle/service/apm/controller.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include - -#include "common/logging/log.h" -#include "common/settings.h" -#include "core/core_timing.h" -#include "core/hle/service/apm/controller.h" - -namespace Service::APM { - -constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7; - -Controller::Controller(Core::Timing::CoreTiming& core_timing_) - : core_timing{core_timing_}, configs{ - {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, - {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, - } {} - -Controller::~Controller() = default; - -void Controller::SetPerformanceConfiguration(PerformanceMode mode, - PerformanceConfiguration config) { - static constexpr std::array, 16> config_to_speed{{ - {PerformanceConfiguration::Config1, 1020}, - {PerformanceConfiguration::Config2, 1020}, - {PerformanceConfiguration::Config3, 1224}, - {PerformanceConfiguration::Config4, 1020}, - {PerformanceConfiguration::Config5, 1020}, - {PerformanceConfiguration::Config6, 1224}, - {PerformanceConfiguration::Config7, 1020}, - {PerformanceConfiguration::Config8, 1020}, - {PerformanceConfiguration::Config9, 1020}, - {PerformanceConfiguration::Config10, 1020}, - {PerformanceConfiguration::Config11, 1020}, - {PerformanceConfiguration::Config12, 1020}, - {PerformanceConfiguration::Config13, 1785}, - {PerformanceConfiguration::Config14, 1785}, - {PerformanceConfiguration::Config15, 1020}, - {PerformanceConfiguration::Config16, 1020}, - }}; - - const auto iter = std::find_if(config_to_speed.cbegin(), config_to_speed.cend(), - [config](const auto& entry) { return entry.first == config; }); - - if (iter == config_to_speed.cend()) { - LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}", config); - return; - } - - SetClockSpeed(iter->second); - configs.insert_or_assign(mode, config); -} - -void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { - constexpr std::array BOOST_MODE_TO_CONFIG_MAP{{ - PerformanceConfiguration::Config7, - PerformanceConfiguration::Config13, - PerformanceConfiguration::Config15, - }}; - - SetPerformanceConfiguration(PerformanceMode::Docked, - BOOST_MODE_TO_CONFIG_MAP.at(static_cast(mode))); -} - -PerformanceMode Controller::GetCurrentPerformanceMode() const { - return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked - : PerformanceMode::Handheld; -} - -PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { - if (configs.find(mode) == configs.end()) { - configs.insert_or_assign(mode, DEFAULT_PERFORMANCE_CONFIGURATION); - } - - return configs[mode]; -} - -void Controller::SetClockSpeed(u32 mhz) { - LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); - // TODO(DarkLordZach): Actually signal core_timing to change clock speed. - // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used. -} - -} // namespace Service::APM diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h deleted file mode 100644 index 8d48e0104..000000000 --- a/src/core/hle/service/apm/controller.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "common/common_types.h" - -namespace Core::Timing { -class CoreTiming; -} - -namespace Service::APM { - -enum class PerformanceConfiguration : u32 { - Config1 = 0x00010000, - Config2 = 0x00010001, - Config3 = 0x00010002, - Config4 = 0x00020000, - Config5 = 0x00020001, - Config6 = 0x00020002, - Config7 = 0x00020003, - Config8 = 0x00020004, - Config9 = 0x00020005, - Config10 = 0x00020006, - Config11 = 0x92220007, - Config12 = 0x92220008, - Config13 = 0x92220009, - Config14 = 0x9222000A, - Config15 = 0x9222000B, - Config16 = 0x9222000C, -}; - -enum class CpuBoostMode : u32 { - Disabled = 0, - Full = 1, // CPU + GPU -> Config 13, 14, 15, or 16 - Partial = 2, // GPU Only -> Config 15 or 16 -}; - -enum class PerformanceMode : u8 { - Handheld = 0, - Docked = 1, -}; - -// Class to manage the state and change of the emulated system performance. -// Specifically, this deals with PerformanceMode, which corresponds to the system being docked or -// undocked, and PerformanceConfig which specifies the exact CPU, GPU, and Memory clocks to operate -// at. Additionally, this manages 'Boost Mode', which allows games to temporarily overclock the -// system during times of high load -- this simply maps to different PerformanceConfigs to use. -class Controller { -public: - explicit Controller(Core::Timing::CoreTiming& core_timing_); - ~Controller(); - - void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); - void SetFromCpuBoostMode(CpuBoostMode mode); - - PerformanceMode GetCurrentPerformanceMode() const; - PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode); - -private: - void SetClockSpeed(u32 mhz); - - [[maybe_unused]] Core::Timing::CoreTiming& core_timing; - - std::map configs; -}; - -} // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp deleted file mode 100644 index d69ddd135..000000000 --- a/src/core/hle/service/apm/interface.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/apm/apm.h" -#include "core/hle/service/apm/controller.h" -#include "core/hle/service/apm/interface.h" - -namespace Service::APM { - -class ISession final : public ServiceFramework { -public: - explicit ISession(Core::System& system_, Controller& controller_) - : ServiceFramework{system_, "ISession"}, controller{controller_} { - static const FunctionInfo functions[] = { - {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, - {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, - {2, nullptr, "SetCpuOverclockEnabled"}, - }; - RegisterHandlers(functions); - } - -private: - void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto mode = rp.PopEnum(); - const auto config = rp.PopEnum(); - LOG_DEBUG(Service_APM, "called mode={} config={}", mode, config); - - controller.SetPerformanceConfiguration(mode, config); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto mode = rp.PopEnum(); - LOG_DEBUG(Service_APM, "called mode={}", mode); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode)); - } - - Controller& controller; -}; - -APM::APM(Core::System& system_, std::shared_ptr apm_, Controller& controller_, - const char* name) - : ServiceFramework{system_, name}, apm(std::move(apm_)), controller{controller_} { - static const FunctionInfo functions[] = { - {0, &APM::OpenSession, "OpenSession"}, - {1, &APM::GetPerformanceMode, "GetPerformanceMode"}, - {6, &APM::IsCpuOverclockEnabled, "IsCpuOverclockEnabled"}, - }; - RegisterHandlers(functions); -} - -APM::~APM() = default; - -void APM::OpenSession(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_APM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, controller); -} - -void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_APM, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.PushEnum(controller.GetCurrentPerformanceMode()); -} - -void APM::IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_APM, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(false); -} - -APM_Sys::APM_Sys(Core::System& system_, Controller& controller_) - : ServiceFramework{system_, "apm:sys"}, controller{controller_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RequestPerformanceMode"}, - {1, &APM_Sys::GetPerformanceEvent, "GetPerformanceEvent"}, - {2, nullptr, "GetThrottlingState"}, - {3, nullptr, "GetLastThrottlingState"}, - {4, nullptr, "ClearLastThrottlingState"}, - {5, nullptr, "LoadAndApplySettings"}, - {6, &APM_Sys::SetCpuBoostMode, "SetCpuBoostMode"}, - {7, &APM_Sys::GetCurrentPerformanceConfiguration, "GetCurrentPerformanceConfiguration"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -APM_Sys::~APM_Sys() = default; - -void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_APM, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, controller); -} - -void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto mode = rp.PopEnum(); - - LOG_DEBUG(Service_APM, "called, mode={:08X}", mode); - - controller.SetFromCpuBoostMode(mode); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void APM_Sys::GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_APM, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum( - controller.GetCurrentPerformanceConfiguration(controller.GetCurrentPerformanceMode())); -} - -} // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h deleted file mode 100644 index 063ad5308..000000000 --- a/src/core/hle/service/apm/interface.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -namespace Service::APM { - -class Controller; -class Module; - -class APM final : public ServiceFramework { -public: - explicit APM(Core::System& system_, std::shared_ptr apm_, Controller& controller_, - const char* name); - ~APM() override; - -private: - void OpenSession(Kernel::HLERequestContext& ctx); - void GetPerformanceMode(Kernel::HLERequestContext& ctx); - void IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx); - - std::shared_ptr apm; - Controller& controller; -}; - -class APM_Sys final : public ServiceFramework { -public: - explicit APM_Sys(Core::System& system_, Controller& controller); - ~APM_Sys() override; - - void SetCpuBoostMode(Kernel::HLERequestContext& ctx); - -private: - void GetPerformanceEvent(Kernel::HLERequestContext& ctx); - void GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx); - - Controller& controller; -}; - -} // namespace Service::APM diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h index d72798980..1eba477da 100644 --- a/src/core/hle/service/bcat/bcat.h +++ b/src/core/hle/service/bcat/bcat.h @@ -4,7 +4,7 @@ #pragma once -#include "core/hle/service/bcat/module.h" +#include "core/hle/service/bcat/bcat_module.h" namespace Core { class System; diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp new file mode 100644 index 000000000..72294eb2e --- /dev/null +++ b/src/core/hle/service/bcat/bcat_module.cpp @@ -0,0 +1,610 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "backend/boxcat.h" +#include "common/hex_util.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/vfs.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/service/bcat/backend/backend.h" +#include "core/hle/service/bcat/bcat.h" +#include "core/hle/service/bcat/bcat_module.h" +#include "core/hle/service/filesystem/filesystem.h" + +namespace Service::BCAT { + +constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1}; +constexpr ResultCode ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2}; +constexpr ResultCode ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6}; +constexpr ResultCode ERROR_NO_OPEN_ENTITY{ErrorModule::BCAT, 7}; + +// The command to clear the delivery cache just calls fs IFileSystem DeleteFile on all of the files +// and if any of them have a non-zero result it just forwards that result. This is the FS error code +// for permission denied, which is the closest approximation of this scenario. +constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400}; + +using BCATDigest = std::array; + +namespace { + +u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) { + u64 out{}; + std::memcpy(&out, id.data(), sizeof(u64)); + return out; +} + +// The digest is only used to determine if a file is unique compared to others of the same name. +// Since the algorithm isn't ever checked in game, MD5 is safe. +BCATDigest DigestFile(const FileSys::VirtualFile& file) { + BCATDigest out{}; + const auto bytes = file->ReadAllBytes(); + mbedtls_md5_ret(bytes.data(), bytes.size(), out.data()); + return out; +} + +// For a name to be valid it must be non-empty, must have a null terminating character as the final +// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if +// file. +bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array name, + char match_char) { + const auto null_chars = std::count(name.begin(), name.end(), 0); + const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) { + return !std::isalnum(static_cast(c)) && c != '_' && c != match_char && c != '\0'; + }); + if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') { + LOG_ERROR(Service_BCAT, "Name passed was invalid!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return false; + } + + return true; +} + +bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) { + return VerifyNameValidInternal(ctx, name, '-'); +} + +bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) { + return VerifyNameValidInternal(ctx, name, '.'); +} + +} // Anonymous namespace + +struct DeliveryCacheDirectoryEntry { + FileName name; + u64 size; + BCATDigest digest; +}; + +class IDeliveryCacheProgressService final : public ServiceFramework { +public: + explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_, + const DeliveryCacheProgressImpl& impl_) + : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, + {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(event); + } + + void GetImpl(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + ctx.WriteBuffer(impl); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + Kernel::KReadableEvent& event; + const DeliveryCacheProgressImpl& impl; +}; + +class IBcatService final : public ServiceFramework { +public: + explicit IBcatService(Core::System& system_, Backend& backend_) + : ServiceFramework{system_, "IBcatService"}, backend{backend_}, + progress{{ + ProgressServiceBackend{system_.Kernel(), "Normal"}, + ProgressServiceBackend{system_.Kernel(), "Directory"}, + }} { + // clang-format off + static const FunctionInfo functions[] = { + {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"}, + {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"}, + {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, + {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, + {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, + {20300, nullptr, "GetDeliveryCacheStorageUpdateNotifier"}, + {20301, nullptr, "RequestSuspendDeliveryTask"}, + {20400, nullptr, "RegisterSystemApplicationDeliveryTask"}, + {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"}, + {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"}, + {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, + {30101, nullptr, "Unknown"}, + {30102, nullptr, "Unknown2"}, + {30200, nullptr, "RegisterBackgroundDeliveryTask"}, + {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, + {30202, nullptr, "BlockDeliveryTask"}, + {30203, nullptr, "UnblockDeliveryTask"}, + {30210, nullptr, "SetDeliveryTaskTimer"}, + {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"}, + {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, + {90101, nullptr, "Unknown90101"}, + {90200, nullptr, "GetDeliveryList"}, + {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, + {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"}, + {90300, nullptr, "GetPushNotificationLog"}, + {90301, nullptr, "Unknown90301"}, + }; + // clang-format on + RegisterHandlers(functions); + } + +private: + enum class SyncType { + Normal, + Directory, + Count, + }; + + std::shared_ptr CreateProgressService(SyncType type) { + auto& progress_backend{GetProgressBackend(type)}; + return std::make_shared(system, progress_backend.GetEvent(), + progress_backend.GetImpl()); + } + + void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + backend.Synchronize({system.CurrentProcess()->GetTitleID(), + GetCurrentBuildID(system.GetCurrentProcessBuildID())}, + GetProgressBackend(SyncType::Normal)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(CreateProgressService(SyncType::Normal)); + } + + void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto name_raw = rp.PopRaw(); + const auto name = + Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, name={}", name); + + backend.SynchronizeDirectory({system.CurrentProcess()->GetTitleID(), + GetCurrentBuildID(system.GetCurrentProcessBuildID())}, + name, GetProgressBackend(SyncType::Directory)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(CreateProgressService(SyncType::Directory)); + } + + void SetPassphrase(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw(); + + const auto passphrase_raw = ctx.ReadBuffer(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, + Common::HexToString(passphrase_raw)); + + if (title_id == 0) { + LOG_ERROR(Service_BCAT, "Invalid title ID!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + } + + if (passphrase_raw.size() > 0x40) { + LOG_ERROR(Service_BCAT, "Passphrase too large!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + Passphrase passphrase{}; + std::memcpy(passphrase.data(), passphrase_raw.data(), + std::min(passphrase.size(), passphrase_raw.size())); + + backend.SetPassphrase(title_id, passphrase); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); + + if (title_id == 0) { + LOG_ERROR(Service_BCAT, "Invalid title ID!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + if (!backend.Clear(title_id)) { + LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_CLEAR_CACHE); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + ProgressServiceBackend& GetProgressBackend(SyncType type) { + return progress.at(static_cast(type)); + } + + const ProgressServiceBackend& GetProgressBackend(SyncType type) const { + return progress.at(static_cast(type)); + } + + Backend& backend; + std::array(SyncType::Count)> progress; +}; + +void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, *backend); +} + +class IDeliveryCacheFileService final : public ServiceFramework { +public: + explicit IDeliveryCacheFileService(Core::System& system_, FileSys::VirtualDir root_) + : ServiceFramework{system_, "IDeliveryCacheFileService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheFileService::Open, "Open"}, + {1, &IDeliveryCacheFileService::Read, "Read"}, + {2, &IDeliveryCacheFileService::GetSize, "GetSize"}, + {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Open(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto dir_name_raw = rp.PopRaw(); + const auto file_name_raw = rp.PopRaw(); + + const auto dir_name = + Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size()); + const auto file_name = + Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name); + + if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw)) + return; + + if (current_file != nullptr) { + LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_ENTITY_ALREADY_OPEN); + return; + } + + const auto dir = root->GetSubdirectory(dir_name); + + if (dir == nullptr) { + LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + current_file = dir->GetFile(file_name); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto offset{rp.PopRaw()}; + + auto size = ctx.GetWriteBufferSize(); + + LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + size = std::min(current_file->GetSize() - offset, size); + const auto buffer = current_file->ReadBytes(size, offset); + ctx.WriteBuffer(buffer); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(buffer.size()); + } + + void GetSize(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(current_file->GetSize()); + } + + void GetDigest(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_file == nullptr) { + LOG_ERROR(Service_BCAT, "There is no file currently open!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + } + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(DigestFile(current_file)); + } + + FileSys::VirtualDir root; + FileSys::VirtualFile current_file; +}; + +class IDeliveryCacheDirectoryService final + : public ServiceFramework { +public: + explicit IDeliveryCacheDirectoryService(Core::System& system_, FileSys::VirtualDir root_) + : ServiceFramework{system_, "IDeliveryCacheDirectoryService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheDirectoryService::Open, "Open"}, + {1, &IDeliveryCacheDirectoryService::Read, "Read"}, + {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Open(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto name_raw = rp.PopRaw(); + const auto name = + Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); + + LOG_DEBUG(Service_BCAT, "called, name={}", name); + + if (!VerifyNameValidDir(ctx, name_raw)) + return; + + if (current_dir != nullptr) { + LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_ENTITY_ALREADY_OPEN); + return; + } + + current_dir = root->GetSubdirectory(name); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_FAILED_OPEN_ENTITY); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Read(Kernel::HLERequestContext& ctx) { + auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); + + LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "There is no open directory!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + return; + } + + const auto files = current_dir->GetFiles(); + write_size = std::min(write_size, files.size()); + std::vector entries(write_size); + std::transform( + files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { + FileName name{}; + std::memcpy(name.data(), file->GetName().data(), + std::min(file->GetName().size(), name.size())); + return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)}; + }); + + ctx.WriteBuffer(entries); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(write_size * sizeof(DeliveryCacheDirectoryEntry))); + } + + void GetCount(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + if (current_dir == nullptr) { + LOG_ERROR(Service_BCAT, "There is no open directory!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_NO_OPEN_ENTITY); + return; + } + + const auto files = current_dir->GetFiles(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(files.size())); + } + + FileSys::VirtualDir root; + FileSys::VirtualDir current_dir; +}; + +class IDeliveryCacheStorageService final : public ServiceFramework { +public: + explicit IDeliveryCacheStorageService(Core::System& system_, FileSys::VirtualDir root_) + : ServiceFramework{system_, "IDeliveryCacheStorageService"}, root(std::move(root_)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, + {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"}, + {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"}, + }; + // clang-format on + + RegisterHandlers(functions); + + for (const auto& subdir : root->GetSubdirectories()) { + DirectoryName name{}; + std::memcpy(name.data(), subdir->GetName().data(), + std::min(sizeof(DirectoryName) - 1, subdir->GetName().size())); + entries.push_back(name); + } + } + +private: + void CreateFileService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, root); + } + + void CreateDirectoryService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, root); + } + + void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { + auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName); + + LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); + + size = std::min(size, entries.size() - next_read_index); + ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName)); + next_read_index += size; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(size)); + } + + FileSys::VirtualDir root; + std::vector entries; + u64 next_read_index = 0; +}; + +void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_BCAT, "called"); + + const auto title_id = system.CurrentProcess()->GetTitleID(); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, fsc.GetBCATDirectory(title_id)); +} + +void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( + Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto title_id = rp.PopRaw(); + + LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, fsc.GetBCATDirectory(title_id)); +} + +std::unique_ptr CreateBackendFromSettings([[maybe_unused]] Core::System& system, + DirectoryGetter getter) { +#ifdef YUZU_ENABLE_BOXCAT + if (Settings::values.bcat_backend.GetValue() == "boxcat") { + return std::make_unique(system.GetAppletManager(), std::move(getter)); + } +#endif + + return std::make_unique(std::move(getter)); +} + +Module::Interface::Interface(Core::System& system_, std::shared_ptr module_, + FileSystem::FileSystemController& fsc_, const char* name) + : ServiceFramework{system_, name}, fsc{fsc_}, module{std::move(module_)}, + backend{CreateBackendFromSettings(system_, + [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })} {} + +Module::Interface::~Interface() = default; + +void InstallInterfaces(Core::System& system) { + auto module = std::make_shared(); + std::make_shared(system, module, system.GetFileSystemController(), "bcat:a") + ->InstallAsService(system.ServiceManager()); + std::make_shared(system, module, system.GetFileSystemController(), "bcat:m") + ->InstallAsService(system.ServiceManager()); + std::make_shared(system, module, system.GetFileSystemController(), "bcat:u") + ->InstallAsService(system.ServiceManager()); + std::make_shared(system, module, system.GetFileSystemController(), "bcat:s") + ->InstallAsService(system.ServiceManager()); +} + +} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/bcat_module.h b/src/core/hle/service/bcat/bcat_module.h new file mode 100644 index 000000000..738731c06 --- /dev/null +++ b/src/core/hle/service/bcat/bcat_module.h @@ -0,0 +1,48 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service { + +namespace FileSystem { +class FileSystemController; +} // namespace FileSystem + +namespace BCAT { + +class Backend; + +class Module final { +public: + class Interface : public ServiceFramework { + public: + explicit Interface(Core::System& system_, std::shared_ptr module_, + FileSystem::FileSystemController& fsc_, const char* name); + ~Interface() override; + + void CreateBcatService(Kernel::HLERequestContext& ctx); + void CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx); + void CreateDeliveryCacheStorageServiceWithApplicationId(Kernel::HLERequestContext& ctx); + + protected: + FileSystem::FileSystemController& fsc; + + std::shared_ptr module; + std::unique_ptr backend; + }; +}; + +/// Registers all BCAT services with the specified service manager. +void InstallInterfaces(Core::System& system); + +} // namespace BCAT + +} // namespace Service diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp deleted file mode 100644 index f85444da8..000000000 --- a/src/core/hle/service/bcat/module.cpp +++ /dev/null @@ -1,610 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include "backend/boxcat.h" -#include "common/hex_util.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/file_sys/vfs.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/kernel/k_writable_event.h" -#include "core/hle/service/bcat/backend/backend.h" -#include "core/hle/service/bcat/bcat.h" -#include "core/hle/service/bcat/module.h" -#include "core/hle/service/filesystem/filesystem.h" - -namespace Service::BCAT { - -constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1}; -constexpr ResultCode ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2}; -constexpr ResultCode ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6}; -constexpr ResultCode ERROR_NO_OPEN_ENTITY{ErrorModule::BCAT, 7}; - -// The command to clear the delivery cache just calls fs IFileSystem DeleteFile on all of the files -// and if any of them have a non-zero result it just forwards that result. This is the FS error code -// for permission denied, which is the closest approximation of this scenario. -constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400}; - -using BCATDigest = std::array; - -namespace { - -u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) { - u64 out{}; - std::memcpy(&out, id.data(), sizeof(u64)); - return out; -} - -// The digest is only used to determine if a file is unique compared to others of the same name. -// Since the algorithm isn't ever checked in game, MD5 is safe. -BCATDigest DigestFile(const FileSys::VirtualFile& file) { - BCATDigest out{}; - const auto bytes = file->ReadAllBytes(); - mbedtls_md5_ret(bytes.data(), bytes.size(), out.data()); - return out; -} - -// For a name to be valid it must be non-empty, must have a null terminating character as the final -// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if -// file. -bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array name, - char match_char) { - const auto null_chars = std::count(name.begin(), name.end(), 0); - const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) { - return !std::isalnum(static_cast(c)) && c != '_' && c != match_char && c != '\0'; - }); - if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') { - LOG_ERROR(Service_BCAT, "Name passed was invalid!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - return false; - } - - return true; -} - -bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) { - return VerifyNameValidInternal(ctx, name, '-'); -} - -bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) { - return VerifyNameValidInternal(ctx, name, '.'); -} - -} // Anonymous namespace - -struct DeliveryCacheDirectoryEntry { - FileName name; - u64 size; - BCATDigest digest; -}; - -class IDeliveryCacheProgressService final : public ServiceFramework { -public: - explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_, - const DeliveryCacheProgressImpl& impl_) - : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, - {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetEvent(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(event); - } - - void GetImpl(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - ctx.WriteBuffer(impl); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - Kernel::KReadableEvent& event; - const DeliveryCacheProgressImpl& impl; -}; - -class IBcatService final : public ServiceFramework { -public: - explicit IBcatService(Core::System& system_, Backend& backend_) - : ServiceFramework{system_, "IBcatService"}, backend{backend_}, - progress{{ - ProgressServiceBackend{system_.Kernel(), "Normal"}, - ProgressServiceBackend{system_.Kernel(), "Directory"}, - }} { - // clang-format off - static const FunctionInfo functions[] = { - {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"}, - {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"}, - {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, - {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, - {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, - {20300, nullptr, "GetDeliveryCacheStorageUpdateNotifier"}, - {20301, nullptr, "RequestSuspendDeliveryTask"}, - {20400, nullptr, "RegisterSystemApplicationDeliveryTask"}, - {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"}, - {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"}, - {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, - {30101, nullptr, "Unknown"}, - {30102, nullptr, "Unknown2"}, - {30200, nullptr, "RegisterBackgroundDeliveryTask"}, - {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, - {30202, nullptr, "BlockDeliveryTask"}, - {30203, nullptr, "UnblockDeliveryTask"}, - {30210, nullptr, "SetDeliveryTaskTimer"}, - {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"}, - {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, - {90101, nullptr, "Unknown90101"}, - {90200, nullptr, "GetDeliveryList"}, - {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, - {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"}, - {90300, nullptr, "GetPushNotificationLog"}, - {90301, nullptr, "Unknown90301"}, - }; - // clang-format on - RegisterHandlers(functions); - } - -private: - enum class SyncType { - Normal, - Directory, - Count, - }; - - std::shared_ptr CreateProgressService(SyncType type) { - auto& progress_backend{GetProgressBackend(type)}; - return std::make_shared(system, progress_backend.GetEvent(), - progress_backend.GetImpl()); - } - - void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - backend.Synchronize({system.CurrentProcess()->GetTitleID(), - GetCurrentBuildID(system.GetCurrentProcessBuildID())}, - GetProgressBackend(SyncType::Normal)); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(CreateProgressService(SyncType::Normal)); - } - - void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto name_raw = rp.PopRaw(); - const auto name = - Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); - - LOG_DEBUG(Service_BCAT, "called, name={}", name); - - backend.SynchronizeDirectory({system.CurrentProcess()->GetTitleID(), - GetCurrentBuildID(system.GetCurrentProcessBuildID())}, - name, GetProgressBackend(SyncType::Directory)); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(CreateProgressService(SyncType::Directory)); - } - - void SetPassphrase(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto title_id = rp.PopRaw(); - - const auto passphrase_raw = ctx.ReadBuffer(); - - LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, - Common::HexToString(passphrase_raw)); - - if (title_id == 0) { - LOG_ERROR(Service_BCAT, "Invalid title ID!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - } - - if (passphrase_raw.size() > 0x40) { - LOG_ERROR(Service_BCAT, "Passphrase too large!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - return; - } - - Passphrase passphrase{}; - std::memcpy(passphrase.data(), passphrase_raw.data(), - std::min(passphrase.size(), passphrase_raw.size())); - - backend.SetPassphrase(title_id, passphrase); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto title_id = rp.PopRaw(); - - LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); - - if (title_id == 0) { - LOG_ERROR(Service_BCAT, "Invalid title ID!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - return; - } - - if (!backend.Clear(title_id)) { - LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_FAILED_CLEAR_CACHE); - return; - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - ProgressServiceBackend& GetProgressBackend(SyncType type) { - return progress.at(static_cast(type)); - } - - const ProgressServiceBackend& GetProgressBackend(SyncType type) const { - return progress.at(static_cast(type)); - } - - Backend& backend; - std::array(SyncType::Count)> progress; -}; - -void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, *backend); -} - -class IDeliveryCacheFileService final : public ServiceFramework { -public: - explicit IDeliveryCacheFileService(Core::System& system_, FileSys::VirtualDir root_) - : ServiceFramework{system_, "IDeliveryCacheFileService"}, root(std::move(root_)) { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IDeliveryCacheFileService::Open, "Open"}, - {1, &IDeliveryCacheFileService::Read, "Read"}, - {2, &IDeliveryCacheFileService::GetSize, "GetSize"}, - {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void Open(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto dir_name_raw = rp.PopRaw(); - const auto file_name_raw = rp.PopRaw(); - - const auto dir_name = - Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size()); - const auto file_name = - Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size()); - - LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name); - - if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw)) - return; - - if (current_file != nullptr) { - LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_ENTITY_ALREADY_OPEN); - return; - } - - const auto dir = root->GetSubdirectory(dir_name); - - if (dir == nullptr) { - LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_FAILED_OPEN_ENTITY); - return; - } - - current_file = dir->GetFile(file_name); - - if (current_file == nullptr) { - LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_FAILED_OPEN_ENTITY); - return; - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Read(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto offset{rp.PopRaw()}; - - auto size = ctx.GetWriteBufferSize(); - - LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size); - - if (current_file == nullptr) { - LOG_ERROR(Service_BCAT, "There is no file currently open!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NO_OPEN_ENTITY); - } - - size = std::min(current_file->GetSize() - offset, size); - const auto buffer = current_file->ReadBytes(size, offset); - ctx.WriteBuffer(buffer); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(buffer.size()); - } - - void GetSize(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - if (current_file == nullptr) { - LOG_ERROR(Service_BCAT, "There is no file currently open!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NO_OPEN_ENTITY); - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(current_file->GetSize()); - } - - void GetDigest(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - if (current_file == nullptr) { - LOG_ERROR(Service_BCAT, "There is no file currently open!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NO_OPEN_ENTITY); - } - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(DigestFile(current_file)); - } - - FileSys::VirtualDir root; - FileSys::VirtualFile current_file; -}; - -class IDeliveryCacheDirectoryService final - : public ServiceFramework { -public: - explicit IDeliveryCacheDirectoryService(Core::System& system_, FileSys::VirtualDir root_) - : ServiceFramework{system_, "IDeliveryCacheDirectoryService"}, root(std::move(root_)) { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IDeliveryCacheDirectoryService::Open, "Open"}, - {1, &IDeliveryCacheDirectoryService::Read, "Read"}, - {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void Open(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto name_raw = rp.PopRaw(); - const auto name = - Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); - - LOG_DEBUG(Service_BCAT, "called, name={}", name); - - if (!VerifyNameValidDir(ctx, name_raw)) - return; - - if (current_dir != nullptr) { - LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_ENTITY_ALREADY_OPEN); - return; - } - - current_dir = root->GetSubdirectory(name); - - if (current_dir == nullptr) { - LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_FAILED_OPEN_ENTITY); - return; - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Read(Kernel::HLERequestContext& ctx) { - auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); - - LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); - - if (current_dir == nullptr) { - LOG_ERROR(Service_BCAT, "There is no open directory!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NO_OPEN_ENTITY); - return; - } - - const auto files = current_dir->GetFiles(); - write_size = std::min(write_size, files.size()); - std::vector entries(write_size); - std::transform( - files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { - FileName name{}; - std::memcpy(name.data(), file->GetName().data(), - std::min(file->GetName().size(), name.size())); - return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)}; - }); - - ctx.WriteBuffer(entries); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(write_size * sizeof(DeliveryCacheDirectoryEntry))); - } - - void GetCount(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - if (current_dir == nullptr) { - LOG_ERROR(Service_BCAT, "There is no open directory!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NO_OPEN_ENTITY); - return; - } - - const auto files = current_dir->GetFiles(); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(files.size())); - } - - FileSys::VirtualDir root; - FileSys::VirtualDir current_dir; -}; - -class IDeliveryCacheStorageService final : public ServiceFramework { -public: - explicit IDeliveryCacheStorageService(Core::System& system_, FileSys::VirtualDir root_) - : ServiceFramework{system_, "IDeliveryCacheStorageService"}, root(std::move(root_)) { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, - {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"}, - {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"}, - }; - // clang-format on - - RegisterHandlers(functions); - - for (const auto& subdir : root->GetSubdirectories()) { - DirectoryName name{}; - std::memcpy(name.data(), subdir->GetName().data(), - std::min(sizeof(DirectoryName) - 1, subdir->GetName().size())); - entries.push_back(name); - } - } - -private: - void CreateFileService(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, root); - } - - void CreateDirectoryService(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, root); - } - - void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { - auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName); - - LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); - - size = std::min(size, entries.size() - next_read_index); - ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName)); - next_read_index += size; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(size)); - } - - FileSys::VirtualDir root; - std::vector entries; - u64 next_read_index = 0; -}; - -void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_BCAT, "called"); - - const auto title_id = system.CurrentProcess()->GetTitleID(); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, fsc.GetBCATDirectory(title_id)); -} - -void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( - Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto title_id = rp.PopRaw(); - - LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, fsc.GetBCATDirectory(title_id)); -} - -std::unique_ptr CreateBackendFromSettings([[maybe_unused]] Core::System& system, - DirectoryGetter getter) { -#ifdef YUZU_ENABLE_BOXCAT - if (Settings::values.bcat_backend.GetValue() == "boxcat") { - return std::make_unique(system.GetAppletManager(), std::move(getter)); - } -#endif - - return std::make_unique(std::move(getter)); -} - -Module::Interface::Interface(Core::System& system_, std::shared_ptr module_, - FileSystem::FileSystemController& fsc_, const char* name) - : ServiceFramework{system_, name}, fsc{fsc_}, module{std::move(module_)}, - backend{CreateBackendFromSettings(system_, - [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })} {} - -Module::Interface::~Interface() = default; - -void InstallInterfaces(Core::System& system) { - auto module = std::make_shared(); - std::make_shared(system, module, system.GetFileSystemController(), "bcat:a") - ->InstallAsService(system.ServiceManager()); - std::make_shared(system, module, system.GetFileSystemController(), "bcat:m") - ->InstallAsService(system.ServiceManager()); - std::make_shared(system, module, system.GetFileSystemController(), "bcat:u") - ->InstallAsService(system.ServiceManager()); - std::make_shared(system, module, system.GetFileSystemController(), "bcat:s") - ->InstallAsService(system.ServiceManager()); -} - -} // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h deleted file mode 100644 index 738731c06..000000000 --- a/src/core/hle/service/bcat/module.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service { - -namespace FileSystem { -class FileSystemController; -} // namespace FileSystem - -namespace BCAT { - -class Backend; - -class Module final { -public: - class Interface : public ServiceFramework { - public: - explicit Interface(Core::System& system_, std::shared_ptr module_, - FileSystem::FileSystemController& fsc_, const char* name); - ~Interface() override; - - void CreateBcatService(Kernel::HLERequestContext& ctx); - void CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx); - void CreateDeliveryCacheStorageServiceWithApplicationId(Kernel::HLERequestContext& ctx); - - protected: - FileSystem::FileSystemController& fsc; - - std::shared_ptr module; - std::unique_ptr backend; - }; -}; - -/// Registers all BCAT services with the specified service manager. -void InstallInterfaces(Core::System& system); - -} // namespace BCAT - -} // namespace Service diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index c5f88bce7..a3c939c0c 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -12,7 +12,7 @@ #include "core/hle/kernel/k_writable_event.h" #include "core/hle/service/friend/errors.h" #include "core/hle/service/friend/friend.h" -#include "core/hle/service/friend/interface.h" +#include "core/hle/service/friend/friend_interface.h" namespace Service::Friend { diff --git a/src/core/hle/service/friend/friend_interface.cpp b/src/core/hle/service/friend/friend_interface.cpp new file mode 100644 index 000000000..9b18b2a32 --- /dev/null +++ b/src/core/hle/service/friend/friend_interface.cpp @@ -0,0 +1,21 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/friend/friend_interface.h" + +namespace Service::Friend { + +Friend::Friend(std::shared_ptr module_, Core::System& system_, const char* name) + : Interface(std::move(module_), system_, name) { + static const FunctionInfo functions[] = { + {0, &Friend::CreateFriendService, "CreateFriendService"}, + {1, &Friend::CreateNotificationService, "CreateNotificationService"}, + {2, nullptr, "CreateDaemonSuspendSessionService"}, + }; + RegisterHandlers(functions); +} + +Friend::~Friend() = default; + +} // namespace Service::Friend diff --git a/src/core/hle/service/friend/friend_interface.h b/src/core/hle/service/friend/friend_interface.h new file mode 100644 index 000000000..43d914b32 --- /dev/null +++ b/src/core/hle/service/friend/friend_interface.h @@ -0,0 +1,17 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/friend/friend.h" + +namespace Service::Friend { + +class Friend final : public Module::Interface { +public: + explicit Friend(std::shared_ptr module_, Core::System& system_, const char* name); + ~Friend() override; +}; + +} // namespace Service::Friend diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp deleted file mode 100644 index 7368ccec2..000000000 --- a/src/core/hle/service/friend/interface.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/service/friend/interface.h" - -namespace Service::Friend { - -Friend::Friend(std::shared_ptr module_, Core::System& system_, const char* name) - : Interface(std::move(module_), system_, name) { - static const FunctionInfo functions[] = { - {0, &Friend::CreateFriendService, "CreateFriendService"}, - {1, &Friend::CreateNotificationService, "CreateNotificationService"}, - {2, nullptr, "CreateDaemonSuspendSessionService"}, - }; - RegisterHandlers(functions); -} - -Friend::~Friend() = default; - -} // namespace Service::Friend diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h deleted file mode 100644 index 43d914b32..000000000 --- a/src/core/hle/service/friend/interface.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/friend/friend.h" - -namespace Service::Friend { - -class Friend final : public Module::Interface { -public: - explicit Friend(std::shared_ptr module_, Core::System& system_, const char* name); - ~Friend() override; -}; - -} // namespace Service::Friend diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index ca25df67e..5a3b54cc1 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp @@ -13,7 +13,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/glue/arp.h" #include "core/hle/service/glue/errors.h" -#include "core/hle/service/glue/manager.h" +#include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/service.h" namespace Service::Glue { diff --git a/src/core/hle/service/glue/glue_manager.cpp b/src/core/hle/service/glue/glue_manager.cpp new file mode 100644 index 000000000..aa9d48c0c --- /dev/null +++ b/src/core/hle/service/glue/glue_manager.cpp @@ -0,0 +1,78 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/glue/errors.h" +#include "core/hle/service/glue/glue_manager.h" + +namespace Service::Glue { + +struct ARPManager::MapEntry { + ApplicationLaunchProperty launch; + std::vector control; +}; + +ARPManager::ARPManager() = default; + +ARPManager::~ARPManager() = default; + +ResultVal ARPManager::GetLaunchProperty(u64 title_id) const { + if (title_id == 0) { + return ERR_INVALID_PROCESS_ID; + } + + const auto iter = entries.find(title_id); + if (iter == entries.end()) { + return ERR_NOT_REGISTERED; + } + + return MakeResult(iter->second.launch); +} + +ResultVal> ARPManager::GetControlProperty(u64 title_id) const { + if (title_id == 0) { + return ERR_INVALID_PROCESS_ID; + } + + const auto iter = entries.find(title_id); + if (iter == entries.end()) { + return ERR_NOT_REGISTERED; + } + + return MakeResult>(iter->second.control); +} + +ResultCode ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch, + std::vector control) { + if (title_id == 0) { + return ERR_INVALID_PROCESS_ID; + } + + const auto iter = entries.find(title_id); + if (iter != entries.end()) { + return ERR_INVALID_ACCESS; + } + + entries.insert_or_assign(title_id, MapEntry{launch, std::move(control)}); + return ResultSuccess; +} + +ResultCode ARPManager::Unregister(u64 title_id) { + if (title_id == 0) { + return ERR_INVALID_PROCESS_ID; + } + + const auto iter = entries.find(title_id); + if (iter == entries.end()) { + return ERR_NOT_REGISTERED; + } + + entries.erase(iter); + return ResultSuccess; +} + +void ARPManager::ResetAll() { + entries.clear(); +} + +} // namespace Service::Glue diff --git a/src/core/hle/service/glue/glue_manager.h b/src/core/hle/service/glue/glue_manager.h new file mode 100644 index 000000000..a7f5ce3ee --- /dev/null +++ b/src/core/hle/service/glue/glue_manager.h @@ -0,0 +1,63 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/common_types.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/romfs_factory.h" +#include "core/hle/result.h" + +namespace Service::Glue { + +struct ApplicationLaunchProperty { + u64 title_id; + u32 version; + FileSys::StorageId base_game_storage_id; + FileSys::StorageId update_storage_id; + u8 program_index; + u8 reserved; +}; +static_assert(sizeof(ApplicationLaunchProperty) == 0x10, + "ApplicationLaunchProperty has incorrect size."); + +// A class to manage state related to the arp:w and arp:r services, specifically the registration +// and unregistration of launch and control properties. +class ARPManager { +public: + ARPManager(); + ~ARPManager(); + + // Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was + // previously registered, otherwise ERR_NOT_REGISTERED if it was never registered or + // ERR_INVALID_PROCESS_ID if the title ID is 0. + ResultVal GetLaunchProperty(u64 title_id) const; + + // Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to + // the provided title ID if it was previously registered, otherwise ERR_NOT_REGISTERED if it was + // never registered or ERR_INVALID_PROCESS_ID if the title ID is 0. + ResultVal> GetControlProperty(u64 title_id) const; + + // Adds a new entry to the internal database with the provided parameters, returning + // ERR_INVALID_ACCESS if attempting to re-register a title ID without an intermediate Unregister + // step, and ERR_INVALID_PROCESS_ID if the title ID is 0. + ResultCode Register(u64 title_id, ApplicationLaunchProperty launch, std::vector control); + + // Removes the registration for the provided title ID from the database, returning + // ERR_NOT_REGISTERED if it doesn't exist in the database and ERR_INVALID_PROCESS_ID if the + // title ID is 0. + ResultCode Unregister(u64 title_id); + + // Removes all entries from the database, always succeeds. Should only be used when resetting + // system state. + void ResetAll(); + +private: + struct MapEntry; + std::map entries; +}; + +} // namespace Service::Glue diff --git a/src/core/hle/service/glue/manager.cpp b/src/core/hle/service/glue/manager.cpp deleted file mode 100644 index 9b1754cf8..000000000 --- a/src/core/hle/service/glue/manager.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/service/glue/errors.h" -#include "core/hle/service/glue/manager.h" - -namespace Service::Glue { - -struct ARPManager::MapEntry { - ApplicationLaunchProperty launch; - std::vector control; -}; - -ARPManager::ARPManager() = default; - -ARPManager::~ARPManager() = default; - -ResultVal ARPManager::GetLaunchProperty(u64 title_id) const { - if (title_id == 0) { - return ERR_INVALID_PROCESS_ID; - } - - const auto iter = entries.find(title_id); - if (iter == entries.end()) { - return ERR_NOT_REGISTERED; - } - - return MakeResult(iter->second.launch); -} - -ResultVal> ARPManager::GetControlProperty(u64 title_id) const { - if (title_id == 0) { - return ERR_INVALID_PROCESS_ID; - } - - const auto iter = entries.find(title_id); - if (iter == entries.end()) { - return ERR_NOT_REGISTERED; - } - - return MakeResult>(iter->second.control); -} - -ResultCode ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch, - std::vector control) { - if (title_id == 0) { - return ERR_INVALID_PROCESS_ID; - } - - const auto iter = entries.find(title_id); - if (iter != entries.end()) { - return ERR_INVALID_ACCESS; - } - - entries.insert_or_assign(title_id, MapEntry{launch, std::move(control)}); - return ResultSuccess; -} - -ResultCode ARPManager::Unregister(u64 title_id) { - if (title_id == 0) { - return ERR_INVALID_PROCESS_ID; - } - - const auto iter = entries.find(title_id); - if (iter == entries.end()) { - return ERR_NOT_REGISTERED; - } - - entries.erase(iter); - return ResultSuccess; -} - -void ARPManager::ResetAll() { - entries.clear(); -} - -} // namespace Service::Glue diff --git a/src/core/hle/service/glue/manager.h b/src/core/hle/service/glue/manager.h deleted file mode 100644 index a7f5ce3ee..000000000 --- a/src/core/hle/service/glue/manager.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "common/common_types.h" -#include "core/file_sys/control_metadata.h" -#include "core/file_sys/romfs_factory.h" -#include "core/hle/result.h" - -namespace Service::Glue { - -struct ApplicationLaunchProperty { - u64 title_id; - u32 version; - FileSys::StorageId base_game_storage_id; - FileSys::StorageId update_storage_id; - u8 program_index; - u8 reserved; -}; -static_assert(sizeof(ApplicationLaunchProperty) == 0x10, - "ApplicationLaunchProperty has incorrect size."); - -// A class to manage state related to the arp:w and arp:r services, specifically the registration -// and unregistration of launch and control properties. -class ARPManager { -public: - ARPManager(); - ~ARPManager(); - - // Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was - // previously registered, otherwise ERR_NOT_REGISTERED if it was never registered or - // ERR_INVALID_PROCESS_ID if the title ID is 0. - ResultVal GetLaunchProperty(u64 title_id) const; - - // Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to - // the provided title ID if it was previously registered, otherwise ERR_NOT_REGISTERED if it was - // never registered or ERR_INVALID_PROCESS_ID if the title ID is 0. - ResultVal> GetControlProperty(u64 title_id) const; - - // Adds a new entry to the internal database with the provided parameters, returning - // ERR_INVALID_ACCESS if attempting to re-register a title ID without an intermediate Unregister - // step, and ERR_INVALID_PROCESS_ID if the title ID is 0. - ResultCode Register(u64 title_id, ApplicationLaunchProperty launch, std::vector control); - - // Removes the registration for the provided title ID from the database, returning - // ERR_NOT_REGISTERED if it doesn't exist in the database and ERR_INVALID_PROCESS_ID if the - // title ID is 0. - ResultCode Unregister(u64 title_id); - - // Removes all entries from the database, always succeeds. Should only be used when resetting - // system state. - void ResetAll(); - -private: - struct MapEntry; - std::map entries; -}; - -} // namespace Service::Glue diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp deleted file mode 100644 index 869d2763f..000000000 --- a/src/core/hle/service/mii/manager.cpp +++ /dev/null @@ -1,465 +0,0 @@ -// Copyright 2020 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include "common/assert.h" -#include "common/logging/log.h" -#include "common/string_util.h" - -#include "core/hle/service/acc/profile_manager.h" -#include "core/hle/service/mii/manager.h" -#include "core/hle/service/mii/raw_data.h" -#include "core/hle/service/mii/types.h" - -namespace Service::Mii { - -namespace { - -constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; - -constexpr std::size_t BaseMiiCount{2}; -constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; - -constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; -constexpr std::array HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; -constexpr std::array EyeColorLookup{8, 9, 10, 11, 12, 13}; -constexpr std::array MouthColorLookup{19, 20, 21, 22, 23}; -constexpr std::array GlassesColorLookup{8, 14, 15, 16, 17, 18, 0}; -constexpr std::array EyeRotateLookup{ - {0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, - 0x04, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04, - 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04}}; -constexpr std::array EyebrowRotateLookup{{0x06, 0x06, 0x05, 0x07, 0x06, 0x07, 0x06, 0x07, - 0x04, 0x07, 0x06, 0x08, 0x05, 0x05, 0x06, 0x06, - 0x07, 0x07, 0x06, 0x06, 0x05, 0x06, 0x07, 0x05}}; - -template -std::array ResizeArray(const std::array& in) { - std::array out{}; - std::memcpy(out.data(), in.data(), sizeof(T) * std::min(SourceArraySize, DestArraySize)); - return out; -} - -MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { - MiiStoreBitFields bf; - std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); - - return { - .uuid = data.data.uuid, - .name = ResizeArray(data.data.name), - .font_region = static_cast(bf.font_region.Value()), - .favorite_color = static_cast(bf.favorite_color.Value()), - .gender = static_cast(bf.gender.Value()), - .height = static_cast(bf.height.Value()), - .build = static_cast(bf.build.Value()), - .type = static_cast(bf.type.Value()), - .region_move = static_cast(bf.region_move.Value()), - .faceline_type = static_cast(bf.faceline_type.Value()), - .faceline_color = static_cast(bf.faceline_color.Value()), - .faceline_wrinkle = static_cast(bf.faceline_wrinkle.Value()), - .faceline_make = static_cast(bf.faceline_makeup.Value()), - .hair_type = static_cast(bf.hair_type.Value()), - .hair_color = static_cast(bf.hair_color.Value()), - .hair_flip = static_cast(bf.hair_flip.Value()), - .eye_type = static_cast(bf.eye_type.Value()), - .eye_color = static_cast(bf.eye_color.Value()), - .eye_scale = static_cast(bf.eye_scale.Value()), - .eye_aspect = static_cast(bf.eye_aspect.Value()), - .eye_rotate = static_cast(bf.eye_rotate.Value()), - .eye_x = static_cast(bf.eye_x.Value()), - .eye_y = static_cast(bf.eye_y.Value()), - .eyebrow_type = static_cast(bf.eyebrow_type.Value()), - .eyebrow_color = static_cast(bf.eyebrow_color.Value()), - .eyebrow_scale = static_cast(bf.eyebrow_scale.Value()), - .eyebrow_aspect = static_cast(bf.eyebrow_aspect.Value()), - .eyebrow_rotate = static_cast(bf.eyebrow_rotate.Value()), - .eyebrow_x = static_cast(bf.eyebrow_x.Value()), - .eyebrow_y = static_cast(bf.eyebrow_y.Value() + 3), - .nose_type = static_cast(bf.nose_type.Value()), - .nose_scale = static_cast(bf.nose_scale.Value()), - .nose_y = static_cast(bf.nose_y.Value()), - .mouth_type = static_cast(bf.mouth_type.Value()), - .mouth_color = static_cast(bf.mouth_color.Value()), - .mouth_scale = static_cast(bf.mouth_scale.Value()), - .mouth_aspect = static_cast(bf.mouth_aspect.Value()), - .mouth_y = static_cast(bf.mouth_y.Value()), - .beard_color = static_cast(bf.beard_color.Value()), - .beard_type = static_cast(bf.beard_type.Value()), - .mustache_type = static_cast(bf.mustache_type.Value()), - .mustache_scale = static_cast(bf.mustache_scale.Value()), - .mustache_y = static_cast(bf.mustache_y.Value()), - .glasses_type = static_cast(bf.glasses_type.Value()), - .glasses_color = static_cast(bf.glasses_color.Value()), - .glasses_scale = static_cast(bf.glasses_scale.Value()), - .glasses_y = static_cast(bf.glasses_y.Value()), - .mole_type = static_cast(bf.mole_type.Value()), - .mole_scale = static_cast(bf.mole_scale.Value()), - .mole_x = static_cast(bf.mole_x.Value()), - .mole_y = static_cast(bf.mole_y.Value()), - .padding = 0, - }; -} - -u16 GenerateCrc16(const void* data, std::size_t size) { - s32 crc{}; - for (std::size_t i = 0; i < size; i++) { - crc ^= static_cast(data)[i] << 8; - for (std::size_t j = 0; j < 8; j++) { - crc <<= 1; - if ((crc & 0x10000) != 0) { - crc = (crc ^ 0x1021) & 0xFFFF; - } - } - } - return Common::swap16(static_cast(crc)); -} - -Common::UUID GenerateValidUUID() { - auto uuid{Common::UUID::Generate()}; - - // Bit 7 must be set, and bit 6 unset for the UUID to be valid - uuid.uuid[1] &= 0xFFFFFFFFFFFFFF3FULL; - uuid.uuid[1] |= 0x0000000000000080ULL; - - return uuid; -} - -template -T GetRandomValue(T min, T max) { - std::random_device device; - std::mt19937 gen(device()); - std::uniform_int_distribution distribution(static_cast(min), static_cast(max)); - return static_cast(distribution(gen)); -} - -template -T GetRandomValue(T max) { - return GetRandomValue({}, max); -} - -MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { - MiiStoreBitFields bf{}; - - if (gender == Gender::All) { - gender = GetRandomValue(Gender::Maximum); - } - - bf.gender.Assign(gender); - bf.favorite_color.Assign(GetRandomValue(11)); - bf.region_move.Assign(0); - bf.font_region.Assign(FontRegion::Standard); - bf.type.Assign(0); - bf.height.Assign(64); - bf.build.Assign(64); - - if (age == Age::All) { - const auto temp{GetRandomValue(10)}; - if (temp >= 8) { - age = Age::Old; - } else if (temp >= 4) { - age = Age::Normal; - } else { - age = Age::Young; - } - } - - if (race == Race::All) { - const auto temp{GetRandomValue(10)}; - if (temp >= 8) { - race = Race::Black; - } else if (temp >= 4) { - race = Race::White; - } else { - race = Race::Asian; - } - } - - u32 axis_y{}; - if (gender == Gender::Female && age == Age::Young) { - axis_y = GetRandomValue(3); - } - - const std::size_t index{3 * static_cast(age) + - 9 * static_cast(gender) + static_cast(race)}; - - const auto faceline_type_info{RawData::RandomMiiFaceline.at(index)}; - const auto faceline_color_info{RawData::RandomMiiFacelineColor.at( - 3 * static_cast(gender) + static_cast(race))}; - const auto faceline_wrinkle_info{RawData::RandomMiiFacelineWrinkle.at(index)}; - const auto faceline_makeup_info{RawData::RandomMiiFacelineMakeup.at(index)}; - const auto hair_type_info{RawData::RandomMiiHairType.at(index)}; - const auto hair_color_info{RawData::RandomMiiHairColor.at(3 * static_cast(race) + - static_cast(age))}; - const auto eye_type_info{RawData::RandomMiiEyeType.at(index)}; - const auto eye_color_info{RawData::RandomMiiEyeColor.at(static_cast(race))}; - const auto eyebrow_type_info{RawData::RandomMiiEyebrowType.at(index)}; - const auto nose_type_info{RawData::RandomMiiNoseType.at(index)}; - const auto mouth_type_info{RawData::RandomMiiMouthType.at(index)}; - const auto glasses_type_info{RawData::RandomMiiGlassType.at(static_cast(age))}; - - bf.faceline_type.Assign( - faceline_type_info.values[GetRandomValue(faceline_type_info.values_count)]); - bf.faceline_color.Assign( - faceline_color_info.values[GetRandomValue(faceline_color_info.values_count)]); - bf.faceline_wrinkle.Assign( - faceline_wrinkle_info - .values[GetRandomValue(faceline_wrinkle_info.values_count)]); - bf.faceline_makeup.Assign( - faceline_makeup_info - .values[GetRandomValue(faceline_makeup_info.values_count)]); - - bf.hair_type.Assign( - hair_type_info.values[GetRandomValue(hair_type_info.values_count)]); - bf.hair_color.Assign( - HairColorLookup[hair_color_info - .values[GetRandomValue(hair_color_info.values_count)]]); - bf.hair_flip.Assign(GetRandomValue(HairFlip::Maximum)); - - bf.eye_type.Assign( - eye_type_info.values[GetRandomValue(eye_type_info.values_count)]); - - const auto eye_rotate_1{gender != Gender::Male ? 4 : 2}; - const auto eye_rotate_2{gender != Gender::Male ? 3 : 4}; - const auto eye_rotate_offset{32 - EyeRotateLookup[eye_rotate_1] + eye_rotate_2}; - const auto eye_rotate{32 - EyeRotateLookup[bf.eye_type]}; - - bf.eye_color.Assign( - EyeColorLookup[eye_color_info - .values[GetRandomValue(eye_color_info.values_count)]]); - bf.eye_scale.Assign(4); - bf.eye_aspect.Assign(3); - bf.eye_rotate.Assign(eye_rotate_offset - eye_rotate); - bf.eye_x.Assign(2); - bf.eye_y.Assign(axis_y + 12); - - bf.eyebrow_type.Assign( - eyebrow_type_info.values[GetRandomValue(eyebrow_type_info.values_count)]); - - const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0}; - const auto eyebrow_y{race == Race::Asian ? 9 : 10}; - const auto eyebrow_rotate_offset{32 - EyebrowRotateLookup[eyebrow_rotate_1] + 6}; - const auto eyebrow_rotate{ - 32 - EyebrowRotateLookup[static_cast(bf.eyebrow_type.Value())]}; - - bf.eyebrow_color.Assign(bf.hair_color); - bf.eyebrow_scale.Assign(4); - bf.eyebrow_aspect.Assign(3); - bf.eyebrow_rotate.Assign(eyebrow_rotate_offset - eyebrow_rotate); - bf.eyebrow_x.Assign(2); - bf.eyebrow_y.Assign(axis_y + eyebrow_y); - - const auto nose_scale{gender == Gender::Female ? 3 : 4}; - - bf.nose_type.Assign( - nose_type_info.values[GetRandomValue(nose_type_info.values_count)]); - bf.nose_scale.Assign(nose_scale); - bf.nose_y.Assign(axis_y + 9); - - const auto mouth_color{gender == Gender::Female ? GetRandomValue(4) : 0}; - - bf.mouth_type.Assign( - mouth_type_info.values[GetRandomValue(mouth_type_info.values_count)]); - bf.mouth_color.Assign(MouthColorLookup[mouth_color]); - bf.mouth_scale.Assign(4); - bf.mouth_aspect.Assign(3); - bf.mouth_y.Assign(axis_y + 13); - - bf.beard_color.Assign(bf.hair_color); - bf.mustache_scale.Assign(4); - - if (gender == Gender::Male && age != Age::Young && GetRandomValue(10) < 2) { - const auto mustache_and_beard_flag{ - GetRandomValue(BeardAndMustacheFlag::All)}; - - auto beard_type{BeardType::None}; - auto mustache_type{MustacheType::None}; - - if ((mustache_and_beard_flag & BeardAndMustacheFlag::Beard) == - BeardAndMustacheFlag::Beard) { - beard_type = GetRandomValue(BeardType::Beard1, BeardType::Beard5); - } - - if ((mustache_and_beard_flag & BeardAndMustacheFlag::Mustache) == - BeardAndMustacheFlag::Mustache) { - mustache_type = - GetRandomValue(MustacheType::Mustache1, MustacheType::Mustache5); - } - - bf.mustache_type.Assign(mustache_type); - bf.beard_type.Assign(beard_type); - bf.mustache_y.Assign(10); - } else { - bf.mustache_type.Assign(MustacheType::None); - bf.beard_type.Assign(BeardType::None); - bf.mustache_y.Assign(axis_y + 10); - } - - const auto glasses_type_start{GetRandomValue(100)}; - u8 glasses_type{}; - while (glasses_type_start < glasses_type_info.values[glasses_type]) { - if (++glasses_type >= glasses_type_info.values_count) { - UNREACHABLE(); - break; - } - } - - bf.glasses_type.Assign(glasses_type); - bf.glasses_color.Assign(GlassesColorLookup[0]); - bf.glasses_scale.Assign(4); - bf.glasses_y.Assign(axis_y + 10); - - bf.mole_type.Assign(0); - bf.mole_scale.Assign(4); - bf.mole_x.Assign(2); - bf.mole_y.Assign(20); - - return {DefaultMiiName, bf, user_id}; -} - -MiiStoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) { - MiiStoreBitFields bf{}; - - bf.font_region.Assign(info.font_region); - bf.favorite_color.Assign(info.favorite_color); - bf.gender.Assign(info.gender); - bf.height.Assign(info.height); - bf.build.Assign(info.weight); - bf.type.Assign(info.type); - bf.region_move.Assign(info.region); - bf.faceline_type.Assign(info.face_type); - bf.faceline_color.Assign(info.face_color); - bf.faceline_wrinkle.Assign(info.face_wrinkle); - bf.faceline_makeup.Assign(info.face_makeup); - bf.hair_type.Assign(info.hair_type); - bf.hair_color.Assign(HairColorLookup[info.hair_color]); - bf.hair_flip.Assign(static_cast(info.hair_flip)); - bf.eye_type.Assign(info.eye_type); - bf.eye_color.Assign(EyeColorLookup[info.eye_color]); - bf.eye_scale.Assign(info.eye_scale); - bf.eye_aspect.Assign(info.eye_aspect); - bf.eye_rotate.Assign(info.eye_rotate); - bf.eye_x.Assign(info.eye_x); - bf.eye_y.Assign(info.eye_y); - bf.eyebrow_type.Assign(info.eyebrow_type); - bf.eyebrow_color.Assign(HairColorLookup[info.eyebrow_color]); - bf.eyebrow_scale.Assign(info.eyebrow_scale); - bf.eyebrow_aspect.Assign(info.eyebrow_aspect); - bf.eyebrow_rotate.Assign(info.eyebrow_rotate); - bf.eyebrow_x.Assign(info.eyebrow_x); - bf.eyebrow_y.Assign(info.eyebrow_y - 3); - bf.nose_type.Assign(info.nose_type); - bf.nose_scale.Assign(info.nose_scale); - bf.nose_y.Assign(info.nose_y); - bf.mouth_type.Assign(info.mouth_type); - bf.mouth_color.Assign(MouthColorLookup[info.mouth_color]); - bf.mouth_scale.Assign(info.mouth_scale); - bf.mouth_aspect.Assign(info.mouth_aspect); - bf.mouth_y.Assign(info.mouth_y); - bf.beard_color.Assign(HairColorLookup[info.beard_color]); - bf.beard_type.Assign(static_cast(info.beard_type)); - bf.mustache_type.Assign(static_cast(info.mustache_type)); - bf.mustache_scale.Assign(info.mustache_scale); - bf.mustache_y.Assign(info.mustache_y); - bf.glasses_type.Assign(info.glasses_type); - bf.glasses_color.Assign(GlassesColorLookup[info.glasses_color]); - bf.glasses_scale.Assign(info.glasses_scale); - bf.glasses_y.Assign(info.glasses_y); - bf.mole_type.Assign(info.mole_type); - bf.mole_scale.Assign(info.mole_scale); - bf.mole_x.Assign(info.mole_x); - bf.mole_y.Assign(info.mole_y); - - return {DefaultMiiName, bf, user_id}; -} - -} // namespace - -MiiStoreData::MiiStoreData() = default; - -MiiStoreData::MiiStoreData(const MiiStoreData::Name& name, const MiiStoreBitFields& bit_fields, - const Common::UUID& user_id) { - data.name = name; - data.uuid = GenerateValidUUID(); - - std::memcpy(data.data.data(), &bit_fields, sizeof(MiiStoreBitFields)); - data_crc = GenerateCrc16(data.data.data(), sizeof(data)); - device_crc = GenerateCrc16(&user_id, sizeof(Common::UUID)); -} - -MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {} - -bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) { - if ((source_flag & SourceFlag::Database) == SourceFlag::None) { - return false; - } - - const bool result{current_update_counter != update_counter}; - - current_update_counter = update_counter; - - return result; -} - -bool MiiManager::IsFullDatabase() const { - // TODO(bunnei): We don't implement the Mii database, so it cannot be full - return false; -} - -u32 MiiManager::GetCount(SourceFlag source_flag) const { - std::size_t count{}; - if ((source_flag & SourceFlag::Database) != SourceFlag::None) { - // TODO(bunnei): We don't implement the Mii database, but when we do, update this - count += 0; - } - if ((source_flag & SourceFlag::Default) != SourceFlag::None) { - count += (DefaultMiiCount - BaseMiiCount); - } - return static_cast(count); -} - -ResultVal MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, - SourceFlag source_flag) { - if ((source_flag & SourceFlag::Database) == SourceFlag::None) { - return ERROR_CANNOT_FIND_ENTRY; - } - - // TODO(bunnei): We don't implement the Mii database, so we can't have an entry - return ERROR_CANNOT_FIND_ENTRY; -} - -MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { - return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); -} - -MiiInfo MiiManager::BuildDefault(std::size_t index) { - return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); -} - -ResultVal> MiiManager::GetDefault(SourceFlag source_flag) { - std::vector result; - - if ((source_flag & SourceFlag::Default) == SourceFlag::None) { - return MakeResult(std::move(result)); - } - - for (std::size_t index = BaseMiiCount; index < DefaultMiiCount; index++) { - result.emplace_back(BuildDefault(index), Source::Default); - } - - return MakeResult(std::move(result)); -} - -ResultCode MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { - constexpr u32 INVALID_INDEX{0xFFFFFFFF}; - - index = INVALID_INDEX; - - // TODO(bunnei): We don't implement the Mii database, so we can't have an index - return ERROR_CANNOT_FIND_ENTRY; -} - -} // namespace Service::Mii diff --git a/src/core/hle/service/mii/manager.h b/src/core/hle/service/mii/manager.h deleted file mode 100644 index 8e048fc56..000000000 --- a/src/core/hle/service/mii/manager.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2020 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/uuid.h" -#include "core/hle/result.h" -#include "core/hle/service/mii/types.h" - -namespace Service::Mii { - -enum class Source : u32 { - Database = 0, - Default = 1, - Account = 2, - Friend = 3, -}; - -enum class SourceFlag : u32 { - None = 0, - Database = 1 << 0, - Default = 1 << 1, -}; -DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); - -struct MiiInfo { - Common::UUID uuid; - std::array name; - u8 font_region; - u8 favorite_color; - u8 gender; - u8 height; - u8 build; - u8 type; - u8 region_move; - u8 faceline_type; - u8 faceline_color; - u8 faceline_wrinkle; - u8 faceline_make; - u8 hair_type; - u8 hair_color; - u8 hair_flip; - u8 eye_type; - u8 eye_color; - u8 eye_scale; - u8 eye_aspect; - u8 eye_rotate; - u8 eye_x; - u8 eye_y; - u8 eyebrow_type; - u8 eyebrow_color; - u8 eyebrow_scale; - u8 eyebrow_aspect; - u8 eyebrow_rotate; - u8 eyebrow_x; - u8 eyebrow_y; - u8 nose_type; - u8 nose_scale; - u8 nose_y; - u8 mouth_type; - u8 mouth_color; - u8 mouth_scale; - u8 mouth_aspect; - u8 mouth_y; - u8 beard_color; - u8 beard_type; - u8 mustache_type; - u8 mustache_scale; - u8 mustache_y; - u8 glasses_type; - u8 glasses_color; - u8 glasses_scale; - u8 glasses_y; - u8 mole_type; - u8 mole_scale; - u8 mole_x; - u8 mole_y; - u8 padding; - - std::u16string Name() const; -}; -static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); -static_assert(std::has_unique_object_representations_v, - "All bits of MiiInfo must contribute to its value."); - -#pragma pack(push, 4) - -struct MiiInfoElement { - MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {} - - MiiInfo info{}; - Source source{}; -}; -static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); - -struct MiiStoreBitFields { - union { - u32 word_0{}; - - BitField<0, 8, u32> hair_type; - BitField<8, 7, u32> height; - BitField<15, 1, u32> mole_type; - BitField<16, 7, u32> build; - BitField<23, 1, HairFlip> hair_flip; - BitField<24, 7, u32> hair_color; - BitField<31, 1, u32> type; - }; - - union { - u32 word_1{}; - - BitField<0, 7, u32> eye_color; - BitField<7, 1, Gender> gender; - BitField<8, 7, u32> eyebrow_color; - BitField<16, 7, u32> mouth_color; - BitField<24, 7, u32> beard_color; - }; - - union { - u32 word_2{}; - - BitField<0, 7, u32> glasses_color; - BitField<8, 6, u32> eye_type; - BitField<14, 2, u32> region_move; - BitField<16, 6, u32> mouth_type; - BitField<22, 2, FontRegion> font_region; - BitField<24, 5, u32> eye_y; - BitField<29, 3, u32> glasses_scale; - }; - - union { - u32 word_3{}; - - BitField<0, 5, u32> eyebrow_type; - BitField<5, 3, MustacheType> mustache_type; - BitField<8, 5, u32> nose_type; - BitField<13, 3, BeardType> beard_type; - BitField<16, 5, u32> nose_y; - BitField<21, 3, u32> mouth_aspect; - BitField<24, 5, u32> mouth_y; - BitField<29, 3, u32> eyebrow_aspect; - }; - - union { - u32 word_4{}; - - BitField<0, 5, u32> mustache_y; - BitField<5, 3, u32> eye_rotate; - BitField<8, 5, u32> glasses_y; - BitField<13, 3, u32> eye_aspect; - BitField<16, 5, u32> mole_x; - BitField<21, 3, u32> eye_scale; - BitField<24, 5, u32> mole_y; - }; - - union { - u32 word_5{}; - - BitField<0, 5, u32> glasses_type; - BitField<8, 4, u32> favorite_color; - BitField<12, 4, u32> faceline_type; - BitField<16, 4, u32> faceline_color; - BitField<20, 4, u32> faceline_wrinkle; - BitField<24, 4, u32> faceline_makeup; - BitField<28, 4, u32> eye_x; - }; - - union { - u32 word_6{}; - - BitField<0, 4, u32> eyebrow_scale; - BitField<4, 4, u32> eyebrow_rotate; - BitField<8, 4, u32> eyebrow_x; - BitField<12, 4, u32> eyebrow_y; - BitField<16, 4, u32> nose_scale; - BitField<20, 4, u32> mouth_scale; - BitField<24, 4, u32> mustache_scale; - BitField<28, 4, u32> mole_scale; - }; -}; -static_assert(sizeof(MiiStoreBitFields) == 0x1c, "MiiStoreBitFields has incorrect size."); -static_assert(std::is_trivially_copyable_v, - "MiiStoreBitFields is not trivially copyable."); - -struct MiiStoreData { - using Name = std::array; - - MiiStoreData(); - MiiStoreData(const Name& name, const MiiStoreBitFields& bit_fields, - const Common::UUID& user_id); - - // This corresponds to the above structure MiiStoreBitFields. I did it like this because the - // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is - // not suitable for our uses. - struct { - std::array data{}; - static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); - - Name name{}; - Common::UUID uuid{Common::INVALID_UUID}; - } data; - - u16 data_crc{}; - u16 device_crc{}; -}; -static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); - -struct MiiStoreDataElement { - MiiStoreData data{}; - Source source{}; -}; -static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); - -struct MiiDatabase { - u32 magic{}; // 'NFDB' - std::array miis{}; - INSERT_PADDING_BYTES(1); - u8 count{}; - u16 crc{}; -}; -static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); - -struct RandomMiiValues { - std::array values{}; -}; -static_assert(sizeof(RandomMiiValues) == 0xbc, "RandomMiiValues has incorrect size."); - -struct RandomMiiData4 { - Gender gender{}; - Age age{}; - Race race{}; - u32 values_count{}; - std::array values{}; -}; -static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); - -struct RandomMiiData3 { - u32 arg_1; - u32 arg_2; - u32 values_count; - std::array values{}; -}; -static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); - -struct RandomMiiData2 { - u32 arg_1; - u32 values_count; - std::array values{}; -}; -static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); - -struct DefaultMii { - u32 face_type{}; - u32 face_color{}; - u32 face_wrinkle{}; - u32 face_makeup{}; - u32 hair_type{}; - u32 hair_color{}; - u32 hair_flip{}; - u32 eye_type{}; - u32 eye_color{}; - u32 eye_scale{}; - u32 eye_aspect{}; - u32 eye_rotate{}; - u32 eye_x{}; - u32 eye_y{}; - u32 eyebrow_type{}; - u32 eyebrow_color{}; - u32 eyebrow_scale{}; - u32 eyebrow_aspect{}; - u32 eyebrow_rotate{}; - u32 eyebrow_x{}; - u32 eyebrow_y{}; - u32 nose_type{}; - u32 nose_scale{}; - u32 nose_y{}; - u32 mouth_type{}; - u32 mouth_color{}; - u32 mouth_scale{}; - u32 mouth_aspect{}; - u32 mouth_y{}; - u32 mustache_type{}; - u32 beard_type{}; - u32 beard_color{}; - u32 mustache_scale{}; - u32 mustache_y{}; - u32 glasses_type{}; - u32 glasses_color{}; - u32 glasses_scale{}; - u32 glasses_y{}; - u32 mole_type{}; - u32 mole_scale{}; - u32 mole_x{}; - u32 mole_y{}; - u32 height{}; - u32 weight{}; - Gender gender{}; - u32 favorite_color{}; - u32 region{}; - FontRegion font_region{}; - u32 type{}; - INSERT_PADDING_WORDS(5); -}; -static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size."); - -#pragma pack(pop) - -// The Mii manager is responsible for loading and storing the Miis to the database in NAND along -// with providing an easy interface for HLE emulation of the mii service. -class MiiManager { -public: - MiiManager(); - - bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); - bool IsFullDatabase() const; - u32 GetCount(SourceFlag source_flag) const; - ResultVal UpdateLatest(const MiiInfo& info, SourceFlag source_flag); - MiiInfo BuildRandom(Age age, Gender gender, Race race); - MiiInfo BuildDefault(std::size_t index); - ResultVal> GetDefault(SourceFlag source_flag); - ResultCode GetIndex(const MiiInfo& info, u32& index); - -private: - const Common::UUID user_id{Common::INVALID_UUID}; - u64 update_counter{}; -}; - -}; // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index bbd81a88a..9d863486a 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -7,8 +7,8 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" -#include "core/hle/service/mii/manager.h" #include "core/hle/service/mii/mii.h" +#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp new file mode 100644 index 000000000..4fef2aea4 --- /dev/null +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -0,0 +1,465 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" + +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/mii/raw_data.h" +#include "core/hle/service/mii/types.h" + +namespace Service::Mii { + +namespace { + +constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; + +constexpr std::size_t BaseMiiCount{2}; +constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; + +constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; +constexpr std::array HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; +constexpr std::array EyeColorLookup{8, 9, 10, 11, 12, 13}; +constexpr std::array MouthColorLookup{19, 20, 21, 22, 23}; +constexpr std::array GlassesColorLookup{8, 14, 15, 16, 17, 18, 0}; +constexpr std::array EyeRotateLookup{ + {0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, + 0x04, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04, + 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04}}; +constexpr std::array EyebrowRotateLookup{{0x06, 0x06, 0x05, 0x07, 0x06, 0x07, 0x06, 0x07, + 0x04, 0x07, 0x06, 0x08, 0x05, 0x05, 0x06, 0x06, + 0x07, 0x07, 0x06, 0x06, 0x05, 0x06, 0x07, 0x05}}; + +template +std::array ResizeArray(const std::array& in) { + std::array out{}; + std::memcpy(out.data(), in.data(), sizeof(T) * std::min(SourceArraySize, DestArraySize)); + return out; +} + +MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { + MiiStoreBitFields bf; + std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); + + return { + .uuid = data.data.uuid, + .name = ResizeArray(data.data.name), + .font_region = static_cast(bf.font_region.Value()), + .favorite_color = static_cast(bf.favorite_color.Value()), + .gender = static_cast(bf.gender.Value()), + .height = static_cast(bf.height.Value()), + .build = static_cast(bf.build.Value()), + .type = static_cast(bf.type.Value()), + .region_move = static_cast(bf.region_move.Value()), + .faceline_type = static_cast(bf.faceline_type.Value()), + .faceline_color = static_cast(bf.faceline_color.Value()), + .faceline_wrinkle = static_cast(bf.faceline_wrinkle.Value()), + .faceline_make = static_cast(bf.faceline_makeup.Value()), + .hair_type = static_cast(bf.hair_type.Value()), + .hair_color = static_cast(bf.hair_color.Value()), + .hair_flip = static_cast(bf.hair_flip.Value()), + .eye_type = static_cast(bf.eye_type.Value()), + .eye_color = static_cast(bf.eye_color.Value()), + .eye_scale = static_cast(bf.eye_scale.Value()), + .eye_aspect = static_cast(bf.eye_aspect.Value()), + .eye_rotate = static_cast(bf.eye_rotate.Value()), + .eye_x = static_cast(bf.eye_x.Value()), + .eye_y = static_cast(bf.eye_y.Value()), + .eyebrow_type = static_cast(bf.eyebrow_type.Value()), + .eyebrow_color = static_cast(bf.eyebrow_color.Value()), + .eyebrow_scale = static_cast(bf.eyebrow_scale.Value()), + .eyebrow_aspect = static_cast(bf.eyebrow_aspect.Value()), + .eyebrow_rotate = static_cast(bf.eyebrow_rotate.Value()), + .eyebrow_x = static_cast(bf.eyebrow_x.Value()), + .eyebrow_y = static_cast(bf.eyebrow_y.Value() + 3), + .nose_type = static_cast(bf.nose_type.Value()), + .nose_scale = static_cast(bf.nose_scale.Value()), + .nose_y = static_cast(bf.nose_y.Value()), + .mouth_type = static_cast(bf.mouth_type.Value()), + .mouth_color = static_cast(bf.mouth_color.Value()), + .mouth_scale = static_cast(bf.mouth_scale.Value()), + .mouth_aspect = static_cast(bf.mouth_aspect.Value()), + .mouth_y = static_cast(bf.mouth_y.Value()), + .beard_color = static_cast(bf.beard_color.Value()), + .beard_type = static_cast(bf.beard_type.Value()), + .mustache_type = static_cast(bf.mustache_type.Value()), + .mustache_scale = static_cast(bf.mustache_scale.Value()), + .mustache_y = static_cast(bf.mustache_y.Value()), + .glasses_type = static_cast(bf.glasses_type.Value()), + .glasses_color = static_cast(bf.glasses_color.Value()), + .glasses_scale = static_cast(bf.glasses_scale.Value()), + .glasses_y = static_cast(bf.glasses_y.Value()), + .mole_type = static_cast(bf.mole_type.Value()), + .mole_scale = static_cast(bf.mole_scale.Value()), + .mole_x = static_cast(bf.mole_x.Value()), + .mole_y = static_cast(bf.mole_y.Value()), + .padding = 0, + }; +} + +u16 GenerateCrc16(const void* data, std::size_t size) { + s32 crc{}; + for (std::size_t i = 0; i < size; i++) { + crc ^= static_cast(data)[i] << 8; + for (std::size_t j = 0; j < 8; j++) { + crc <<= 1; + if ((crc & 0x10000) != 0) { + crc = (crc ^ 0x1021) & 0xFFFF; + } + } + } + return Common::swap16(static_cast(crc)); +} + +Common::UUID GenerateValidUUID() { + auto uuid{Common::UUID::Generate()}; + + // Bit 7 must be set, and bit 6 unset for the UUID to be valid + uuid.uuid[1] &= 0xFFFFFFFFFFFFFF3FULL; + uuid.uuid[1] |= 0x0000000000000080ULL; + + return uuid; +} + +template +T GetRandomValue(T min, T max) { + std::random_device device; + std::mt19937 gen(device()); + std::uniform_int_distribution distribution(static_cast(min), static_cast(max)); + return static_cast(distribution(gen)); +} + +template +T GetRandomValue(T max) { + return GetRandomValue({}, max); +} + +MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { + MiiStoreBitFields bf{}; + + if (gender == Gender::All) { + gender = GetRandomValue(Gender::Maximum); + } + + bf.gender.Assign(gender); + bf.favorite_color.Assign(GetRandomValue(11)); + bf.region_move.Assign(0); + bf.font_region.Assign(FontRegion::Standard); + bf.type.Assign(0); + bf.height.Assign(64); + bf.build.Assign(64); + + if (age == Age::All) { + const auto temp{GetRandomValue(10)}; + if (temp >= 8) { + age = Age::Old; + } else if (temp >= 4) { + age = Age::Normal; + } else { + age = Age::Young; + } + } + + if (race == Race::All) { + const auto temp{GetRandomValue(10)}; + if (temp >= 8) { + race = Race::Black; + } else if (temp >= 4) { + race = Race::White; + } else { + race = Race::Asian; + } + } + + u32 axis_y{}; + if (gender == Gender::Female && age == Age::Young) { + axis_y = GetRandomValue(3); + } + + const std::size_t index{3 * static_cast(age) + + 9 * static_cast(gender) + static_cast(race)}; + + const auto faceline_type_info{RawData::RandomMiiFaceline.at(index)}; + const auto faceline_color_info{RawData::RandomMiiFacelineColor.at( + 3 * static_cast(gender) + static_cast(race))}; + const auto faceline_wrinkle_info{RawData::RandomMiiFacelineWrinkle.at(index)}; + const auto faceline_makeup_info{RawData::RandomMiiFacelineMakeup.at(index)}; + const auto hair_type_info{RawData::RandomMiiHairType.at(index)}; + const auto hair_color_info{RawData::RandomMiiHairColor.at(3 * static_cast(race) + + static_cast(age))}; + const auto eye_type_info{RawData::RandomMiiEyeType.at(index)}; + const auto eye_color_info{RawData::RandomMiiEyeColor.at(static_cast(race))}; + const auto eyebrow_type_info{RawData::RandomMiiEyebrowType.at(index)}; + const auto nose_type_info{RawData::RandomMiiNoseType.at(index)}; + const auto mouth_type_info{RawData::RandomMiiMouthType.at(index)}; + const auto glasses_type_info{RawData::RandomMiiGlassType.at(static_cast(age))}; + + bf.faceline_type.Assign( + faceline_type_info.values[GetRandomValue(faceline_type_info.values_count)]); + bf.faceline_color.Assign( + faceline_color_info.values[GetRandomValue(faceline_color_info.values_count)]); + bf.faceline_wrinkle.Assign( + faceline_wrinkle_info + .values[GetRandomValue(faceline_wrinkle_info.values_count)]); + bf.faceline_makeup.Assign( + faceline_makeup_info + .values[GetRandomValue(faceline_makeup_info.values_count)]); + + bf.hair_type.Assign( + hair_type_info.values[GetRandomValue(hair_type_info.values_count)]); + bf.hair_color.Assign( + HairColorLookup[hair_color_info + .values[GetRandomValue(hair_color_info.values_count)]]); + bf.hair_flip.Assign(GetRandomValue(HairFlip::Maximum)); + + bf.eye_type.Assign( + eye_type_info.values[GetRandomValue(eye_type_info.values_count)]); + + const auto eye_rotate_1{gender != Gender::Male ? 4 : 2}; + const auto eye_rotate_2{gender != Gender::Male ? 3 : 4}; + const auto eye_rotate_offset{32 - EyeRotateLookup[eye_rotate_1] + eye_rotate_2}; + const auto eye_rotate{32 - EyeRotateLookup[bf.eye_type]}; + + bf.eye_color.Assign( + EyeColorLookup[eye_color_info + .values[GetRandomValue(eye_color_info.values_count)]]); + bf.eye_scale.Assign(4); + bf.eye_aspect.Assign(3); + bf.eye_rotate.Assign(eye_rotate_offset - eye_rotate); + bf.eye_x.Assign(2); + bf.eye_y.Assign(axis_y + 12); + + bf.eyebrow_type.Assign( + eyebrow_type_info.values[GetRandomValue(eyebrow_type_info.values_count)]); + + const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0}; + const auto eyebrow_y{race == Race::Asian ? 9 : 10}; + const auto eyebrow_rotate_offset{32 - EyebrowRotateLookup[eyebrow_rotate_1] + 6}; + const auto eyebrow_rotate{ + 32 - EyebrowRotateLookup[static_cast(bf.eyebrow_type.Value())]}; + + bf.eyebrow_color.Assign(bf.hair_color); + bf.eyebrow_scale.Assign(4); + bf.eyebrow_aspect.Assign(3); + bf.eyebrow_rotate.Assign(eyebrow_rotate_offset - eyebrow_rotate); + bf.eyebrow_x.Assign(2); + bf.eyebrow_y.Assign(axis_y + eyebrow_y); + + const auto nose_scale{gender == Gender::Female ? 3 : 4}; + + bf.nose_type.Assign( + nose_type_info.values[GetRandomValue(nose_type_info.values_count)]); + bf.nose_scale.Assign(nose_scale); + bf.nose_y.Assign(axis_y + 9); + + const auto mouth_color{gender == Gender::Female ? GetRandomValue(4) : 0}; + + bf.mouth_type.Assign( + mouth_type_info.values[GetRandomValue(mouth_type_info.values_count)]); + bf.mouth_color.Assign(MouthColorLookup[mouth_color]); + bf.mouth_scale.Assign(4); + bf.mouth_aspect.Assign(3); + bf.mouth_y.Assign(axis_y + 13); + + bf.beard_color.Assign(bf.hair_color); + bf.mustache_scale.Assign(4); + + if (gender == Gender::Male && age != Age::Young && GetRandomValue(10) < 2) { + const auto mustache_and_beard_flag{ + GetRandomValue(BeardAndMustacheFlag::All)}; + + auto beard_type{BeardType::None}; + auto mustache_type{MustacheType::None}; + + if ((mustache_and_beard_flag & BeardAndMustacheFlag::Beard) == + BeardAndMustacheFlag::Beard) { + beard_type = GetRandomValue(BeardType::Beard1, BeardType::Beard5); + } + + if ((mustache_and_beard_flag & BeardAndMustacheFlag::Mustache) == + BeardAndMustacheFlag::Mustache) { + mustache_type = + GetRandomValue(MustacheType::Mustache1, MustacheType::Mustache5); + } + + bf.mustache_type.Assign(mustache_type); + bf.beard_type.Assign(beard_type); + bf.mustache_y.Assign(10); + } else { + bf.mustache_type.Assign(MustacheType::None); + bf.beard_type.Assign(BeardType::None); + bf.mustache_y.Assign(axis_y + 10); + } + + const auto glasses_type_start{GetRandomValue(100)}; + u8 glasses_type{}; + while (glasses_type_start < glasses_type_info.values[glasses_type]) { + if (++glasses_type >= glasses_type_info.values_count) { + UNREACHABLE(); + break; + } + } + + bf.glasses_type.Assign(glasses_type); + bf.glasses_color.Assign(GlassesColorLookup[0]); + bf.glasses_scale.Assign(4); + bf.glasses_y.Assign(axis_y + 10); + + bf.mole_type.Assign(0); + bf.mole_scale.Assign(4); + bf.mole_x.Assign(2); + bf.mole_y.Assign(20); + + return {DefaultMiiName, bf, user_id}; +} + +MiiStoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) { + MiiStoreBitFields bf{}; + + bf.font_region.Assign(info.font_region); + bf.favorite_color.Assign(info.favorite_color); + bf.gender.Assign(info.gender); + bf.height.Assign(info.height); + bf.build.Assign(info.weight); + bf.type.Assign(info.type); + bf.region_move.Assign(info.region); + bf.faceline_type.Assign(info.face_type); + bf.faceline_color.Assign(info.face_color); + bf.faceline_wrinkle.Assign(info.face_wrinkle); + bf.faceline_makeup.Assign(info.face_makeup); + bf.hair_type.Assign(info.hair_type); + bf.hair_color.Assign(HairColorLookup[info.hair_color]); + bf.hair_flip.Assign(static_cast(info.hair_flip)); + bf.eye_type.Assign(info.eye_type); + bf.eye_color.Assign(EyeColorLookup[info.eye_color]); + bf.eye_scale.Assign(info.eye_scale); + bf.eye_aspect.Assign(info.eye_aspect); + bf.eye_rotate.Assign(info.eye_rotate); + bf.eye_x.Assign(info.eye_x); + bf.eye_y.Assign(info.eye_y); + bf.eyebrow_type.Assign(info.eyebrow_type); + bf.eyebrow_color.Assign(HairColorLookup[info.eyebrow_color]); + bf.eyebrow_scale.Assign(info.eyebrow_scale); + bf.eyebrow_aspect.Assign(info.eyebrow_aspect); + bf.eyebrow_rotate.Assign(info.eyebrow_rotate); + bf.eyebrow_x.Assign(info.eyebrow_x); + bf.eyebrow_y.Assign(info.eyebrow_y - 3); + bf.nose_type.Assign(info.nose_type); + bf.nose_scale.Assign(info.nose_scale); + bf.nose_y.Assign(info.nose_y); + bf.mouth_type.Assign(info.mouth_type); + bf.mouth_color.Assign(MouthColorLookup[info.mouth_color]); + bf.mouth_scale.Assign(info.mouth_scale); + bf.mouth_aspect.Assign(info.mouth_aspect); + bf.mouth_y.Assign(info.mouth_y); + bf.beard_color.Assign(HairColorLookup[info.beard_color]); + bf.beard_type.Assign(static_cast(info.beard_type)); + bf.mustache_type.Assign(static_cast(info.mustache_type)); + bf.mustache_scale.Assign(info.mustache_scale); + bf.mustache_y.Assign(info.mustache_y); + bf.glasses_type.Assign(info.glasses_type); + bf.glasses_color.Assign(GlassesColorLookup[info.glasses_color]); + bf.glasses_scale.Assign(info.glasses_scale); + bf.glasses_y.Assign(info.glasses_y); + bf.mole_type.Assign(info.mole_type); + bf.mole_scale.Assign(info.mole_scale); + bf.mole_x.Assign(info.mole_x); + bf.mole_y.Assign(info.mole_y); + + return {DefaultMiiName, bf, user_id}; +} + +} // namespace + +MiiStoreData::MiiStoreData() = default; + +MiiStoreData::MiiStoreData(const MiiStoreData::Name& name, const MiiStoreBitFields& bit_fields, + const Common::UUID& user_id) { + data.name = name; + data.uuid = GenerateValidUUID(); + + std::memcpy(data.data.data(), &bit_fields, sizeof(MiiStoreBitFields)); + data_crc = GenerateCrc16(data.data.data(), sizeof(data)); + device_crc = GenerateCrc16(&user_id, sizeof(Common::UUID)); +} + +MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {} + +bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return false; + } + + const bool result{current_update_counter != update_counter}; + + current_update_counter = update_counter; + + return result; +} + +bool MiiManager::IsFullDatabase() const { + // TODO(bunnei): We don't implement the Mii database, so it cannot be full + return false; +} + +u32 MiiManager::GetCount(SourceFlag source_flag) const { + std::size_t count{}; + if ((source_flag & SourceFlag::Database) != SourceFlag::None) { + // TODO(bunnei): We don't implement the Mii database, but when we do, update this + count += 0; + } + if ((source_flag & SourceFlag::Default) != SourceFlag::None) { + count += (DefaultMiiCount - BaseMiiCount); + } + return static_cast(count); +} + +ResultVal MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, + SourceFlag source_flag) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return ERROR_CANNOT_FIND_ENTRY; + } + + // TODO(bunnei): We don't implement the Mii database, so we can't have an entry + return ERROR_CANNOT_FIND_ENTRY; +} + +MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { + return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); +} + +MiiInfo MiiManager::BuildDefault(std::size_t index) { + return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); +} + +ResultVal> MiiManager::GetDefault(SourceFlag source_flag) { + std::vector result; + + if ((source_flag & SourceFlag::Default) == SourceFlag::None) { + return MakeResult(std::move(result)); + } + + for (std::size_t index = BaseMiiCount; index < DefaultMiiCount; index++) { + result.emplace_back(BuildDefault(index), Source::Default); + } + + return MakeResult(std::move(result)); +} + +ResultCode MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { + constexpr u32 INVALID_INDEX{0xFFFFFFFF}; + + index = INVALID_INDEX; + + // TODO(bunnei): We don't implement the Mii database, so we can't have an index + return ERROR_CANNOT_FIND_ENTRY; +} + +} // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h new file mode 100644 index 000000000..8e048fc56 --- /dev/null +++ b/src/core/hle/service/mii/mii_manager.h @@ -0,0 +1,333 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/uuid.h" +#include "core/hle/result.h" +#include "core/hle/service/mii/types.h" + +namespace Service::Mii { + +enum class Source : u32 { + Database = 0, + Default = 1, + Account = 2, + Friend = 3, +}; + +enum class SourceFlag : u32 { + None = 0, + Database = 1 << 0, + Default = 1 << 1, +}; +DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); + +struct MiiInfo { + Common::UUID uuid; + std::array name; + u8 font_region; + u8 favorite_color; + u8 gender; + u8 height; + u8 build; + u8 type; + u8 region_move; + u8 faceline_type; + u8 faceline_color; + u8 faceline_wrinkle; + u8 faceline_make; + u8 hair_type; + u8 hair_color; + u8 hair_flip; + u8 eye_type; + u8 eye_color; + u8 eye_scale; + u8 eye_aspect; + u8 eye_rotate; + u8 eye_x; + u8 eye_y; + u8 eyebrow_type; + u8 eyebrow_color; + u8 eyebrow_scale; + u8 eyebrow_aspect; + u8 eyebrow_rotate; + u8 eyebrow_x; + u8 eyebrow_y; + u8 nose_type; + u8 nose_scale; + u8 nose_y; + u8 mouth_type; + u8 mouth_color; + u8 mouth_scale; + u8 mouth_aspect; + u8 mouth_y; + u8 beard_color; + u8 beard_type; + u8 mustache_type; + u8 mustache_scale; + u8 mustache_y; + u8 glasses_type; + u8 glasses_color; + u8 glasses_scale; + u8 glasses_y; + u8 mole_type; + u8 mole_scale; + u8 mole_x; + u8 mole_y; + u8 padding; + + std::u16string Name() const; +}; +static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); +static_assert(std::has_unique_object_representations_v, + "All bits of MiiInfo must contribute to its value."); + +#pragma pack(push, 4) + +struct MiiInfoElement { + MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {} + + MiiInfo info{}; + Source source{}; +}; +static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); + +struct MiiStoreBitFields { + union { + u32 word_0{}; + + BitField<0, 8, u32> hair_type; + BitField<8, 7, u32> height; + BitField<15, 1, u32> mole_type; + BitField<16, 7, u32> build; + BitField<23, 1, HairFlip> hair_flip; + BitField<24, 7, u32> hair_color; + BitField<31, 1, u32> type; + }; + + union { + u32 word_1{}; + + BitField<0, 7, u32> eye_color; + BitField<7, 1, Gender> gender; + BitField<8, 7, u32> eyebrow_color; + BitField<16, 7, u32> mouth_color; + BitField<24, 7, u32> beard_color; + }; + + union { + u32 word_2{}; + + BitField<0, 7, u32> glasses_color; + BitField<8, 6, u32> eye_type; + BitField<14, 2, u32> region_move; + BitField<16, 6, u32> mouth_type; + BitField<22, 2, FontRegion> font_region; + BitField<24, 5, u32> eye_y; + BitField<29, 3, u32> glasses_scale; + }; + + union { + u32 word_3{}; + + BitField<0, 5, u32> eyebrow_type; + BitField<5, 3, MustacheType> mustache_type; + BitField<8, 5, u32> nose_type; + BitField<13, 3, BeardType> beard_type; + BitField<16, 5, u32> nose_y; + BitField<21, 3, u32> mouth_aspect; + BitField<24, 5, u32> mouth_y; + BitField<29, 3, u32> eyebrow_aspect; + }; + + union { + u32 word_4{}; + + BitField<0, 5, u32> mustache_y; + BitField<5, 3, u32> eye_rotate; + BitField<8, 5, u32> glasses_y; + BitField<13, 3, u32> eye_aspect; + BitField<16, 5, u32> mole_x; + BitField<21, 3, u32> eye_scale; + BitField<24, 5, u32> mole_y; + }; + + union { + u32 word_5{}; + + BitField<0, 5, u32> glasses_type; + BitField<8, 4, u32> favorite_color; + BitField<12, 4, u32> faceline_type; + BitField<16, 4, u32> faceline_color; + BitField<20, 4, u32> faceline_wrinkle; + BitField<24, 4, u32> faceline_makeup; + BitField<28, 4, u32> eye_x; + }; + + union { + u32 word_6{}; + + BitField<0, 4, u32> eyebrow_scale; + BitField<4, 4, u32> eyebrow_rotate; + BitField<8, 4, u32> eyebrow_x; + BitField<12, 4, u32> eyebrow_y; + BitField<16, 4, u32> nose_scale; + BitField<20, 4, u32> mouth_scale; + BitField<24, 4, u32> mustache_scale; + BitField<28, 4, u32> mole_scale; + }; +}; +static_assert(sizeof(MiiStoreBitFields) == 0x1c, "MiiStoreBitFields has incorrect size."); +static_assert(std::is_trivially_copyable_v, + "MiiStoreBitFields is not trivially copyable."); + +struct MiiStoreData { + using Name = std::array; + + MiiStoreData(); + MiiStoreData(const Name& name, const MiiStoreBitFields& bit_fields, + const Common::UUID& user_id); + + // This corresponds to the above structure MiiStoreBitFields. I did it like this because the + // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is + // not suitable for our uses. + struct { + std::array data{}; + static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); + + Name name{}; + Common::UUID uuid{Common::INVALID_UUID}; + } data; + + u16 data_crc{}; + u16 device_crc{}; +}; +static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); + +struct MiiStoreDataElement { + MiiStoreData data{}; + Source source{}; +}; +static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); + +struct MiiDatabase { + u32 magic{}; // 'NFDB' + std::array miis{}; + INSERT_PADDING_BYTES(1); + u8 count{}; + u16 crc{}; +}; +static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); + +struct RandomMiiValues { + std::array values{}; +}; +static_assert(sizeof(RandomMiiValues) == 0xbc, "RandomMiiValues has incorrect size."); + +struct RandomMiiData4 { + Gender gender{}; + Age age{}; + Race race{}; + u32 values_count{}; + std::array values{}; +}; +static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); + +struct RandomMiiData3 { + u32 arg_1; + u32 arg_2; + u32 values_count; + std::array values{}; +}; +static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); + +struct RandomMiiData2 { + u32 arg_1; + u32 values_count; + std::array values{}; +}; +static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); + +struct DefaultMii { + u32 face_type{}; + u32 face_color{}; + u32 face_wrinkle{}; + u32 face_makeup{}; + u32 hair_type{}; + u32 hair_color{}; + u32 hair_flip{}; + u32 eye_type{}; + u32 eye_color{}; + u32 eye_scale{}; + u32 eye_aspect{}; + u32 eye_rotate{}; + u32 eye_x{}; + u32 eye_y{}; + u32 eyebrow_type{}; + u32 eyebrow_color{}; + u32 eyebrow_scale{}; + u32 eyebrow_aspect{}; + u32 eyebrow_rotate{}; + u32 eyebrow_x{}; + u32 eyebrow_y{}; + u32 nose_type{}; + u32 nose_scale{}; + u32 nose_y{}; + u32 mouth_type{}; + u32 mouth_color{}; + u32 mouth_scale{}; + u32 mouth_aspect{}; + u32 mouth_y{}; + u32 mustache_type{}; + u32 beard_type{}; + u32 beard_color{}; + u32 mustache_scale{}; + u32 mustache_y{}; + u32 glasses_type{}; + u32 glasses_color{}; + u32 glasses_scale{}; + u32 glasses_y{}; + u32 mole_type{}; + u32 mole_scale{}; + u32 mole_x{}; + u32 mole_y{}; + u32 height{}; + u32 weight{}; + Gender gender{}; + u32 favorite_color{}; + u32 region{}; + FontRegion font_region{}; + u32 type{}; + INSERT_PADDING_WORDS(5); +}; +static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size."); + +#pragma pack(pop) + +// The Mii manager is responsible for loading and storing the Miis to the database in NAND along +// with providing an easy interface for HLE emulation of the mii service. +class MiiManager { +public: + MiiManager(); + + bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); + bool IsFullDatabase() const; + u32 GetCount(SourceFlag source_flag) const; + ResultVal UpdateLatest(const MiiInfo& info, SourceFlag source_flag); + MiiInfo BuildRandom(Age age, Gender gender, Race race); + MiiInfo BuildDefault(std::size_t index); + ResultVal> GetDefault(SourceFlag source_flag); + ResultCode GetIndex(const MiiInfo& info, u32& index); + +private: + const Common::UUID user_id{Common::INVALID_UUID}; + u64 update_counter{}; +}; + +}; // namespace Service::Mii diff --git a/src/core/hle/service/mii/raw_data.h b/src/core/hle/service/mii/raw_data.h index 0e35d69d2..a0d2b9d3a 100644 --- a/src/core/hle/service/mii/raw_data.h +++ b/src/core/hle/service/mii/raw_data.h @@ -7,7 +7,7 @@ #include #include "common/common_types.h" -#include "core/hle/service/mii/manager.h" +#include "core/hle/service/mii/mii_manager.h" namespace Service::Mii::RawData { diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp deleted file mode 100644 index e4d495000..000000000 --- a/src/core/hle/service/nvdrv/interface.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/k_writable_event.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/service/nvdrv/interface.h" -#include "core/hle/service/nvdrv/nvdata.h" -#include "core/hle/service/nvdrv/nvdrv.h" - -namespace Service::Nvidia { - -void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { - nvdrv->SignalSyncpt(syncpoint_id, value); -} - -void NVDRV::Open(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NVDRV, "called"); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - - if (!is_initialized) { - rb.Push(0); - rb.PushEnum(NvResult::NotInitialized); - - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); - return; - } - - const auto& buffer = ctx.ReadBuffer(); - const std::string device_name(buffer.begin(), buffer.end()); - - if (device_name == "/dev/nvhost-prof-gpu") { - rb.Push(0); - rb.PushEnum(NvResult::NotSupported); - - LOG_WARNING(Service_NVDRV, "/dev/nvhost-prof-gpu cannot be opened in production"); - return; - } - - DeviceFD fd = nvdrv->Open(device_name); - - rb.Push(fd); - rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); -} - -void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) { - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(result); -} - -void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto fd = rp.Pop(); - const auto command = rp.PopRaw(); - LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); - - if (!is_initialized) { - ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); - return; - } - - // Check device - std::vector output_buffer(ctx.GetWriteBufferSize(0)); - const auto input_buffer = ctx.ReadBuffer(0); - - const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); - if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer); - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(nv_result); -} - -void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto fd = rp.Pop(); - const auto command = rp.PopRaw(); - LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); - - if (!is_initialized) { - ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); - return; - } - - const auto input_buffer = ctx.ReadBuffer(0); - const auto input_inlined_buffer = ctx.ReadBuffer(1); - std::vector output_buffer(ctx.GetWriteBufferSize(0)); - - const auto nv_result = - nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); - if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer); - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(nv_result); -} - -void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto fd = rp.Pop(); - const auto command = rp.PopRaw(); - LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); - - if (!is_initialized) { - ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); - return; - } - - const auto input_buffer = ctx.ReadBuffer(0); - std::vector output_buffer(ctx.GetWriteBufferSize(0)); - std::vector output_buffer_inline(ctx.GetWriteBufferSize(1)); - - const auto nv_result = - nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); - if (command.is_out != 0) { - ctx.WriteBuffer(output_buffer, 0); - ctx.WriteBuffer(output_buffer_inline, 1); - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(nv_result); -} - -void NVDRV::Close(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NVDRV, "called"); - - if (!is_initialized) { - ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); - return; - } - - IPC::RequestParser rp{ctx}; - const auto fd = rp.Pop(); - const auto result = nvdrv->Close(fd); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(result); -} - -void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); - - is_initialized = true; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(NvResult::Success); -} - -void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto fd = rp.Pop(); - const auto event_id = rp.Pop() & 0x00FF; - LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); - - if (!is_initialized) { - ServiceError(ctx, NvResult::NotInitialized); - LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); - return; - } - - const auto nv_result = nvdrv->VerifyFD(fd); - if (nv_result != NvResult::Success) { - LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); - ServiceError(ctx, nv_result); - return; - } - - if (event_id < MaxNvEvents) { - IPC::ResponseBuilder rb{ctx, 3, 1}; - rb.Push(ResultSuccess); - auto& event = nvdrv->GetEvent(event_id); - event.Clear(); - rb.PushCopyObjects(event); - rb.PushEnum(NvResult::Success); - } else { - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(NvResult::BadParameter); - } -} - -void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - pid = rp.Pop(); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(NvResult::Success); -} - -void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(NvResult::Success); -} - -void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { - // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on - // retail hardware. - LOG_DEBUG(Service_NVDRV, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -NVDRV::NVDRV(Core::System& system_, std::shared_ptr nvdrv_, const char* name) - : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} { - static const FunctionInfo functions[] = { - {0, &NVDRV::Open, "Open"}, - {1, &NVDRV::Ioctl1, "Ioctl"}, - {2, &NVDRV::Close, "Close"}, - {3, &NVDRV::Initialize, "Initialize"}, - {4, &NVDRV::QueryEvent, "QueryEvent"}, - {5, nullptr, "MapSharedMem"}, - {6, &NVDRV::GetStatus, "GetStatus"}, - {7, nullptr, "SetAruidForTest"}, - {8, &NVDRV::SetAruid, "SetAruid"}, - {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, - {10, nullptr, "InitializeDevtools"}, - {11, &NVDRV::Ioctl2, "Ioctl2"}, - {12, &NVDRV::Ioctl3, "Ioctl3"}, - {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled, - "SetGraphicsFirmwareMemoryMarginEnabled"}, - }; - RegisterHandlers(functions); -} - -NVDRV::~NVDRV() = default; - -} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h deleted file mode 100644 index 0e764c53f..000000000 --- a/src/core/hle/service/nvdrv/interface.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/service.h" - -namespace Kernel { -class KWritableEvent; -} - -namespace Service::Nvidia { - -class NVDRV final : public ServiceFramework { -public: - explicit NVDRV(Core::System& system_, std::shared_ptr nvdrv_, const char* name); - ~NVDRV() override; - - void SignalGPUInterruptSyncpt(u32 syncpoint_id, u32 value); - -private: - void Open(Kernel::HLERequestContext& ctx); - void Ioctl1(Kernel::HLERequestContext& ctx); - void Ioctl2(Kernel::HLERequestContext& ctx); - void Ioctl3(Kernel::HLERequestContext& ctx); - void Close(Kernel::HLERequestContext& ctx); - void Initialize(Kernel::HLERequestContext& ctx); - void QueryEvent(Kernel::HLERequestContext& ctx); - void SetAruid(Kernel::HLERequestContext& ctx); - void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); - void GetStatus(Kernel::HLERequestContext& ctx); - void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); - - void ServiceError(Kernel::HLERequestContext& ctx, NvResult result); - - std::shared_ptr nvdrv; - - u64 pid{}; - bool is_initialized{}; -}; - -} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 74796dce1..03992af5e 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -20,8 +20,8 @@ #include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" #include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "core/hle/service/nvdrv/devices/nvmap.h" -#include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvdrv/nvdrv_interface.h" #include "core/hle/service/nvdrv/nvmemp.h" #include "core/hle/service/nvdrv/syncpoint_manager.h" #include "core/hle/service/nvflinger/nvflinger.h" diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp new file mode 100644 index 000000000..d61fb73dc --- /dev/null +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -0,0 +1,259 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/nvdrv/nvdata.h" +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvdrv/nvdrv_interface.h" + +namespace Service::Nvidia { + +void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { + nvdrv->SignalSyncpt(syncpoint_id, value); +} + +void NVDRV::Open(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NVDRV, "called"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + + if (!is_initialized) { + rb.Push(0); + rb.PushEnum(NvResult::NotInitialized); + + LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + return; + } + + const auto& buffer = ctx.ReadBuffer(); + const std::string device_name(buffer.begin(), buffer.end()); + + if (device_name == "/dev/nvhost-prof-gpu") { + rb.Push(0); + rb.PushEnum(NvResult::NotSupported); + + LOG_WARNING(Service_NVDRV, "/dev/nvhost-prof-gpu cannot be opened in production"); + return; + } + + DeviceFD fd = nvdrv->Open(device_name); + + rb.Push(fd); + rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); +} + +void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(result); +} + +void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto fd = rp.Pop(); + const auto command = rp.PopRaw(); + LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + + if (!is_initialized) { + ServiceError(ctx, NvResult::NotInitialized); + LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + return; + } + + // Check device + std::vector output_buffer(ctx.GetWriteBufferSize(0)); + const auto input_buffer = ctx.ReadBuffer(0); + + const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); + if (command.is_out != 0) { + ctx.WriteBuffer(output_buffer); + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(nv_result); +} + +void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto fd = rp.Pop(); + const auto command = rp.PopRaw(); + LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + + if (!is_initialized) { + ServiceError(ctx, NvResult::NotInitialized); + LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + return; + } + + const auto input_buffer = ctx.ReadBuffer(0); + const auto input_inlined_buffer = ctx.ReadBuffer(1); + std::vector output_buffer(ctx.GetWriteBufferSize(0)); + + const auto nv_result = + nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); + if (command.is_out != 0) { + ctx.WriteBuffer(output_buffer); + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(nv_result); +} + +void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto fd = rp.Pop(); + const auto command = rp.PopRaw(); + LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + + if (!is_initialized) { + ServiceError(ctx, NvResult::NotInitialized); + LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + return; + } + + const auto input_buffer = ctx.ReadBuffer(0); + std::vector output_buffer(ctx.GetWriteBufferSize(0)); + std::vector output_buffer_inline(ctx.GetWriteBufferSize(1)); + + const auto nv_result = + nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); + if (command.is_out != 0) { + ctx.WriteBuffer(output_buffer, 0); + ctx.WriteBuffer(output_buffer_inline, 1); + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(nv_result); +} + +void NVDRV::Close(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NVDRV, "called"); + + if (!is_initialized) { + ServiceError(ctx, NvResult::NotInitialized); + LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + return; + } + + IPC::RequestParser rp{ctx}; + const auto fd = rp.Pop(); + const auto result = nvdrv->Close(fd); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(result); +} + +void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + + is_initialized = true; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(NvResult::Success); +} + +void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto fd = rp.Pop(); + const auto event_id = rp.Pop() & 0x00FF; + LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); + + if (!is_initialized) { + ServiceError(ctx, NvResult::NotInitialized); + LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); + return; + } + + const auto nv_result = nvdrv->VerifyFD(fd); + if (nv_result != NvResult::Success) { + LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); + ServiceError(ctx, nv_result); + return; + } + + if (event_id < MaxNvEvents) { + IPC::ResponseBuilder rb{ctx, 3, 1}; + rb.Push(ResultSuccess); + auto& event = nvdrv->GetEvent(event_id); + event.Clear(); + rb.PushCopyObjects(event); + rb.PushEnum(NvResult::Success); + } else { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(NvResult::BadParameter); + } +} + +void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + pid = rp.Pop(); + LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(NvResult::Success); +} + +void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(NvResult::Success); +} + +void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { + // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on + // retail hardware. + LOG_DEBUG(Service_NVDRV, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +NVDRV::NVDRV(Core::System& system_, std::shared_ptr nvdrv_, const char* name) + : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} { + static const FunctionInfo functions[] = { + {0, &NVDRV::Open, "Open"}, + {1, &NVDRV::Ioctl1, "Ioctl"}, + {2, &NVDRV::Close, "Close"}, + {3, &NVDRV::Initialize, "Initialize"}, + {4, &NVDRV::QueryEvent, "QueryEvent"}, + {5, nullptr, "MapSharedMem"}, + {6, &NVDRV::GetStatus, "GetStatus"}, + {7, nullptr, "SetAruidForTest"}, + {8, &NVDRV::SetAruid, "SetAruid"}, + {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, + {10, nullptr, "InitializeDevtools"}, + {11, &NVDRV::Ioctl2, "Ioctl2"}, + {12, &NVDRV::Ioctl3, "Ioctl3"}, + {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled, + "SetGraphicsFirmwareMemoryMarginEnabled"}, + }; + RegisterHandlers(functions); +} + +NVDRV::~NVDRV() = default; + +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h new file mode 100644 index 000000000..0e764c53f --- /dev/null +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h @@ -0,0 +1,45 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KWritableEvent; +} + +namespace Service::Nvidia { + +class NVDRV final : public ServiceFramework { +public: + explicit NVDRV(Core::System& system_, std::shared_ptr nvdrv_, const char* name); + ~NVDRV() override; + + void SignalGPUInterruptSyncpt(u32 syncpoint_id, u32 value); + +private: + void Open(Kernel::HLERequestContext& ctx); + void Ioctl1(Kernel::HLERequestContext& ctx); + void Ioctl2(Kernel::HLERequestContext& ctx); + void Ioctl3(Kernel::HLERequestContext& ctx); + void Close(Kernel::HLERequestContext& ctx); + void Initialize(Kernel::HLERequestContext& ctx); + void QueryEvent(Kernel::HLERequestContext& ctx); + void SetAruid(Kernel::HLERequestContext& ctx); + void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); + void GetStatus(Kernel::HLERequestContext& ctx); + void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); + + void ServiceError(Kernel::HLERequestContext& ctx, NvResult result); + + std::shared_ptr nvdrv; + + u64 pid{}; + bool is_initialized{}; +}; + +} // namespace Service::Nvidia diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp deleted file mode 100644 index 1e31d05a6..000000000 --- a/src/core/hle/service/pctl/module.cpp +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" -#include "core/core.h" -#include "core/file_sys/control_metadata.h" -#include "core/file_sys/patch_manager.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_process.h" -#include "core/hle/service/pctl/module.h" -#include "core/hle/service/pctl/pctl.h" - -namespace Service::PCTL { - -namespace Error { - -constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101}; -constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104}; -constexpr ResultCode ResultNoCapability{ErrorModule::PCTL, 131}; -constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181}; - -} // namespace Error - -class IParentalControlService final : public ServiceFramework { -public: - explicit IParentalControlService(Core::System& system_, Capability capability_) - : ServiceFramework{system_, "IParentalControlService"}, capability{capability_} { - // clang-format off - static const FunctionInfo functions[] = { - {1, &IParentalControlService::Initialize, "Initialize"}, - {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, - {1002, nullptr, "ConfirmLaunchApplicationPermission"}, - {1003, nullptr, "ConfirmResumeApplicationPermission"}, - {1004, nullptr, "ConfirmSnsPostPermission"}, - {1005, nullptr, "ConfirmSystemSettingsPermission"}, - {1006, nullptr, "IsRestrictionTemporaryUnlocked"}, - {1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, - {1008, nullptr, "EnterRestrictedSystemSettings"}, - {1009, nullptr, "LeaveRestrictedSystemSettings"}, - {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, - {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, - {1012, nullptr, "GetRestrictedFeatures"}, - {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"}, - {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, - {1015, nullptr, "ConfirmPlayableApplicationVideo"}, - {1016, nullptr, "ConfirmShowNewsPermission"}, - {1017, nullptr, "EndFreeCommunication"}, - {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"}, - {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"}, - {1032, nullptr, "GetSafetyLevel"}, - {1033, nullptr, "SetSafetyLevel"}, - {1034, nullptr, "GetSafetyLevelSettings"}, - {1035, nullptr, "GetCurrentSettings"}, - {1036, nullptr, "SetCustomSafetyLevelSettings"}, - {1037, nullptr, "GetDefaultRatingOrganization"}, - {1038, nullptr, "SetDefaultRatingOrganization"}, - {1039, nullptr, "GetFreeCommunicationApplicationListCount"}, - {1042, nullptr, "AddToFreeCommunicationApplicationList"}, - {1043, nullptr, "DeleteSettings"}, - {1044, nullptr, "GetFreeCommunicationApplicationList"}, - {1045, nullptr, "UpdateFreeCommunicationApplicationList"}, - {1046, nullptr, "DisableFeaturesForReset"}, - {1047, nullptr, "NotifyApplicationDownloadStarted"}, - {1048, nullptr, "NotifyNetworkProfileCreated"}, - {1049, nullptr, "ResetFreeCommunicationApplicationList"}, - {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"}, - {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"}, - {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"}, - {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"}, - {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"}, - {1201, nullptr, "UnlockRestrictionTemporarily"}, - {1202, nullptr, "UnlockSystemSettingsRestriction"}, - {1203, nullptr, "SetPinCode"}, - {1204, nullptr, "GenerateInquiryCode"}, - {1205, nullptr, "CheckMasterKey"}, - {1206, nullptr, "GetPinCodeLength"}, - {1207, nullptr, "GetPinCodeChangedEvent"}, - {1208, nullptr, "GetPinCode"}, - {1403, nullptr, "IsPairingActive"}, - {1406, nullptr, "GetSettingsLastUpdated"}, - {1411, nullptr, "GetPairingAccountInfo"}, - {1421, nullptr, "GetAccountNickname"}, - {1424, nullptr, "GetAccountState"}, - {1425, nullptr, "RequestPostEvents"}, - {1426, nullptr, "GetPostEventInterval"}, - {1427, nullptr, "SetPostEventInterval"}, - {1432, nullptr, "GetSynchronizationEvent"}, - {1451, nullptr, "StartPlayTimer"}, - {1452, nullptr, "StopPlayTimer"}, - {1453, nullptr, "IsPlayTimerEnabled"}, - {1454, nullptr, "GetPlayTimerRemainingTime"}, - {1455, nullptr, "IsRestrictedByPlayTimer"}, - {1456, nullptr, "GetPlayTimerSettings"}, - {1457, nullptr, "GetPlayTimerEventToRequestSuspension"}, - {1458, nullptr, "IsPlayTimerAlarmDisabled"}, - {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"}, - {1472, nullptr, "CancelNetworkRequest"}, - {1473, nullptr, "GetUnlinkedEvent"}, - {1474, nullptr, "ClearUnlinkedEvent"}, - {1601, nullptr, "DisableAllFeatures"}, - {1602, nullptr, "PostEnableAllFeatures"}, - {1603, nullptr, "IsAllFeaturesDisabled"}, - {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"}, - {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"}, - {1903, nullptr, "GetExemptApplicationListCountForDebug"}, - {1904, nullptr, "GetExemptApplicationListForDebug"}, - {1905, nullptr, "UpdateExemptApplicationListForDebug"}, - {1906, nullptr, "AddToExemptApplicationListForDebug"}, - {1907, nullptr, "DeleteFromExemptApplicationListForDebug"}, - {1908, nullptr, "ClearExemptApplicationListForDebug"}, - {1941, nullptr, "DeletePairing"}, - {1951, nullptr, "SetPlayTimerSettingsForDebug"}, - {1952, nullptr, "GetPlayTimerSpentTimeForTest"}, - {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"}, - {2001, nullptr, "RequestPairingAsync"}, - {2002, nullptr, "FinishRequestPairing"}, - {2003, nullptr, "AuthorizePairingAsync"}, - {2004, nullptr, "FinishAuthorizePairing"}, - {2005, nullptr, "RetrievePairingInfoAsync"}, - {2006, nullptr, "FinishRetrievePairingInfo"}, - {2007, nullptr, "UnlinkPairingAsync"}, - {2008, nullptr, "FinishUnlinkPairing"}, - {2009, nullptr, "GetAccountMiiImageAsync"}, - {2010, nullptr, "FinishGetAccountMiiImage"}, - {2011, nullptr, "GetAccountMiiImageContentTypeAsync"}, - {2012, nullptr, "FinishGetAccountMiiImageContentType"}, - {2013, nullptr, "SynchronizeParentalControlSettingsAsync"}, - {2014, nullptr, "FinishSynchronizeParentalControlSettings"}, - {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"}, - {2016, nullptr, "RequestUpdateExemptionListAsync"}, - }; - // clang-format on - RegisterHandlers(functions); - } - -private: - bool CheckFreeCommunicationPermissionImpl() const { - if (states.temporary_unlocked) { - return true; - } - if ((states.application_info.parental_control_flag & 1) == 0) { - return true; - } - if (pin_code[0] == '\0') { - return true; - } - if (!settings.is_free_communication_default_on) { - return true; - } - // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here - // but as we don't have multiproceses support yet, we can just assume our application is - // valid for the time being - return true; - } - - bool ConfirmStereoVisionPermissionImpl() const { - if (states.temporary_unlocked) { - return true; - } - if (pin_code[0] == '\0') { - return true; - } - if (!settings.is_stero_vision_restricted) { - return false; - } - return true; - } - - void SetStereoVisionRestrictionImpl(bool is_restricted) { - if (settings.disabled) { - return; - } - - if (pin_code[0] == '\0') { - return; - } - settings.is_stero_vision_restricted = is_restricted; - } - - void Initialize(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - - if (False(capability & (Capability::Application | Capability::System))) { - LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability); - return; - } - - // TODO(ogniK): Recovery flag initialization for pctl:r - - const auto tid = system.CurrentProcess()->GetTitleID(); - if (tid != 0) { - const FileSys::PatchManager pm{tid, system.GetFileSystemController(), - system.GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - if (control.first) { - states.tid_from_event = 0; - states.launch_time_valid = false; - states.is_suspended = false; - states.free_communication = false; - states.stereo_vision = false; - states.application_info = ApplicationInfo{ - .tid = tid, - .age_rating = control.first->GetRatingAge(), - .parental_control_flag = control.first->GetParentalControlFlag(), - .capability = capability, - }; - - if (False(capability & (Capability::System | Capability::Recovery))) { - // TODO(ogniK): Signal application launch event - } - } - } - - rb.Push(ResultSuccess); - } - - void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - if (!CheckFreeCommunicationPermissionImpl()) { - rb.Push(Error::ResultNoFreeCommunication); - } else { - rb.Push(ResultSuccess); - } - - states.free_communication = true; - } - - void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - states.stereo_vision = true; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_PCTL, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - if (!CheckFreeCommunicationPermissionImpl()) { - rb.Push(Error::ResultNoFreeCommunication); - } else { - rb.Push(ResultSuccess); - } - } - - void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - if (False(capability & (Capability::Status | Capability::Recovery))) { - LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!"); - rb.Push(Error::ResultNoCapability); - rb.Push(false); - return; - } - - rb.Push(pin_code[0] != '\0'); - } - - void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - - if (False(capability & Capability::StereoVision)) { - LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); - rb.Push(Error::ResultNoCapability); - return; - } - - if (pin_code[0] == '\0') { - rb.Push(Error::ResultNoRestrictionEnabled); - return; - } - - rb.Push(ResultSuccess); - } - - void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - if (!ConfirmStereoVisionPermissionImpl()) { - rb.Push(Error::ResultStereoVisionRestricted); - rb.Push(false); - } else { - rb.Push(ResultSuccess); - rb.Push(true); - } - } - - void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto can_use = rp.Pop(); - LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use); - - IPC::ResponseBuilder rb{ctx, 2}; - if (False(capability & Capability::StereoVision)) { - LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); - rb.Push(Error::ResultNoCapability); - return; - } - - SetStereoVisionRestrictionImpl(can_use); - rb.Push(ResultSuccess); - } - - void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - if (False(capability & Capability::StereoVision)) { - LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); - rb.Push(Error::ResultNoCapability); - rb.Push(false); - return; - } - - rb.Push(ResultSuccess); - rb.Push(settings.is_stero_vision_restricted); - } - - void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - states.stereo_vision = false; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - struct ApplicationInfo { - u64 tid{}; - std::array age_rating{}; - u32 parental_control_flag{}; - Capability capability{}; - }; - - struct States { - u64 current_tid{}; - ApplicationInfo application_info{}; - u64 tid_from_event{}; - bool launch_time_valid{}; - bool is_suspended{}; - bool temporary_unlocked{}; - bool free_communication{}; - bool stereo_vision{}; - }; - - struct ParentalControlSettings { - bool is_stero_vision_restricted{}; - bool is_free_communication_default_on{}; - bool disabled{}; - }; - - States states{}; - ParentalControlSettings settings{}; - std::array pin_code{}; - Capability capability{}; -}; - -void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - // TODO(ogniK): Get TID from process - - rb.PushIpcInterface(system, capability); -} - -void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_PCTL, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(system, capability); -} - -Module::Interface::Interface(Core::System& system_, std::shared_ptr module_, - const char* name_, Capability capability_) - : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {} - -Module::Interface::~Interface() = default; - -void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { - auto module = std::make_shared(); - std::make_shared(system, module, "pctl", - Capability::Application | Capability::SnsPost | Capability::Status | - Capability::StereoVision) - ->InstallAsService(service_manager); - // TODO(ogniK): Implement remaining capabilities - std::make_shared(system, module, "pctl:a", Capability::None) - ->InstallAsService(service_manager); - std::make_shared(system, module, "pctl:r", Capability::None) - ->InstallAsService(service_manager); - std::make_shared(system, module, "pctl:s", Capability::None) - ->InstallAsService(service_manager); -} - -} // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h deleted file mode 100644 index f25c5c557..000000000 --- a/src/core/hle/service/pctl/module.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_funcs.h" -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::PCTL { - -enum class Capability : u32 { - None = 0, - Application = 1 << 0, - SnsPost = 1 << 1, - Recovery = 1 << 6, - Status = 1 << 8, - StereoVision = 1 << 9, - System = 1 << 15, -}; -DECLARE_ENUM_FLAG_OPERATORS(Capability); - -class Module final { -public: - class Interface : public ServiceFramework { - public: - explicit Interface(Core::System& system_, std::shared_ptr module_, - const char* name_, Capability capability_); - ~Interface() override; - - void CreateService(Kernel::HLERequestContext& ctx); - void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx); - - protected: - std::shared_ptr module; - - private: - Capability capability{}; - }; -}; - -/// Registers all PCTL services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); - -} // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h index ea3b97823..1d28900b2 100644 --- a/src/core/hle/service/pctl/pctl.h +++ b/src/core/hle/service/pctl/pctl.h @@ -4,7 +4,7 @@ #pragma once -#include "core/hle/service/pctl/module.h" +#include "core/hle/service/pctl/pctl_module.h" namespace Core { class System; diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp new file mode 100644 index 000000000..6949fcf3b --- /dev/null +++ b/src/core/hle/service/pctl/pctl_module.cpp @@ -0,0 +1,406 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/service/pctl/pctl.h" +#include "core/hle/service/pctl/pctl_module.h" + +namespace Service::PCTL { + +namespace Error { + +constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101}; +constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104}; +constexpr ResultCode ResultNoCapability{ErrorModule::PCTL, 131}; +constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181}; + +} // namespace Error + +class IParentalControlService final : public ServiceFramework { +public: + explicit IParentalControlService(Core::System& system_, Capability capability_) + : ServiceFramework{system_, "IParentalControlService"}, capability{capability_} { + // clang-format off + static const FunctionInfo functions[] = { + {1, &IParentalControlService::Initialize, "Initialize"}, + {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"}, + {1002, nullptr, "ConfirmLaunchApplicationPermission"}, + {1003, nullptr, "ConfirmResumeApplicationPermission"}, + {1004, nullptr, "ConfirmSnsPostPermission"}, + {1005, nullptr, "ConfirmSystemSettingsPermission"}, + {1006, nullptr, "IsRestrictionTemporaryUnlocked"}, + {1007, nullptr, "RevertRestrictionTemporaryUnlocked"}, + {1008, nullptr, "EnterRestrictedSystemSettings"}, + {1009, nullptr, "LeaveRestrictedSystemSettings"}, + {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, + {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, + {1012, nullptr, "GetRestrictedFeatures"}, + {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"}, + {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, + {1015, nullptr, "ConfirmPlayableApplicationVideo"}, + {1016, nullptr, "ConfirmShowNewsPermission"}, + {1017, nullptr, "EndFreeCommunication"}, + {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"}, + {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"}, + {1032, nullptr, "GetSafetyLevel"}, + {1033, nullptr, "SetSafetyLevel"}, + {1034, nullptr, "GetSafetyLevelSettings"}, + {1035, nullptr, "GetCurrentSettings"}, + {1036, nullptr, "SetCustomSafetyLevelSettings"}, + {1037, nullptr, "GetDefaultRatingOrganization"}, + {1038, nullptr, "SetDefaultRatingOrganization"}, + {1039, nullptr, "GetFreeCommunicationApplicationListCount"}, + {1042, nullptr, "AddToFreeCommunicationApplicationList"}, + {1043, nullptr, "DeleteSettings"}, + {1044, nullptr, "GetFreeCommunicationApplicationList"}, + {1045, nullptr, "UpdateFreeCommunicationApplicationList"}, + {1046, nullptr, "DisableFeaturesForReset"}, + {1047, nullptr, "NotifyApplicationDownloadStarted"}, + {1048, nullptr, "NotifyNetworkProfileCreated"}, + {1049, nullptr, "ResetFreeCommunicationApplicationList"}, + {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"}, + {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"}, + {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"}, + {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"}, + {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"}, + {1201, nullptr, "UnlockRestrictionTemporarily"}, + {1202, nullptr, "UnlockSystemSettingsRestriction"}, + {1203, nullptr, "SetPinCode"}, + {1204, nullptr, "GenerateInquiryCode"}, + {1205, nullptr, "CheckMasterKey"}, + {1206, nullptr, "GetPinCodeLength"}, + {1207, nullptr, "GetPinCodeChangedEvent"}, + {1208, nullptr, "GetPinCode"}, + {1403, nullptr, "IsPairingActive"}, + {1406, nullptr, "GetSettingsLastUpdated"}, + {1411, nullptr, "GetPairingAccountInfo"}, + {1421, nullptr, "GetAccountNickname"}, + {1424, nullptr, "GetAccountState"}, + {1425, nullptr, "RequestPostEvents"}, + {1426, nullptr, "GetPostEventInterval"}, + {1427, nullptr, "SetPostEventInterval"}, + {1432, nullptr, "GetSynchronizationEvent"}, + {1451, nullptr, "StartPlayTimer"}, + {1452, nullptr, "StopPlayTimer"}, + {1453, nullptr, "IsPlayTimerEnabled"}, + {1454, nullptr, "GetPlayTimerRemainingTime"}, + {1455, nullptr, "IsRestrictedByPlayTimer"}, + {1456, nullptr, "GetPlayTimerSettings"}, + {1457, nullptr, "GetPlayTimerEventToRequestSuspension"}, + {1458, nullptr, "IsPlayTimerAlarmDisabled"}, + {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"}, + {1472, nullptr, "CancelNetworkRequest"}, + {1473, nullptr, "GetUnlinkedEvent"}, + {1474, nullptr, "ClearUnlinkedEvent"}, + {1601, nullptr, "DisableAllFeatures"}, + {1602, nullptr, "PostEnableAllFeatures"}, + {1603, nullptr, "IsAllFeaturesDisabled"}, + {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"}, + {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"}, + {1903, nullptr, "GetExemptApplicationListCountForDebug"}, + {1904, nullptr, "GetExemptApplicationListForDebug"}, + {1905, nullptr, "UpdateExemptApplicationListForDebug"}, + {1906, nullptr, "AddToExemptApplicationListForDebug"}, + {1907, nullptr, "DeleteFromExemptApplicationListForDebug"}, + {1908, nullptr, "ClearExemptApplicationListForDebug"}, + {1941, nullptr, "DeletePairing"}, + {1951, nullptr, "SetPlayTimerSettingsForDebug"}, + {1952, nullptr, "GetPlayTimerSpentTimeForTest"}, + {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"}, + {2001, nullptr, "RequestPairingAsync"}, + {2002, nullptr, "FinishRequestPairing"}, + {2003, nullptr, "AuthorizePairingAsync"}, + {2004, nullptr, "FinishAuthorizePairing"}, + {2005, nullptr, "RetrievePairingInfoAsync"}, + {2006, nullptr, "FinishRetrievePairingInfo"}, + {2007, nullptr, "UnlinkPairingAsync"}, + {2008, nullptr, "FinishUnlinkPairing"}, + {2009, nullptr, "GetAccountMiiImageAsync"}, + {2010, nullptr, "FinishGetAccountMiiImage"}, + {2011, nullptr, "GetAccountMiiImageContentTypeAsync"}, + {2012, nullptr, "FinishGetAccountMiiImageContentType"}, + {2013, nullptr, "SynchronizeParentalControlSettingsAsync"}, + {2014, nullptr, "FinishSynchronizeParentalControlSettings"}, + {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"}, + {2016, nullptr, "RequestUpdateExemptionListAsync"}, + }; + // clang-format on + RegisterHandlers(functions); + } + +private: + bool CheckFreeCommunicationPermissionImpl() const { + if (states.temporary_unlocked) { + return true; + } + if ((states.application_info.parental_control_flag & 1) == 0) { + return true; + } + if (pin_code[0] == '\0') { + return true; + } + if (!settings.is_free_communication_default_on) { + return true; + } + // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here + // but as we don't have multiproceses support yet, we can just assume our application is + // valid for the time being + return true; + } + + bool ConfirmStereoVisionPermissionImpl() const { + if (states.temporary_unlocked) { + return true; + } + if (pin_code[0] == '\0') { + return true; + } + if (!settings.is_stero_vision_restricted) { + return false; + } + return true; + } + + void SetStereoVisionRestrictionImpl(bool is_restricted) { + if (settings.disabled) { + return; + } + + if (pin_code[0] == '\0') { + return; + } + settings.is_stero_vision_restricted = is_restricted; + } + + void Initialize(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + IPC::ResponseBuilder rb{ctx, 2}; + + if (False(capability & (Capability::Application | Capability::System))) { + LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability); + return; + } + + // TODO(ogniK): Recovery flag initialization for pctl:r + + const auto tid = system.CurrentProcess()->GetTitleID(); + if (tid != 0) { + const FileSys::PatchManager pm{tid, system.GetFileSystemController(), + system.GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + if (control.first) { + states.tid_from_event = 0; + states.launch_time_valid = false; + states.is_suspended = false; + states.free_communication = false; + states.stereo_vision = false; + states.application_info = ApplicationInfo{ + .tid = tid, + .age_rating = control.first->GetRatingAge(), + .parental_control_flag = control.first->GetParentalControlFlag(), + .capability = capability, + }; + + if (False(capability & (Capability::System | Capability::Recovery))) { + // TODO(ogniK): Signal application launch event + } + } + } + + rb.Push(ResultSuccess); + } + + void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + if (!CheckFreeCommunicationPermissionImpl()) { + rb.Push(Error::ResultNoFreeCommunication); + } else { + rb.Push(ResultSuccess); + } + + states.free_communication = true; + } + + void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + states.stereo_vision = true; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_PCTL, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + if (!CheckFreeCommunicationPermissionImpl()) { + rb.Push(Error::ResultNoFreeCommunication); + } else { + rb.Push(ResultSuccess); + } + } + + void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + if (False(capability & (Capability::Status | Capability::Recovery))) { + LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!"); + rb.Push(Error::ResultNoCapability); + rb.Push(false); + return; + } + + rb.Push(pin_code[0] != '\0'); + } + + void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + + if (False(capability & Capability::StereoVision)) { + LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); + rb.Push(Error::ResultNoCapability); + return; + } + + if (pin_code[0] == '\0') { + rb.Push(Error::ResultNoRestrictionEnabled); + return; + } + + rb.Push(ResultSuccess); + } + + void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + if (!ConfirmStereoVisionPermissionImpl()) { + rb.Push(Error::ResultStereoVisionRestricted); + rb.Push(false); + } else { + rb.Push(ResultSuccess); + rb.Push(true); + } + } + + void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto can_use = rp.Pop(); + LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use); + + IPC::ResponseBuilder rb{ctx, 2}; + if (False(capability & Capability::StereoVision)) { + LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); + rb.Push(Error::ResultNoCapability); + return; + } + + SetStereoVisionRestrictionImpl(can_use); + rb.Push(ResultSuccess); + } + + void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + if (False(capability & Capability::StereoVision)) { + LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!"); + rb.Push(Error::ResultNoCapability); + rb.Push(false); + return; + } + + rb.Push(ResultSuccess); + rb.Push(settings.is_stero_vision_restricted); + } + + void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + states.stereo_vision = false; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + struct ApplicationInfo { + u64 tid{}; + std::array age_rating{}; + u32 parental_control_flag{}; + Capability capability{}; + }; + + struct States { + u64 current_tid{}; + ApplicationInfo application_info{}; + u64 tid_from_event{}; + bool launch_time_valid{}; + bool is_suspended{}; + bool temporary_unlocked{}; + bool free_communication{}; + bool stereo_vision{}; + }; + + struct ParentalControlSettings { + bool is_stero_vision_restricted{}; + bool is_free_communication_default_on{}; + bool disabled{}; + }; + + States states{}; + ParentalControlSettings settings{}; + std::array pin_code{}; + Capability capability{}; +}; + +void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + // TODO(ogniK): Get TID from process + + rb.PushIpcInterface(system, capability); +} + +void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCTL, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system, capability); +} + +Module::Interface::Interface(Core::System& system_, std::shared_ptr module_, + const char* name_, Capability capability_) + : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {} + +Module::Interface::~Interface() = default; + +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + auto module = std::make_shared(); + std::make_shared(system, module, "pctl", + Capability::Application | Capability::SnsPost | Capability::Status | + Capability::StereoVision) + ->InstallAsService(service_manager); + // TODO(ogniK): Implement remaining capabilities + std::make_shared(system, module, "pctl:a", Capability::None) + ->InstallAsService(service_manager); + std::make_shared(system, module, "pctl:r", Capability::None) + ->InstallAsService(service_manager); + std::make_shared(system, module, "pctl:s", Capability::None) + ->InstallAsService(service_manager); +} + +} // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/pctl_module.h b/src/core/hle/service/pctl/pctl_module.h new file mode 100644 index 000000000..f25c5c557 --- /dev/null +++ b/src/core/hle/service/pctl/pctl_module.h @@ -0,0 +1,49 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_funcs.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::PCTL { + +enum class Capability : u32 { + None = 0, + Application = 1 << 0, + SnsPost = 1 << 1, + Recovery = 1 << 6, + Status = 1 << 8, + StereoVision = 1 << 9, + System = 1 << 15, +}; +DECLARE_ENUM_FLAG_OPERATORS(Capability); + +class Module final { +public: + class Interface : public ServiceFramework { + public: + explicit Interface(Core::System& system_, std::shared_ptr module_, + const char* name_, Capability capability_); + ~Interface() override; + + void CreateService(Kernel::HLERequestContext& ctx); + void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr module; + + private: + Capability capability{}; + }; +}; + +/// Registers all PCTL services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); + +} // namespace Service::PCTL diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 663b83cd3..e6fba88b2 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -21,7 +21,7 @@ #include "core/hle/service/aoc/aoc_u.h" #include "core/hle/service/apm/apm.h" #include "core/hle/service/audio/audio.h" -#include "core/hle/service/bcat/module.h" +#include "core/hle/service/bcat/bcat_module.h" #include "core/hle/service/bpc/bpc.h" #include "core/hle/service/btdrv/btdrv.h" #include "core/hle/service/btm/btm.h" @@ -54,7 +54,7 @@ #include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/olsc/olsc.h" #include "core/hle/service/pcie/pcie.h" -#include "core/hle/service/pctl/module.h" +#include "core/hle/service/pctl/pctl_module.h" #include "core/hle/service/pcv/pcv.h" #include "core/hle/service/pm/pm.h" #include "core/hle/service/prepo/prepo.h" @@ -64,7 +64,7 @@ #include "core/hle/service/set/settings.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/sockets/sockets.h" -#include "core/hle/service/spl/module.h" +#include "core/hle/service/spl/spl_module.h" #include "core/hle/service/ssl/ssl.h" #include "core/hle/service/time/time.h" #include "core/hle/service/usb/usb.h" diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp deleted file mode 100644 index 8b9418e0f..000000000 --- a/src/core/hle/service/sm/controller.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018 yuzu emulator team -// 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/core.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_client_port.h" -#include "core/hle/kernel/k_client_session.h" -#include "core/hle/kernel/k_port.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/k_server_port.h" -#include "core/hle/kernel/k_server_session.h" -#include "core/hle/kernel/k_session.h" -#include "core/hle/service/sm/controller.h" - -namespace Service::SM { - -void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { - ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); - LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); - ctx.Session()->ConvertToDomain(); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(1); // Converted sessions start with 1 request handler -} - -void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service, "called"); - - auto& parent_session = *ctx.Session()->GetParent(); - auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort(); - auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); - - // Create a session. - Kernel::KClientSession* session{}; - const ResultCode result = parent_port.CreateSession(std::addressof(session), session_manager); - if (result.IsError()) { - LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } - - // We succeeded. - IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; - rb.Push(ResultSuccess); - rb.PushMoveObjects(session); -} - -void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service, "called"); - - CloneCurrentObject(ctx); -} - -void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0x8000); -} - -// https://switchbrew.org/wiki/IPC_Marshalling -Controller::Controller(Core::System& system_) : ServiceFramework{system_, "IpcController"} { - static const FunctionInfo functions[] = { - {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"}, - {1, nullptr, "CopyFromCurrentDomain"}, - {2, &Controller::CloneCurrentObject, "CloneCurrentObject"}, - {3, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"}, - {4, &Controller::CloneCurrentObjectEx, "CloneCurrentObjectEx"}, - }; - RegisterHandlers(functions); -} - -Controller::~Controller() = default; - -} // namespace Service::SM diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h deleted file mode 100644 index 7494f898d..000000000 --- a/src/core/hle/service/sm/controller.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::SM { - -class Controller final : public ServiceFramework { -public: - explicit Controller(Core::System& system_); - ~Controller() override; - -private: - void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx); - void CloneCurrentObject(Kernel::HLERequestContext& ctx); - void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx); - void QueryPointerBufferSize(Kernel::HLERequestContext& ctx); -}; - -} // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index c7828c3bd..15034abed 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -14,8 +14,8 @@ #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" #include "core/hle/result.h" -#include "core/hle/service/sm/controller.h" #include "core/hle/service/sm/sm.h" +#include "core/hle/service/sm/sm_controller.h" namespace Service::SM { diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp new file mode 100644 index 000000000..b5fbc4569 --- /dev/null +++ b/src/core/hle/service/sm/sm_controller.cpp @@ -0,0 +1,80 @@ +// Copyright 2018 yuzu emulator team +// 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/core.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/service/sm/sm_controller.h" + +namespace Service::SM { + +void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { + ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); + LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); + ctx.Session()->ConvertToDomain(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(1); // Converted sessions start with 1 request handler +} + +void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service, "called"); + + auto& parent_session = *ctx.Session()->GetParent(); + auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort(); + auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); + + // Create a session. + Kernel::KClientSession* session{}; + const ResultCode result = parent_port.CreateSession(std::addressof(session), session_manager); + if (result.IsError()) { + LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + } + + // We succeeded. + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(ResultSuccess); + rb.PushMoveObjects(session); +} + +void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service, "called"); + + CloneCurrentObject(ctx); +} + +void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0x8000); +} + +// https://switchbrew.org/wiki/IPC_Marshalling +Controller::Controller(Core::System& system_) : ServiceFramework{system_, "IpcController"} { + static const FunctionInfo functions[] = { + {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"}, + {1, nullptr, "CopyFromCurrentDomain"}, + {2, &Controller::CloneCurrentObject, "CloneCurrentObject"}, + {3, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"}, + {4, &Controller::CloneCurrentObjectEx, "CloneCurrentObjectEx"}, + }; + RegisterHandlers(functions); +} + +Controller::~Controller() = default; + +} // namespace Service::SM diff --git a/src/core/hle/service/sm/sm_controller.h b/src/core/hle/service/sm/sm_controller.h new file mode 100644 index 000000000..7494f898d --- /dev/null +++ b/src/core/hle/service/sm/sm_controller.h @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::SM { + +class Controller final : public ServiceFramework { +public: + explicit Controller(Core::System& system_); + ~Controller() override; + +private: + void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx); + void CloneCurrentObject(Kernel::HLERequestContext& ctx); + void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx); + void QueryPointerBufferSize(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::SM diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h index 5c0bd2199..0d03cc6cb 100644 --- a/src/core/hle/service/spl/csrng.h +++ b/src/core/hle/service/spl/csrng.h @@ -4,7 +4,7 @@ #pragma once -#include "core/hle/service/spl/module.h" +#include "core/hle/service/spl/spl_module.h" namespace Core { class System; diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp deleted file mode 100644 index ebb179aa8..000000000 --- a/src/core/hle/service/spl/module.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include "common/logging/log.h" -#include "common/settings.h" -#include "core/hle/api_version.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/spl/csrng.h" -#include "core/hle/service/spl/module.h" -#include "core/hle/service/spl/spl.h" - -namespace Service::SPL { - -Module::Interface::Interface(Core::System& system_, std::shared_ptr module_, - const char* name) - : ServiceFramework{system_, name}, module{std::move(module_)}, - rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {} - -Module::Interface::~Interface() = default; - -void Module::Interface::GetConfig(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto config_item = rp.PopEnum(); - - // This should call svcCallSecureMonitor with the appropriate args. - // Since we do not have it implemented yet, we will use this for now. - const auto smc_result = GetConfigImpl(config_item); - const auto result_code = smc_result.Code(); - - if (smc_result.Failed()) { - LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item, - result_code.raw); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result_code); - } - - LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item, - result_code.raw, *smc_result); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(result_code); - rb.Push(*smc_result); -} - -void Module::Interface::ModularExponentiate(Kernel::HLERequestContext& ctx) { - UNIMPLEMENTED_MSG("ModularExponentiate is not implemented!"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSecureMonitorNotImplemented); -} - -void Module::Interface::SetConfig(Kernel::HLERequestContext& ctx) { - UNIMPLEMENTED_MSG("SetConfig is not implemented!"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSecureMonitorNotImplemented); -} - -void Module::Interface::GenerateRandomBytes(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_SPL, "called"); - - const std::size_t size = ctx.GetWriteBufferSize(); - - std::uniform_int_distribution distribution(0, std::numeric_limits::max()); - std::vector data(size); - std::generate(data.begin(), data.end(), [&] { return static_cast(distribution(rng)); }); - - ctx.WriteBuffer(data); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void Module::Interface::IsDevelopment(Kernel::HLERequestContext& ctx) { - UNIMPLEMENTED_MSG("IsDevelopment is not implemented!"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSecureMonitorNotImplemented); -} - -void Module::Interface::SetBootReason(Kernel::HLERequestContext& ctx) { - UNIMPLEMENTED_MSG("SetBootReason is not implemented!"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSecureMonitorNotImplemented); -} - -void Module::Interface::GetBootReason(Kernel::HLERequestContext& ctx) { - UNIMPLEMENTED_MSG("GetBootReason is not implemented!"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSecureMonitorNotImplemented); -} - -ResultVal Module::Interface::GetConfigImpl(ConfigItem config_item) const { - switch (config_item) { - case ConfigItem::DisableProgramVerification: - case ConfigItem::DramId: - case ConfigItem::SecurityEngineInterruptNumber: - case ConfigItem::FuseVersion: - case ConfigItem::HardwareType: - case ConfigItem::HardwareState: - case ConfigItem::IsRecoveryBoot: - case ConfigItem::DeviceId: - case ConfigItem::BootReason: - case ConfigItem::MemoryMode: - case ConfigItem::IsDevelopmentFunctionEnabled: - case ConfigItem::KernelConfiguration: - case ConfigItem::IsChargerHiZModeEnabled: - case ConfigItem::QuestState: - case ConfigItem::RegulatorType: - case ConfigItem::DeviceUniqueKeyGeneration: - case ConfigItem::Package2Hash: - return ResultSecureMonitorNotImplemented; - case ConfigItem::ExosphereApiVersion: - // Get information about the current exosphere version. - return MakeResult((u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) | - (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) | - (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) | - (static_cast(HLE::ApiVersion::GetTargetFirmware()))); - case ConfigItem::ExosphereNeedsReboot: - // We are executing, so we aren't in the process of rebooting. - return MakeResult(u64{0}); - case ConfigItem::ExosphereNeedsShutdown: - // We are executing, so we aren't in the process of shutting down. - return MakeResult(u64{0}); - case ConfigItem::ExosphereGitCommitHash: - // Get information about the current exosphere git commit hash. - return MakeResult(u64{0}); - case ConfigItem::ExosphereHasRcmBugPatch: - // Get information about whether this unit has the RCM bug patched. - return MakeResult(u64{0}); - case ConfigItem::ExosphereBlankProdInfo: - // Get whether this unit should simulate a "blanked" PRODINFO. - return MakeResult(u64{0}); - case ConfigItem::ExosphereAllowCalWrites: - // Get whether this unit should allow writing to the calibration partition. - return MakeResult(u64{0}); - case ConfigItem::ExosphereEmummcType: - // Get what kind of emummc this unit has active. - return MakeResult(u64{0}); - case ConfigItem::ExospherePayloadAddress: - // Gets the physical address of the reboot payload buffer, if one exists. - return ResultSecureMonitorNotInitialized; - case ConfigItem::ExosphereLogConfiguration: - // Get the log configuration. - return MakeResult(u64{0}); - case ConfigItem::ExosphereForceEnableUsb30: - // Get whether usb 3.0 should be force-enabled. - return MakeResult(u64{0}); - default: - return ResultSecureMonitorInvalidArgument; - } -} - -void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { - auto module = std::make_shared(); - std::make_shared(system, module)->InstallAsService(service_manager); - std::make_shared(system, module)->InstallAsService(service_manager); - std::make_shared(system, module)->InstallAsService(service_manager); - std::make_shared(system, module)->InstallAsService(service_manager); - std::make_shared(system, module)->InstallAsService(service_manager); - std::make_shared(system, module)->InstallAsService(service_manager); - std::make_shared(system, module)->InstallAsService(service_manager); -} - -} // namespace Service::SPL diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h deleted file mode 100644 index 61630df80..000000000 --- a/src/core/hle/service/spl/module.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/hle/service/service.h" -#include "core/hle/service/spl/spl_results.h" -#include "core/hle/service/spl/spl_types.h" - -namespace Core { -class System; -} - -namespace Service::SPL { - -class Module final { -public: - class Interface : public ServiceFramework { - public: - explicit Interface(Core::System& system_, std::shared_ptr module_, - const char* name); - ~Interface() override; - - // General - void GetConfig(Kernel::HLERequestContext& ctx); - void ModularExponentiate(Kernel::HLERequestContext& ctx); - void SetConfig(Kernel::HLERequestContext& ctx); - void GenerateRandomBytes(Kernel::HLERequestContext& ctx); - void IsDevelopment(Kernel::HLERequestContext& ctx); - void SetBootReason(Kernel::HLERequestContext& ctx); - void GetBootReason(Kernel::HLERequestContext& ctx); - - protected: - std::shared_ptr module; - - private: - ResultVal GetConfigImpl(ConfigItem config_item) const; - - std::mt19937 rng; - }; -}; - -/// Registers all SPL services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); - -} // namespace Service::SPL diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h index 9b35012ed..5599c0c01 100644 --- a/src/core/hle/service/spl/spl.h +++ b/src/core/hle/service/spl/spl.h @@ -4,7 +4,7 @@ #pragma once -#include "core/hle/service/spl/module.h" +#include "core/hle/service/spl/spl_module.h" namespace Core { class System; diff --git a/src/core/hle/service/spl/spl_module.cpp b/src/core/hle/service/spl/spl_module.cpp new file mode 100644 index 000000000..918633af5 --- /dev/null +++ b/src/core/hle/service/spl/spl_module.cpp @@ -0,0 +1,175 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include "common/logging/log.h" +#include "common/settings.h" +#include "core/hle/api_version.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/spl/csrng.h" +#include "core/hle/service/spl/spl.h" +#include "core/hle/service/spl/spl_module.h" + +namespace Service::SPL { + +Module::Interface::Interface(Core::System& system_, std::shared_ptr module_, + const char* name) + : ServiceFramework{system_, name}, module{std::move(module_)}, + rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {} + +Module::Interface::~Interface() = default; + +void Module::Interface::GetConfig(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto config_item = rp.PopEnum(); + + // This should call svcCallSecureMonitor with the appropriate args. + // Since we do not have it implemented yet, we will use this for now. + const auto smc_result = GetConfigImpl(config_item); + const auto result_code = smc_result.Code(); + + if (smc_result.Failed()) { + LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item, + result_code.raw); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result_code); + } + + LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item, + result_code.raw, *smc_result); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(result_code); + rb.Push(*smc_result); +} + +void Module::Interface::ModularExponentiate(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("ModularExponentiate is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::SetConfig(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("SetConfig is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::GenerateRandomBytes(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_SPL, "called"); + + const std::size_t size = ctx.GetWriteBufferSize(); + + std::uniform_int_distribution distribution(0, std::numeric_limits::max()); + std::vector data(size); + std::generate(data.begin(), data.end(), [&] { return static_cast(distribution(rng)); }); + + ctx.WriteBuffer(data); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void Module::Interface::IsDevelopment(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("IsDevelopment is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::SetBootReason(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("SetBootReason is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::GetBootReason(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("GetBootReason is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +ResultVal Module::Interface::GetConfigImpl(ConfigItem config_item) const { + switch (config_item) { + case ConfigItem::DisableProgramVerification: + case ConfigItem::DramId: + case ConfigItem::SecurityEngineInterruptNumber: + case ConfigItem::FuseVersion: + case ConfigItem::HardwareType: + case ConfigItem::HardwareState: + case ConfigItem::IsRecoveryBoot: + case ConfigItem::DeviceId: + case ConfigItem::BootReason: + case ConfigItem::MemoryMode: + case ConfigItem::IsDevelopmentFunctionEnabled: + case ConfigItem::KernelConfiguration: + case ConfigItem::IsChargerHiZModeEnabled: + case ConfigItem::QuestState: + case ConfigItem::RegulatorType: + case ConfigItem::DeviceUniqueKeyGeneration: + case ConfigItem::Package2Hash: + return ResultSecureMonitorNotImplemented; + case ConfigItem::ExosphereApiVersion: + // Get information about the current exosphere version. + return MakeResult((u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) | + (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) | + (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) | + (static_cast(HLE::ApiVersion::GetTargetFirmware()))); + case ConfigItem::ExosphereNeedsReboot: + // We are executing, so we aren't in the process of rebooting. + return MakeResult(u64{0}); + case ConfigItem::ExosphereNeedsShutdown: + // We are executing, so we aren't in the process of shutting down. + return MakeResult(u64{0}); + case ConfigItem::ExosphereGitCommitHash: + // Get information about the current exosphere git commit hash. + return MakeResult(u64{0}); + case ConfigItem::ExosphereHasRcmBugPatch: + // Get information about whether this unit has the RCM bug patched. + return MakeResult(u64{0}); + case ConfigItem::ExosphereBlankProdInfo: + // Get whether this unit should simulate a "blanked" PRODINFO. + return MakeResult(u64{0}); + case ConfigItem::ExosphereAllowCalWrites: + // Get whether this unit should allow writing to the calibration partition. + return MakeResult(u64{0}); + case ConfigItem::ExosphereEmummcType: + // Get what kind of emummc this unit has active. + return MakeResult(u64{0}); + case ConfigItem::ExospherePayloadAddress: + // Gets the physical address of the reboot payload buffer, if one exists. + return ResultSecureMonitorNotInitialized; + case ConfigItem::ExosphereLogConfiguration: + // Get the log configuration. + return MakeResult(u64{0}); + case ConfigItem::ExosphereForceEnableUsb30: + // Get whether usb 3.0 should be force-enabled. + return MakeResult(u64{0}); + default: + return ResultSecureMonitorInvalidArgument; + } +} + +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + auto module = std::make_shared(); + std::make_shared(system, module)->InstallAsService(service_manager); + std::make_shared(system, module)->InstallAsService(service_manager); + std::make_shared(system, module)->InstallAsService(service_manager); + std::make_shared(system, module)->InstallAsService(service_manager); + std::make_shared(system, module)->InstallAsService(service_manager); + std::make_shared(system, module)->InstallAsService(service_manager); + std::make_shared(system, module)->InstallAsService(service_manager); +} + +} // namespace Service::SPL diff --git a/src/core/hle/service/spl/spl_module.h b/src/core/hle/service/spl/spl_module.h new file mode 100644 index 000000000..61630df80 --- /dev/null +++ b/src/core/hle/service/spl/spl_module.h @@ -0,0 +1,48 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "core/hle/service/service.h" +#include "core/hle/service/spl/spl_results.h" +#include "core/hle/service/spl/spl_types.h" + +namespace Core { +class System; +} + +namespace Service::SPL { + +class Module final { +public: + class Interface : public ServiceFramework { + public: + explicit Interface(Core::System& system_, std::shared_ptr module_, + const char* name); + ~Interface() override; + + // General + void GetConfig(Kernel::HLERequestContext& ctx); + void ModularExponentiate(Kernel::HLERequestContext& ctx); + void SetConfig(Kernel::HLERequestContext& ctx); + void GenerateRandomBytes(Kernel::HLERequestContext& ctx); + void IsDevelopment(Kernel::HLERequestContext& ctx); + void SetBootReason(Kernel::HLERequestContext& ctx); + void GetBootReason(Kernel::HLERequestContext& ctx); + + protected: + std::shared_ptr module; + + private: + ResultVal GetConfigImpl(ConfigItem config_item) const; + + std::mt19937 rng; + }; +}; + +/// Registers all SPL services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); + +} // namespace Service::SPL diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp deleted file mode 100644 index 53a204796..000000000 --- a/src/core/hle/service/time/interface.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/service/time/interface.h" - -namespace Service::Time { - -Time::Time(std::shared_ptr module_, Core::System& system_, const char* name_) - : Interface{std::move(module_), system_, name_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, - {1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, - {2, &Time::GetStandardSteadyClock, "GetStandardSteadyClock"}, - {3, &Time::GetTimeZoneService, "GetTimeZoneService"}, - {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, - {5, nullptr, "GetEphemeralNetworkSystemClock"}, - {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, - {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"}, - {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, - {50, nullptr, "SetStandardSteadyClockInternalOffset"}, - {51, nullptr, "GetStandardSteadyClockRtcValue"}, - {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, - {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, - {102, nullptr, "GetStandardUserSystemClockInitialYear"}, - {200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, - {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, - {300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, - {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, - {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, - {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, - {501, &Time::CalculateSpanBetween, "CalculateSpanBetween"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -Time::~Time() = default; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h deleted file mode 100644 index c41766f1a..000000000 --- a/src/core/hle/service/time/interface.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/time/time.h" - -namespace Core { -class System; -} - -namespace Service::Time { - -class Time final : public Module::Interface { -public: - explicit Time(std::shared_ptr time, Core::System& system_, const char* name_); - ~Time() override; -}; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index d6f710eba..8fdd5076f 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -11,8 +11,8 @@ #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/service/time/interface.h" #include "core/hle/service/time/time.h" +#include "core/hle/service/time/time_interface.h" #include "core/hle/service/time/time_sharedmemory.h" #include "core/hle/service/time/time_zone_service.h" diff --git a/src/core/hle/service/time/time_interface.cpp b/src/core/hle/service/time/time_interface.cpp new file mode 100644 index 000000000..bb7b6b5c1 --- /dev/null +++ b/src/core/hle/service/time/time_interface.cpp @@ -0,0 +1,42 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/time/time_interface.h" + +namespace Service::Time { + +Time::Time(std::shared_ptr module_, Core::System& system_, const char* name_) + : Interface{std::move(module_), system_, name_} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, + {1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, + {2, &Time::GetStandardSteadyClock, "GetStandardSteadyClock"}, + {3, &Time::GetTimeZoneService, "GetTimeZoneService"}, + {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, + {5, nullptr, "GetEphemeralNetworkSystemClock"}, + {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, + {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"}, + {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, + {50, nullptr, "SetStandardSteadyClockInternalOffset"}, + {51, nullptr, "GetStandardSteadyClockRtcValue"}, + {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, + {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, + {102, nullptr, "GetStandardUserSystemClockInitialYear"}, + {200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, + {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, + {300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, + {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, + {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, + {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, + {501, &Time::CalculateSpanBetween, "CalculateSpanBetween"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +Time::~Time() = default; + +} // namespace Service::Time diff --git a/src/core/hle/service/time/time_interface.h b/src/core/hle/service/time/time_interface.h new file mode 100644 index 000000000..c41766f1a --- /dev/null +++ b/src/core/hle/service/time/time_interface.h @@ -0,0 +1,21 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/time/time.h" + +namespace Core { +class System; +} + +namespace Service::Time { + +class Time final : public Module::Interface { +public: + explicit Time(std::shared_ptr time, Core::System& system_, const char* name_); + ~Time() override; +}; + +} // namespace Service::Time -- cgit v1.2.3