2 Commits

Author SHA1 Message Date
Christoph Baumann
42c9e8f47c Support for SD redirection, eMMC redirection to eMMC GPP partition/file 2025-05-09 12:30:41 +02:00
Christoph Baumann
5fb3507a2a add missing cast 2025-02-19 14:32:21 +01:00
6 changed files with 157 additions and 62 deletions

View File

@@ -279,12 +279,31 @@ namespace ams::secmon::smc {
break; break;
case ConfigItem::ExosphereAllowCalWrites: case ConfigItem::ExosphereAllowCalWrites:
/* Get whether this unit should allow writing to the calibration partition. */ /* 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; break;
case ConfigItem::ExosphereEmummcType: case ConfigItem::ExosphereEmummcEmmcType:
/* Get what kind of emummc this unit has active. */ /* Get what kind of eMMC redirection this unit has active. */
/* NOTE: This may return values other than 1 in the future. */ /* NOTE: Even when returning 0, the emummc driver may be used if SD is redirected */
args.r[1] = (GetEmummcConfiguration().IsEmummcActive() ? 1 : 0); {
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; break;
case ConfigItem::ExospherePayloadAddress: case ConfigItem::ExospherePayloadAddress:
/* Gets the physical address of the reboot payload buffer, if one exists. */ /* 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; const uintptr_t user_offset = user_address % 4_KB;
/* Validate arguments. */ /* Validate arguments. */
/* NOTE: In the future, configuration for non-NAND storage may be implemented. */ /* NOTE: Only eMMC and SD redirection supported. GC redirection may be supported in the future */
SMC_R_UNLESS(mmc == EmummcMmc_Nand, NotSupported); SMC_R_UNLESS(mmc == EmummcMmc_Nand || mmc == EmummcMmc_Sd, NotSupported);
SMC_R_UNLESS(user_offset + 2 * sizeof(EmummcFilePath) <= 4_KB, InvalidArgument); 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]); constexpr size_t InlineOutputSize = sizeof(args) - sizeof(args.r[0]);
u8 * const inline_output = static_cast<u8 *>(static_cast<void *>(std::addressof(args.r[1]))); u8 * const inline_output = static_cast<u8 *>(static_cast<void *>(std::addressof(args.r[1])));
std::memset(inline_output, 0, InlineOutputSize); std::memset(inline_output, 0, InlineOutputSize);
/* Copy out the configuration. */ if(mmc == EmummcMmc_Nand){
{ /* Copy emummc config for eMMC redirection */
/* Map the user output page. */
AtmosphereUserPageMapper mapper(user_address); /* Get emummc config for eMMC redirection */
SMC_R_UNLESS(mapper.Map(), InvalidArgument); const auto &cfg = GetEmummcEmmcConfiguration();
/* Copy the base configuration. */
static_assert(sizeof(cfg.base_cfg) <= InlineOutputSize); static_assert(sizeof(cfg.base_cfg) <= InlineOutputSize);
std::memcpy(inline_output, std::addressof(cfg.base_cfg), sizeof(cfg.base_cfg)); std::memcpy(inline_output, std::addressof(cfg.base_cfg), sizeof(cfg.base_cfg));
/* Copy out type-specific data. */ AtmosphereUserPageMapper mapper(user_address);
switch (cfg.base_cfg.type) { SMC_R_UNLESS(mapper.Map(), InvalidArgument);
case EmummcType_None:
/* No additional configuration needs to be copied. */ switch(cfg.base_cfg.type){
case EmummcEmmcType_None:
/* Nothing to copy if disabled */
break; break;
case EmummcType_Partition: case EmummcEmmcType_Partition_Emmc:
/* Copy the partition config. */ case EmummcEmmcType_Partition_Sd:
/* Copy file config, if file based */
static_assert(sizeof(cfg.base_cfg) + sizeof(cfg.partition_cfg) <= InlineOutputSize); 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)); std::memcpy(inline_output + sizeof(cfg.base_cfg), std::addressof(cfg.partition_cfg), sizeof(cfg.partition_cfg));
break; break;
case EmummcType_File: case EmummcEmmcType_File_Emmc:
/* Copy the file config. */ 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); SMC_R_UNLESS(mapper.CopyToUser(user_address, std::addressof(cfg.file_cfg), sizeof(cfg.file_cfg)), InvalidArgument);
break; break;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }
/* Copy the redirection directory path to the user page. */ /* 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); 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; return SmcResult::Success;

View File

@@ -47,12 +47,13 @@ namespace ams::secmon::smc {
ExosphereHasRcmBugPatch = 65004, ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005, ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006, ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007, ExosphereEmummcEmmcType = 65007,
ExospherePayloadAddress = 65008, ExospherePayloadAddress = 65008,
ExosphereLogConfiguration = 65009, ExosphereLogConfiguration = 65009,
ExosphereForceEnableUsb30 = 65010, ExosphereForceEnableUsb30 = 65010,
ExosphereSupportedHosVersion = 65011, ExosphereSupportedHosVersion = 65011,
ExosphereApproximateApiVersion = 65012, ExosphereApproximateApiVersion = 65012,
ExosphereEmummcSdType = 65013,
}; };
SmcResult SmcGetConfigUser(SmcArguments &args); SmcResult SmcGetConfigUser(SmcArguments &args);

View File

@@ -78,7 +78,7 @@ namespace ams::nxboot {
u32 num_sectors; u32 num_sectors;
R_TRY(GetMmcMemoryCapacity(std::addressof(num_sectors), Partition)); R_TRY(GetMmcMemoryCapacity(std::addressof(num_sectors), Partition));
*out = num_sectors * sdmmc::SectorSize; *out = static_cast<s64>(num_sectors) * static_cast<s64>(sdmmc::SectorSize);
R_SUCCEED(); R_SUCCEED();
} }

View File

@@ -28,7 +28,7 @@ namespace ams::secmon {
}; };
union { union {
EmummcConfiguration emummc_cfg; EmummcConfiguration emummc_cfg;
u8 _raw_emummc_config[0x120]; u8 _raw_emummc_config[0x128];
}; };
u8 sealed_device_keys[pkg1::KeyGeneration_Max][se::AesBlockSize]; u8 sealed_device_keys[pkg1::KeyGeneration_Max][se::AesBlockSize];
u8 sealed_master_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; return GetConfigurationContext().secmon_cfg;
} }
ALWAYS_INLINE const EmummcConfiguration &GetEmummcConfiguration() { ALWAYS_INLINE const EmummcEmmcConfiguration &GetEmummcEmmcConfiguration() {
return GetConfigurationContext().emummc_cfg; return GetConfigurationContext().emummc_cfg.emmc_cfg;
}
ALWAYS_INLINE const EmummcSdConfiguration &GetEmummcSdConfiguration() {
return GetConfigurationContext().emummc_cfg.sd_cfg;
} }
ALWAYS_INLINE const pkg1::BootConfig &GetBootConfig() { ALWAYS_INLINE const pkg1::BootConfig &GetBootConfig() {

View File

@@ -18,10 +18,21 @@
namespace ams::secmon { namespace ams::secmon {
enum EmummcType : u32 { enum EmummcEmmcType : u32 {
EmummcType_None = 0, EmummcEmmcType_None = 0,
EmummcType_Partition = 1, EmummcEmmcType_Partition_Sd = 1,
EmummcType_File = 2, 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 { enum EmummcMmc {
@@ -38,24 +49,6 @@ namespace ams::secmon {
static_assert(util::is_pod<EmummcFilePath>::value); static_assert(util::is_pod<EmummcFilePath>::value);
static_assert(sizeof(EmummcFilePath) == EmummcFilePathLengthMax); 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<EmummcBaseConfiguration>::value);
static_assert(sizeof(EmummcBaseConfiguration) == 0x10);
struct EmummcPartitionConfiguration { struct EmummcPartitionConfiguration {
u64 start_sector; u64 start_sector;
@@ -67,8 +60,27 @@ namespace ams::secmon {
}; };
static_assert(util::is_pod<EmummcFileConfiguration>::value); static_assert(util::is_pod<EmummcFileConfiguration>::value);
struct EmummcConfiguration { struct EmummcEmmcBaseConfiguration {
EmummcBaseConfiguration base_cfg; 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<EmummcEmmcBaseConfiguration>::value);
static_assert(sizeof(EmummcEmmcBaseConfiguration) == 0x10);
struct EmummcEmmcConfiguration {
EmummcEmmcBaseConfiguration base_cfg;
union { union {
EmummcPartitionConfiguration partition_cfg; EmummcPartitionConfiguration partition_cfg;
EmummcFileConfiguration file_cfg; EmummcFileConfiguration file_cfg;
@@ -79,10 +91,53 @@ namespace ams::secmon {
return this->base_cfg.IsValid(); return this->base_cfg.IsValid();
} }
constexpr bool IsEmummcActive() const { constexpr bool IsActive() const {
return this->base_cfg.IsEmummcActive(); return this->base_cfg.IsActive();
} }
}; };
static_assert(util::is_pod<EmummcEmmcConfiguration>::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<EmummcSdBaseConfiguration>::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<EmummcSdConfiguration>::value);
static_assert(sizeof(EmummcSdConfiguration) == 0x18);
struct EmummcConfiguration {
EmummcEmmcConfiguration emmc_cfg;
EmummcSdConfiguration sd_cfg;
};
static_assert(util::is_pod<EmummcConfiguration>::value); static_assert(util::is_pod<EmummcConfiguration>::value);
static_assert(sizeof(EmummcConfiguration) <= 0x200); static_assert(sizeof(EmummcConfiguration) <= 0x200);

View File

@@ -50,7 +50,7 @@ namespace ams::secmon {
constexpr bool IsValid() const { return this->magic == Magic; } constexpr bool IsValid() const { return this->magic == Magic; }
}; };
static_assert(util::is_pod<SecureMonitorStorageConfiguration>::value); static_assert(util::is_pod<SecureMonitorStorageConfiguration>::value);
static_assert(sizeof(SecureMonitorStorageConfiguration) == 0x130); static_assert(sizeof(SecureMonitorStorageConfiguration) == 0x148);
struct SecureMonitorConfiguration { struct SecureMonitorConfiguration {
ams::TargetFirmware target_firmware; ams::TargetFirmware target_firmware;