diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 8fbbca114..fd8cf17af 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -220,6 +220,24 @@ void Module::Interface::SecureInfoGetByte101(Kernel::HLERequestContext& ctx) { rb.Push(0); } +void Module::Interface::SetUUIDClockSequence(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + + cfg->mcu_data.clock_sequence = rp.Pop(); + cfg->SaveMCUConfig(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::GetUUIDClockSequence(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast(cfg->mcu_data.clock_sequence)); +} + void Module::Interface::GetTransferableId(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); const u32 app_id_salt = rp.Pop() & 0x000FFFFF; @@ -557,8 +575,33 @@ ResultCode Module::LoadConfigNANDSaveFile() { return FormatConfig(); } +void Module::LoadMCUConfig() { + FileUtil::IOFile mcu_data_file( + fmt::format("{}/mcu.dat", FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir)), "r"); + + if (mcu_data_file.IsOpen() && mcu_data_file.GetSize() >= sizeof(MCUData) && + mcu_data_file.ReadBytes(&mcu_data, sizeof(MCUData)) == sizeof(MCUData)) { + if (mcu_data.IsValid()) { + return; + } + } + mcu_data_file.Close(); + mcu_data = MCUData(); + SaveMCUConfig(); +} + +void Module::SaveMCUConfig() { + FileUtil::IOFile mcu_data_file( + fmt::format("{}/mcu.dat", FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir)), "w"); + + if (mcu_data_file.IsOpen()) { + mcu_data_file.WriteBytes(&mcu_data, sizeof(MCUData)); + } +} + Module::Module() { LoadConfigNANDSaveFile(); + LoadMCUConfig(); // Check the config savegame EULA Version and update it to 0x7F7F if necessary // so users will never get a prompt to accept EULA auto version = GetEULAVersion(); diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index 738709829..bff4021b4 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h @@ -82,7 +82,7 @@ enum ConfigBlockID { DebugModeBlockID = 0x00130000, ClockSequenceBlockID = 0x00150000, Unknown_0x00150001 = 0x00150001, - NpnsUrlID = 0x00150002, // Maybe? 3dbrew documentation is weirdly written. + ServerType = 0x00150002, Unknown_0x00160000 = 0x00160000, MiiverseAccessKeyBlockID = 0x00170000, QtmInfraredLedRelatedBlockID = 0x00180000, @@ -230,6 +230,27 @@ public: */ void SecureInfoGetByte101(Kernel::HLERequestContext& ctx); + /** + * CFG::SetUUIDClockSequence service function + * Inputs: + * 1 : UUID Clock Sequence + * Outputs: + * 0 : Result Header code + * 1 : Result of function, 0 on success, otherwise error code + */ + void SetUUIDClockSequence(Kernel::HLERequestContext& ctx); + + /** + * CFG::GetUUIDClockSequence service function + * Inputs: + * 1 : None + * Outputs: + * 0 : Result Header code + * 1 : Result of function, 0 on success, otherwise error code + * 2 : UUID Clock Sequence + */ + void GetUUIDClockSequence(Kernel::HLERequestContext& ctx); + /** * CFG::GetTransferableId service function * Inputs: @@ -338,6 +359,25 @@ public: }; private: + // Represents save data that would normally be stored in the MCU + // on real hardware. Try to keep this struct backwards compatible + // if a new version is needed to prevent data loss. + struct MCUData { + struct Header { + static constexpr u32 MAGIC_VALUE = 0x4455434D; + static constexpr u32 VERSION_VALUE = 1; + u32 magic = MAGIC_VALUE; + u32 version = VERSION_VALUE; + u64 reserved = 0; + }; + Header header; + u32 clock_sequence = 0; + + [[nodiscard]] bool IsValid() const { + return header.magic == Header::MAGIC_VALUE && header.version == Header::VERSION_VALUE; + } + }; + ResultVal GetConfigBlockPointer(u32 block_id, u32 size, AccessFlag accesss_flag); /** @@ -397,6 +437,11 @@ private: */ ResultCode LoadConfigNANDSaveFile(); + /** + * Loads MCU specific data + */ + void LoadMCUConfig(); + public: u32 GetRegionValue(); @@ -538,11 +583,17 @@ public: */ ResultCode UpdateConfigNANDSavegame(); + /** + * Saves MCU specific data + */ + void SaveMCUConfig(); + private: static constexpr u32 CONFIG_SAVEFILE_SIZE = 0x8000; std::array cfg_config_file_buffer; std::unique_ptr cfg_system_save_data_archive; u32 preferred_region_code = 0; + MCUData mcu_data{}; template void serialize(Archive& ar, const unsigned int); diff --git a/src/core/hle/service/cfg/cfg_defaults.cpp b/src/core/hle/service/cfg/cfg_defaults.cpp index 4f31e3eda..3ecd85e07 100644 --- a/src/core/hle/service/cfg/cfg_defaults.cpp +++ b/src/core/hle/service/cfg/cfg_defaults.cpp @@ -57,6 +57,8 @@ constexpr ConsoleModelInfo DEFAULT_CONSOLE_MODEL{NEW_NINTENDO_3DS_XL, {0, 0, 0}} constexpr std::array DEFAULT_X_DEVICE_TOKEN = {}; constexpr u32_le DEFAULT_SYSTEM_SETUP_REQUIRED_FLAG = 1; constexpr u32_le DEFAULT_DEBUG_MODE_FLAG = 0; +constexpr u32_le DEFAULT_CLOCK_SEQUENCE = 0; +constexpr const char DEFAULT_SERVER_TYPE[4] = {'L', '1', '\0', '\0'}; constexpr u32_le DEFAULT_0x00160000_DATA = 0; constexpr u32_le DEFAULT_MIIVERSE_ACCESS_KEY = 0; @@ -108,6 +110,9 @@ static const std::unordered_map DEFAULT_CONF sizeof(DEFAULT_SYSTEM_SETUP_REQUIRED_FLAG)}}, {DebugModeBlockID, {AccessFlag::Global, &DEFAULT_DEBUG_MODE_FLAG, sizeof(DEFAULT_DEBUG_MODE_FLAG)}}, + {ClockSequenceBlockID, + {AccessFlag::System, &DEFAULT_CLOCK_SEQUENCE, sizeof(DEFAULT_CLOCK_SEQUENCE)}}, + {ServerType, {AccessFlag::Global, DEFAULT_SERVER_TYPE, sizeof(DEFAULT_SERVER_TYPE)}}, {Unknown_0x00160000, {AccessFlag::Global, &DEFAULT_0x00160000_DATA, sizeof(DEFAULT_0x00160000_DATA)}}, {MiiverseAccessKeyBlockID, diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index e75ca8548..3b2a50ff4 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp @@ -34,6 +34,8 @@ CFG_S::CFG_S(std::shared_ptr cfg) : Module::Interface(std::move(cfg), "c {0x0407, &CFG_S::SecureInfoGetByte101, "SecureInfoGetByte101"}, {0x0408, nullptr, "SecureInfoGetSerialNo"}, {0x0409, nullptr, "UpdateConfigBlk00040003"}, + {0x040D, &CFG_S::SetUUIDClockSequence, "SetUUIDClockSequence"}, + {0x040E, &CFG_S::GetUUIDClockSequence, "GetUUIDClockSequence"}, // clang-format on }; RegisterHandlers(functions);