From 42c9e8f47c9c8c1a78624dea7bac547d2f4edbc1 Mon Sep 17 00:00:00 2001 From: Christoph Baumann Date: Fri, 9 May 2025 12:30:41 +0200 Subject: [PATCH] Support for SD redirection, eMMC redirection to eMMC GPP partition/file --- .../program/source/smc/secmon_smc_info.cpp | 95 +++++++++++----- .../program/source/smc/secmon_smc_info.hpp | 3 +- ...ecmon_configuration_context.arch.arm64.hpp | 10 +- .../secmon/secmon_emummc_context.hpp | 107 +++++++++++++----- .../secmon/secmon_monitor_context.hpp | 2 +- 5 files changed, 156 insertions(+), 61 deletions(-) diff --git a/exosphere/program/source/smc/secmon_smc_info.cpp b/exosphere/program/source/smc/secmon_smc_info.cpp index 11f4a693a..334072f73 100644 --- a/exosphere/program/source/smc/secmon_smc_info.cpp +++ b/exosphere/program/source/smc/secmon_smc_info.cpp @@ -279,12 +279,31 @@ namespace ams::secmon::smc { break; case ConfigItem::ExosphereAllowCalWrites: /* Get whether this unit should allow writing to the calibration partition. */ - args.r[1] = (GetEmummcConfiguration().IsEmummcActive() || GetSecmonConfiguration().AllowWritingToCalibrationBinarySysmmc()); + args.r[1] = (GetEmummcEmmcConfiguration().IsActive() || GetSecmonConfiguration().AllowWritingToCalibrationBinarySysmmc()); break; - case ConfigItem::ExosphereEmummcType: - /* Get what kind of emummc this unit has active. */ - /* NOTE: This may return values other than 1 in the future. */ - args.r[1] = (GetEmummcConfiguration().IsEmummcActive() ? 1 : 0); + case ConfigItem::ExosphereEmummcEmmcType: + /* Get what kind of eMMC redirection this unit has active. */ + /* NOTE: Even when returning 0, the emummc driver may be used if SD is redirected */ + { + auto &cfg = GetEmummcEmmcConfiguration(); + if(cfg.IsActive()) { + args.r[1] = cfg.base_cfg.type; + }else{ + args.r[1] = 0; + } + } + break; + case ConfigItem::ExosphereEmummcSdType: + /* Get what kind of SD redirection this unit has active. */ + /* NOTE: Even when returning 0, the emummc driver may be used if eMMC is redirected */ + { + auto &cfg = GetEmummcSdConfiguration(); + if(cfg.IsActive()) { + args.r[1] = cfg.base_cfg.type; + }else{ + args.r[1] = 0; + } + } break; case ConfigItem::ExospherePayloadAddress: /* Gets the physical address of the reboot payload buffer, if one exists. */ @@ -421,49 +440,65 @@ namespace ams::secmon::smc { const uintptr_t user_offset = user_address % 4_KB; /* Validate arguments. */ - /* NOTE: In the future, configuration for non-NAND storage may be implemented. */ - SMC_R_UNLESS(mmc == EmummcMmc_Nand, NotSupported); - SMC_R_UNLESS(user_offset + 2 * sizeof(EmummcFilePath) <= 4_KB, InvalidArgument); + /* NOTE: Only eMMC and SD redirection supported. GC redirection may be supported in the future */ + SMC_R_UNLESS(mmc == EmummcMmc_Nand || mmc == EmummcMmc_Sd, NotSupported); + SMC_R_UNLESS(mmc != EmummcMmc_Nand || user_offset + 2 * sizeof(EmummcFilePath) <= 4_KB, InvalidArgument); - /* Get the emummc config. */ - const auto &cfg = GetEmummcConfiguration(); - static_assert(sizeof(cfg.file_cfg) == sizeof(EmummcFilePath)); - static_assert(sizeof(cfg.emu_dir_path) == sizeof(EmummcFilePath)); - - /* Clear the output. */ constexpr size_t InlineOutputSize = sizeof(args) - sizeof(args.r[0]); u8 * const inline_output = static_cast(static_cast(std::addressof(args.r[1]))); std::memset(inline_output, 0, InlineOutputSize); - /* Copy out the configuration. */ - { - /* Map the user output page. */ - AtmosphereUserPageMapper mapper(user_address); - SMC_R_UNLESS(mapper.Map(), InvalidArgument); + if(mmc == EmummcMmc_Nand){ + /* Copy emummc config for eMMC redirection */ + + /* Get emummc config for eMMC redirection */ + const auto &cfg = GetEmummcEmmcConfiguration(); - /* Copy the base configuration. */ static_assert(sizeof(cfg.base_cfg) <= InlineOutputSize); std::memcpy(inline_output, std::addressof(cfg.base_cfg), sizeof(cfg.base_cfg)); - /* Copy out type-specific data. */ - switch (cfg.base_cfg.type) { - case EmummcType_None: - /* No additional configuration needs to be copied. */ + AtmosphereUserPageMapper mapper(user_address); + SMC_R_UNLESS(mapper.Map(), InvalidArgument); + + switch(cfg.base_cfg.type){ + case EmummcEmmcType_None: + /* Nothing to copy if disabled */ break; - case EmummcType_Partition: - /* Copy the partition config. */ + case EmummcEmmcType_Partition_Emmc: + case EmummcEmmcType_Partition_Sd: + /* Copy file config, if file based */ static_assert(sizeof(cfg.base_cfg) + sizeof(cfg.partition_cfg) <= InlineOutputSize); std::memcpy(inline_output + sizeof(cfg.base_cfg), std::addressof(cfg.partition_cfg), sizeof(cfg.partition_cfg)); break; - case EmummcType_File: - /* Copy the file config. */ + case EmummcEmmcType_File_Emmc: + case EmummcEmmcType_File_Sd: + /* Copy partition config, if partition based */ SMC_R_UNLESS(mapper.CopyToUser(user_address, std::addressof(cfg.file_cfg), sizeof(cfg.file_cfg)), InvalidArgument); break; AMS_UNREACHABLE_DEFAULT_CASE(); } - /* Copy the redirection directory path to the user page. */ - SMC_R_UNLESS(mapper.CopyToUser(user_address + sizeof(EmummcFilePath), std::addressof(cfg.emu_dir_path), sizeof(cfg.emu_dir_path)), InvalidArgument); + /* Copy the redirection directory path to the user page */ + SMC_R_UNLESS(mapper.CopyToUser(user_address + sizeof(cfg.file_cfg), std::addressof(cfg.emu_dir_path), sizeof(cfg.emu_dir_path)), InvalidArgument); + }else if(mmc == EmummcMmc_Sd){ + /* Copy emummc config for SD redirection */ + + /* Get emummc config for SD redirection */ + const auto &cfg = GetEmummcSdConfiguration(); + + static_assert(sizeof(cfg.base_cfg) <= InlineOutputSize); + std::memcpy(inline_output, std::addressof(cfg.base_cfg), sizeof(cfg.base_cfg)); + + switch(cfg.base_cfg.type) { + case EmummcSdType_None: + break; + case EmummcSdType_Partition_Emmc: + static_assert(sizeof(cfg.base_cfg) + sizeof(cfg.partition_cfg) <= InlineOutputSize); + std::memcpy(inline_output + sizeof(cfg.base_cfg), std::addressof(cfg.partition_cfg), sizeof(cfg.partition_cfg)); + break; + /* File based and SD partition based (currently) not supported for SD redirection */ + AMS_UNREACHABLE_DEFAULT_CASE(); + } } return SmcResult::Success; diff --git a/exosphere/program/source/smc/secmon_smc_info.hpp b/exosphere/program/source/smc/secmon_smc_info.hpp index 605bbf333..a2a2e4c3e 100644 --- a/exosphere/program/source/smc/secmon_smc_info.hpp +++ b/exosphere/program/source/smc/secmon_smc_info.hpp @@ -47,12 +47,13 @@ namespace ams::secmon::smc { ExosphereHasRcmBugPatch = 65004, ExosphereBlankProdInfo = 65005, ExosphereAllowCalWrites = 65006, - ExosphereEmummcType = 65007, + ExosphereEmummcEmmcType = 65007, ExospherePayloadAddress = 65008, ExosphereLogConfiguration = 65009, ExosphereForceEnableUsb30 = 65010, ExosphereSupportedHosVersion = 65011, ExosphereApproximateApiVersion = 65012, + ExosphereEmummcSdType = 65013, }; SmcResult SmcGetConfigUser(SmcArguments &args); diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp index 9eacd856f..9c9ae2618 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp @@ -28,7 +28,7 @@ namespace ams::secmon { }; union { EmummcConfiguration emummc_cfg; - u8 _raw_emummc_config[0x120]; + u8 _raw_emummc_config[0x128]; }; u8 sealed_device_keys[pkg1::KeyGeneration_Max][se::AesBlockSize]; u8 sealed_master_keys[pkg1::KeyGeneration_Max][se::AesBlockSize]; @@ -88,8 +88,12 @@ namespace ams::secmon { return GetConfigurationContext().secmon_cfg; } - ALWAYS_INLINE const EmummcConfiguration &GetEmummcConfiguration() { - return GetConfigurationContext().emummc_cfg; + ALWAYS_INLINE const EmummcEmmcConfiguration &GetEmummcEmmcConfiguration() { + return GetConfigurationContext().emummc_cfg.emmc_cfg; + } + + ALWAYS_INLINE const EmummcSdConfiguration &GetEmummcSdConfiguration() { + return GetConfigurationContext().emummc_cfg.sd_cfg; } ALWAYS_INLINE const pkg1::BootConfig &GetBootConfig() { diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp index d42d4e2fc..9c2eaac1f 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp @@ -18,10 +18,21 @@ namespace ams::secmon { - enum EmummcType : u32 { - EmummcType_None = 0, - EmummcType_Partition = 1, - EmummcType_File = 2, + enum EmummcEmmcType : u32 { + EmummcEmmcType_None = 0, + EmummcEmmcType_Partition_Sd = 1, + EmummcEmmcType_File_Sd = 2, + EmummcEmmcType_Partition_Emmc = 3, + EmummcEmmcType_File_Emmc = 4, + }; + + enum EmummcSdType : u32 { + EmummcSdType_None = 0, + EmummcSdType_Partition_Emmc = 3, + // Not (currently) supported + // EmummcSdType_Partition_Sd = 1, + // EmummcSdType_File_Sd = 2, + // EmummcSdType_File_Emmc = 4, }; enum EmummcMmc { @@ -38,24 +49,6 @@ namespace ams::secmon { static_assert(util::is_pod::value); static_assert(sizeof(EmummcFilePath) == EmummcFilePathLengthMax); - struct EmummcBaseConfiguration { - static constexpr u32 Magic = util::FourCC<'E','F','S','0'>::Code; - - u32 magic; - EmummcType type; - u32 id; - u32 fs_version; - - constexpr bool IsValid() const { - return this->magic == Magic; - } - - constexpr bool IsEmummcActive() const { - return this->IsValid() && this->type != EmummcType_None; - } - }; - static_assert(util::is_pod::value); - static_assert(sizeof(EmummcBaseConfiguration) == 0x10); struct EmummcPartitionConfiguration { u64 start_sector; @@ -67,8 +60,27 @@ namespace ams::secmon { }; static_assert(util::is_pod::value); - struct EmummcConfiguration { - EmummcBaseConfiguration base_cfg; + struct EmummcEmmcBaseConfiguration { + static constexpr u32 Magic = util::FourCC<'E','F','S','0'>::Code; + u32 magic; + EmummcEmmcType type; + u32 id; + u32 fs_version; + + constexpr bool IsValid() const { + return this->magic == Magic; + } + + constexpr bool IsActive() const { + return this->IsValid() && this->type != EmummcEmmcType::EmummcType_None; + } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(EmummcEmmcBaseConfiguration) == 0x10); + + + struct EmummcEmmcConfiguration { + EmummcEmmcBaseConfiguration base_cfg; union { EmummcPartitionConfiguration partition_cfg; EmummcFileConfiguration file_cfg; @@ -79,10 +91,53 @@ namespace ams::secmon { return this->base_cfg.IsValid(); } - constexpr bool IsEmummcActive() const { - return this->base_cfg.IsEmummcActive(); + constexpr bool IsActive() const { + return this->base_cfg.IsActive(); } }; + static_assert(util::is_pod::value); + static_assert(sizeof(EmummcEmmcConfiguration) == 0x110); + + struct EmummcSdBaseConfiguration { + static constexpr u32 Magic = util::FourCC<'E','F','S','0'>::Code; + u32 magic; + EmummcSdType type; + u32 fs_version; + + constexpr bool IsValid() const { + return this->magic == Magic; + } + + constexpr bool IsActive() const { + return this->IsValid() && this->type != EmummcSdType::EmummcSdType_None; + } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(EmummcSdBaseConfiguration) == 0x0C); + + struct EmummcSdConfiguration { + EmummcSdBaseConfiguration base_cfg; + union { + EmummcPartitionConfiguration partition_cfg; + // File based (currently) not supported + // EmummcFileConfiguration file_cfg + }; + + constexpr bool IsValid() const { + return this->base_cfg.IsValid(); + } + + constexpr bool IsActive() const { + return this->base_cfg.IsActive(); + } + }; + static_assert(util::is_pod::value); + static_assert(sizeof(EmummcSdConfiguration) == 0x18); + + struct EmummcConfiguration { + EmummcEmmcConfiguration emmc_cfg; + EmummcSdConfiguration sd_cfg; + }; static_assert(util::is_pod::value); static_assert(sizeof(EmummcConfiguration) <= 0x200); diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp index c37b76c82..d12c1d88f 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp @@ -50,7 +50,7 @@ namespace ams::secmon { constexpr bool IsValid() const { return this->magic == Magic; } }; static_assert(util::is_pod::value); - static_assert(sizeof(SecureMonitorStorageConfiguration) == 0x130); + static_assert(sizeof(SecureMonitorStorageConfiguration) == 0x148); struct SecureMonitorConfiguration { ams::TargetFirmware target_firmware;