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/fusee/program/source/fatfs/ff.h b/fusee/program/source/fatfs/ff.h index edf3f80d5..c87202fad 100644 --- a/fusee/program/source/fatfs/ff.h +++ b/fusee/program/source/fatfs/ff.h @@ -172,8 +172,7 @@ typedef struct { LBA_t bitbase; /* Allocation bitmap base sector */ #endif LBA_t winsect; /* Current sector appearing in the win[] */ - BYTE pad[4]; - BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ + __attribute__((aligned(8))) BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; @@ -218,7 +217,7 @@ typedef struct { DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif #if !FF_FS_TINY - BYTE buf[FF_MAX_SS]; /* File private data read/write window */ + __attribute__((aligned(8))) BYTE buf[FF_MAX_SS]; /* File private data read/write window */ #endif } FIL; diff --git a/fusee/program/source/fatfs/fusee_diskio.cpp b/fusee/program/source/fatfs/fusee_diskio.cpp index 9afad4ff7..74cbad17f 100644 --- a/fusee/program/source/fatfs/fusee_diskio.cpp +++ b/fusee/program/source/fatfs/fusee_diskio.cpp @@ -16,7 +16,7 @@ #include #include "diskio_cpp.h" #include "../fusee_sd_card.hpp" -#include "../fusee_emummc.hpp" +#include "../fusee_mmc.hpp" bool diskio_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count) { return R_SUCCEEDED(::ams::nxboot::ReadSdCard(dst, size, sector_index, sector_count)); @@ -27,9 +27,10 @@ bool diskio_write_sd_card(size_t sector_index, size_t sector_count, const void * } bool diskio_read_system(void *dst, size_t size, size_t sector_index, size_t sector_count) { - return false; + return R_SUCCEEDED(::ams::nxboot::ReadMmc(dst, size, ::ams::sdmmc::MmcPartition::MmcPartition_UserData, sector_index, sector_count)); } bool diskio_write_system(size_t sector_index, size_t sector_count, const void *src, size_t size) { + /* Don't allow writes to eMMC GPP partition */ return false; } \ No newline at end of file diff --git a/fusee/program/source/fs/fusee_fs_api.cpp b/fusee/program/source/fs/fusee_fs_api.cpp index d72189241..4338b2c8a 100644 --- a/fusee/program/source/fs/fusee_fs_api.cpp +++ b/fusee/program/source/fs/fusee_fs_api.cpp @@ -26,9 +26,11 @@ namespace ams::fs { constexpr size_t MaxFiles = 8 + 64; constexpr size_t MaxDirectories = 2; - constinit bool g_is_sd_mounted = false; + constinit bool g_is_sd_mounted = false; + constinit bool g_is_sys_mounted = false; - alignas(0x10) constinit FATFS g_sd_fs = {}; + alignas(0x10) constinit FATFS g_sd_fs = {}; + alignas(0x10) constinit FATFS g_sys_fs = {}; alignas(0x10) constinit FIL g_files[MaxFiles] = {}; alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {}; @@ -117,6 +119,18 @@ namespace ams::fs { } + bool MountSys() { + AMS_ASSERT(!g_is_sys_mounted); + g_is_sys_mounted = f_mount(std::addressof(g_sys_fs), "sys:", 1) == FR_OK; + return g_is_sys_mounted; + } + + void UnmountSys() { + AMS_ASSERT(g_is_sys_mounted); + f_unmount("sys:"); + g_is_sys_mounted = false; + } + bool MountSdCard() { AMS_ASSERT(!g_is_sd_mounted); g_is_sd_mounted = f_mount(std::addressof(g_sd_fs), "sdmc:", 1) == FR_OK; diff --git a/fusee/program/source/fs/fusee_fs_api.hpp b/fusee/program/source/fs/fusee_fs_api.hpp index d47ec1952..e97a19c8c 100644 --- a/fusee/program/source/fs/fusee_fs_api.hpp +++ b/fusee/program/source/fs/fusee_fs_api.hpp @@ -98,6 +98,9 @@ namespace ams::fs { bool MountSdCard(); void UnmountSdCard(); + bool MountSys(); + void UnmountSys(); + Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path); Result CreateFile(const char *path, s64 size); diff --git a/fusee/program/source/fusee_emummc.cpp b/fusee/program/source/fusee_emummc.cpp index b56f5d005..509ddab3c 100644 --- a/fusee/program/source/fusee_emummc.cpp +++ b/fusee/program/source/fusee_emummc.cpp @@ -233,7 +233,7 @@ namespace ams::nxboot { } - void InitializeEmummc(bool emummc_enabled, const secmon::EmummcConfiguration &emummc_cfg) { + void InitializeEmummc(bool emummc_enabled, const secmon::EmummcEmmcConfiguration &emummc_cfg) { Result result; if (emummc_enabled) { /* Get sd card size. */ @@ -242,34 +242,65 @@ namespace ams::nxboot { ShowFatalError("Failed to get sd card size: 0x%08" PRIx32 "!\n", result.GetValue()); } - if (emummc_cfg.base_cfg.type == secmon::EmummcType_Partition) { - const s64 partition_start = emummc_cfg.partition_cfg.start_sector * sdmmc::SectorSize; - g_boot0_storage = AllocateObject(g_sd_card_storage, partition_start, 4_MB); - g_user_storage = AllocateObject(g_sd_card_storage, partition_start + 8_MB, sd_card_size - (partition_start + 8_MB)); - } else if (emummc_cfg.base_cfg.type == secmon::EmummcType_File) { - /* Get the base emummc path. */ - std::memcpy(g_emummc_path, emummc_cfg.file_cfg.path.str, sizeof(emummc_cfg.file_cfg.path.str)); - - /* Get path length. */ - auto len = std::strlen(g_emummc_path); - - /* Append emmc. */ - std::memcpy(g_emummc_path + len, "/eMMC", 6); - len += 5; - - /* Open boot0. */ - fs::FileHandle boot0_file; - std::memcpy(g_emummc_path + len, "/boot0", 7); - if (R_FAILED((result = fs::OpenFile(std::addressof(boot0_file), g_emummc_path, fs::OpenMode_Read)))) { - ShowFatalError("Failed to open emummc boot0 file: 0x%08" PRIx32 "!\n", result.GetValue()); + if(emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_Partition_Emmc || emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_Partition_Sd) { + /* Partition based emummc */ + if(emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_Partition_Emmc) { + /* When emmc based, init eMMC */ + if (R_FAILED((result = InitializeMmc()))) { + ShowFatalError("Failed to initialize mmc: 0x%08" PRIx32 "\n", result.GetValue()); + } } - /* Open boot1. */ - g_emummc_path[len + 5] = '1'; + /* Get SD or eMMC storage */ + fs::IStorage &storage = emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_Partition_Sd ? static_cast(g_sd_card_storage) : static_cast(g_mmc_user_storage); + + /* Get total storage size */ + s64 storage_size; + if (R_FAILED((result = storage.GetSize(std::addressof(storage_size))))) { + ShowFatalError("Failed to get storage size: 0x%08" PRIx32 "!\n", result.GetValue()); + } + + const s64 partition_start = emummc_cfg.partition_cfg.start_sector * sdmmc::SectorSize; + g_boot0_storage = AllocateObject(storage, partition_start, 4_MB); + g_user_storage = AllocateObject(storage, partition_start + 8_MB, storage_size - (partition_start + 8_MB)); + } else if (emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Emmc || emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Sd) { + /* File based emummc */ + if(emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Emmc) { + /* When emmc based, init eMMC */ + if (R_FAILED((result = InitializeMmc()))) { + ShowFatalError("Failed to initialize mmc: 0x%08" PRIx32 "\n", result.GetValue()); + } + + if (!fs::MountSys()) { + ShowFatalError("Failed to mount mmc!\n"); + } + } + + /* Set drive to read from */ + if (emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Sd) { + std::strcpy(g_emummc_path, "sdmc:"); + } else { + std::strcpy(g_emummc_path, "sys:"); + } + + std::memcpy(g_emummc_path + std::strlen(g_emummc_path), emummc_cfg.file_cfg.path.str, sizeof(emummc_cfg.file_cfg.path.str)); + std::strcat(g_emummc_path, "/eMMC"); + + auto len = std::strlen(g_emummc_path); + + /* Open boot0 file */ + fs::FileHandle boot0_file; + std::strcat(g_emummc_path, "/boot0"); + if(R_FAILED((result = fs::OpenFile(std::addressof(boot0_file), g_emummc_path, fs::OpenMode_Read)))) { + ShowFatalError("Failed to open emummc boot0 file: 0x%08" PRIx32 " %s!\n", result.GetValue(), g_emummc_path); + } + + /* Check if boot1 file exists */ + std::strcpy(g_emummc_path + len, "/boot1"); { fs::DirectoryEntryType entry_type; bool is_archive; - if (R_FAILED((result = fs::GetEntryType(std::addressof(entry_type), std::addressof(is_archive), g_emummc_path)))) { + if (R_FAILED((result = fs::GetEntryType(std::addressof(entry_type), std::addressof(is_archive), g_emummc_path)))){ ShowFatalError("Failed to find emummc boot1 file: 0x%08" PRIx32 "!\n", result.GetValue()); } @@ -278,16 +309,16 @@ namespace ams::nxboot { } } - /* Open userdata. */ - std::memcpy(g_emummc_path + len, "/00", 4); + /* Open userdata */ + std::strcpy(g_emummc_path + len, "/00"); fs::FileHandle user00_file; - if (R_FAILED((result = fs::OpenFile(std::addressof(user00_file), g_emummc_path, fs::OpenMode_Read)))) { + if(R_FAILED((result = fs::OpenFile(std::addressof(user00_file), g_emummc_path, fs::OpenMode_Read)))) { ShowFatalError("Failed to open emummc user %02d file: 0x%08" PRIx32 "!\n", 0, result.GetValue()); } - /* Create partitions. */ + /* Create partition */ g_boot0_storage = AllocateObject(boot0_file); - g_user_storage = AllocateObject(user00_file, len + 1); + g_user_storage = AllocateObject(user00_file, len + 1); } else { ShowFatalError("Unknown emummc type %d\n", static_cast(emummc_cfg.base_cfg.type)); } @@ -304,6 +335,7 @@ namespace ams::nxboot { g_boot0_storage = std::addressof(g_mmc_boot0_storage); g_user_storage = std::addressof(g_mmc_user_storage); } + if (g_boot0_storage == nullptr) { ShowFatalError("Failed to initialize BOOT0\n"); } diff --git a/fusee/program/source/fusee_emummc.hpp b/fusee/program/source/fusee_emummc.hpp index 5dd40aa8b..a0e99f6aa 100644 --- a/fusee/program/source/fusee_emummc.hpp +++ b/fusee/program/source/fusee_emummc.hpp @@ -20,7 +20,7 @@ namespace ams::nxboot { - void InitializeEmummc(bool emummc_enabled, const secmon::EmummcConfiguration &emummc_cfg); + void InitializeEmummc(bool emummc_enabled, const secmon::EmummcEmmcConfiguration &emummc_cfg); Result ReadBoot0(s64 offset, void *dst, size_t size); Result ReadPackage2(s64 offset, void *dst, size_t size); diff --git a/fusee/program/source/fusee_setup_horizon.cpp b/fusee/program/source/fusee_setup_horizon.cpp index 000bbe524..0a2000bc3 100644 --- a/fusee/program/source/fusee_setup_horizon.cpp +++ b/fusee/program/source/fusee_setup_horizon.cpp @@ -126,27 +126,33 @@ namespace ams::nxboot { bool ConfigureEmummc() { /* Set magic. */ - g_emummc_cfg.base_cfg.magic = secmon::EmummcBaseConfiguration::Magic; + auto &sd_cfg = g_emummc_cfg.sd_cfg; + auto &emmc_cfg = g_emummc_cfg.emmc_cfg; - /* Parse ini. */ - bool enabled = false; + emmc_cfg.base_cfg.magic = secmon::EmummcEmmcBaseConfiguration::Magic; + sd_cfg.base_cfg.magic = secmon::EmummcSdBaseConfiguration::Magic; + + bool emummc_driver_enabled = false; + + /* Parse emummc ini. */ + u32 enabled = 0; u32 id = 0; u32 sector = 0; const char *path = ""; const char *n_path = ""; + { IniSectionList sections; if (ParseIniSafe(sections, "sdmc:/emummc/emummc.ini")) { - for (const auto §ion : sections) { - /* We only care about the [emummc] section. */ + for (const auto §ion : sections){ + /* Skip non-emummc sections */ if (std::strcmp(section.name, "emummc")) { continue; } - /* Handle individual fields. */ for (const auto &entry : section.kv_list) { - if (std::strcmp(entry.key, "enabled") == 0) { - enabled = entry.value[0] != '0'; + if(std::strcmp(entry.key, "enabled") == 0) { + enabled = ParseDecimalInteger(entry.value); } else if (std::strcmp(entry.key, "id") == 0) { id = ParseHexInteger(entry.value); } else if (std::strcmp(entry.key, "sector") == 0) { @@ -161,26 +167,88 @@ namespace ams::nxboot { } } - /* Set values parsed from config. */ - g_emummc_cfg.base_cfg.id = id; - std::strncpy(g_emummc_cfg.emu_dir_path.str, n_path, sizeof(g_emummc_cfg.emu_dir_path.str)); - g_emummc_cfg.emu_dir_path.str[sizeof(g_emummc_cfg.emu_dir_path.str) - 1] = '\x00'; + /* Set parsed values to config */ + constexpr const char *emummc_err_str = "Invalid emummc setting!\n"; - if (enabled) { + emmc_cfg.base_cfg.id = id; + std::strncpy(emmc_cfg.emu_dir_path.str, n_path, sizeof(emmc_cfg.emu_dir_path.str)); + emmc_cfg.emu_dir_path.str[sizeof(emmc_cfg.emu_dir_path.str) - 1] = '\x00'; + + if (enabled == 1) { + /* SD based */ + emummc_driver_enabled = true; if (sector > 0) { - g_emummc_cfg.base_cfg.type = secmon::EmummcType_Partition; - g_emummc_cfg.partition_cfg.start_sector = sector; + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_Partition_Sd; + emmc_cfg.partition_cfg.start_sector = sector; } else if (path[0] != '\x00' && IsDirectoryExist(path)) { - g_emummc_cfg.base_cfg.type = secmon::EmummcType_File; - - std::strncpy(g_emummc_cfg.file_cfg.path.str, path, sizeof(g_emummc_cfg.file_cfg.path.str)); - g_emummc_cfg.file_cfg.path.str[sizeof(g_emummc_cfg.file_cfg.path.str) - 1] = '\x00'; + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_File_Sd; + std::strncpy(emmc_cfg.file_cfg.path.str, path, sizeof(emmc_cfg.file_cfg.path.str)); + emmc_cfg.file_cfg.path.str[sizeof(emmc_cfg.file_cfg.path.str) - 1] = '\x00'; } else { - ShowFatalError("Invalid emummc setting!\n"); + ShowFatalError(emummc_err_str); + } + } else if (enabled == 4){ + /* eMMC based */ + emummc_driver_enabled = true; + if (sector > 0) { + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_Partition_Emmc; + emmc_cfg.partition_cfg.start_sector = sector; + } else if (path[0] != '\x00' /* && IsDirectoryExist(path) */) { + /* TODO: Should check if directory exist on *eMMC* fat partition instead of SD */ + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_File_Emmc; + std::strncpy(emmc_cfg.file_cfg.path.str, path, sizeof(emmc_cfg.file_cfg.path.str)); + emmc_cfg.file_cfg.path.str[sizeof(emmc_cfg.file_cfg.path.str) - 1] = '\x00'; + } else { + ShowFatalError(emummc_err_str); + } + } else if (enabled == 0) { + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_None; + } else { + ShowFatalError(emummc_err_str); + } + + /* Parse emusd ini. */ + constexpr const char *emusd_err_str = "Invalid emusd setting!\n"; + + u32 sd_enabled = 0; + u32 sd_sector = 0; + + { + IniSectionList sections; + if (ParseIniSafe(sections, "sdmc:/emusd/emusd.ini")) { + for (const auto §ion : sections){ + /* Skip non-emummc sections */ + if (std::strcmp(section.name, "emusd")) { + continue; + } + + for (const auto &entry : section.kv_list) { + if(std::strcmp(entry.key, "enabled") == 0) { + sd_enabled = ParseDecimalInteger(entry.value); + } else if (std::strcmp(entry.key, "sector") == 0) { + sd_sector = ParseHexInteger(entry.value); + } + } + } } } - return enabled; + /* Set parsed values to config */ + if (sd_enabled == 4) { + emummc_driver_enabled = true; + if (sd_sector > 0) { + sd_cfg.partition_cfg.start_sector = sd_sector; + sd_cfg.base_cfg.type = secmon::EmummcSdType::EmummcSdType_Partition_Emmc; + } else { + ShowFatalError(emusd_err_str); + } + } else if (sd_enabled == 0) { + sd_cfg.base_cfg.type = secmon::EmummcSdType::EmummcSdType_None; + } else { + ShowFatalError(emusd_err_str); + } + + return emummc_driver_enabled; } u8 *LoadPackage1(fuse::SocType soc_type) { @@ -502,7 +570,8 @@ namespace ams::nxboot { storage_ctx.log_baud_rate = 115200; /* Set the fs version. */ - storage_ctx.emummc_cfg.base_cfg.fs_version = fs_version; + storage_ctx.emummc_cfg.emmc_cfg.base_cfg.fs_version = fs_version; + storage_ctx.emummc_cfg.sd_cfg.base_cfg.fs_version = fs_version; /* Parse fields from exosphere.ini */ { @@ -730,11 +799,12 @@ namespace ams::nxboot { DeriveAllKeys(soc_type); /* Determine whether we're using emummc. */ - const bool emummc_enabled = ConfigureEmummc(); + const bool emummc_driver_enabled = ConfigureEmummc(); + const bool emummc_enabled = g_emummc_cfg.emmc_cfg.base_cfg.type != secmon::EmummcEmmcType_None; /* Initialize emummc. */ /* NOTE: SYSTEM:/ accessible past this point. */ - InitializeEmummc(emummc_enabled, g_emummc_cfg); + InitializeEmummc(emummc_enabled, g_emummc_cfg.emmc_cfg); /* Read bootloader. */ const u8 * const package1 = LoadPackage1(soc_type); @@ -752,7 +822,7 @@ namespace ams::nxboot { const bool nogc_enabled = IsNogcEnabled(target_firmware); /* Decide what KIPs/patches we're loading. */ - const auto fs_version = ConfigureStratosphere(package2, target_firmware, emummc_enabled, nogc_enabled); + const auto fs_version = ConfigureStratosphere(package2, target_firmware, emummc_driver_enabled, nogc_enabled); /* Setup exosphere. */ ConfigureExosphere(soc_type, target_firmware, emummc_enabled, fs_version); @@ -761,7 +831,7 @@ namespace ams::nxboot { StartCpu(); /* Build modified package2. */ - RebuildPackage2(target_firmware, emummc_enabled); + RebuildPackage2(target_firmware, emummc_driver_enabled); /* Wait for confirmation that exosphere is ready. */ WaitSecureMonitorState(pkg1::SecureMonitorState_Initialized); diff --git a/fusee/program/source/fusee_stratosphere.cpp b/fusee/program/source/fusee_stratosphere.cpp index 34134ff42..2ad85fb8d 100644 --- a/fusee/program/source/fusee_stratosphere.cpp +++ b/fusee/program/source/fusee_stratosphere.cpp @@ -764,7 +764,7 @@ namespace ams::nxboot { } - u32 ConfigureStratosphere(const u8 *nn_package2, ams::TargetFirmware target_firmware, bool emummc_enabled, bool nogc_enabled) { + u32 ConfigureStratosphere(const u8 *nn_package2, ams::TargetFirmware target_firmware, bool emummc_driver_enabled, bool nogc_enabled) { /* Load KIPs off the SD card. */ { /* Create kip dir path. */ @@ -852,13 +852,13 @@ namespace ams::nxboot { /* Get FS version. */ const auto fs_version = GetFsVersion(fs_meta->kip_hash); if (fs_version >= FsVersion_Count) { - if (emummc_enabled || nogc_enabled) { + if (emummc_driver_enabled || nogc_enabled) { ShowFatalError("Failed to identify FS!\n"); } } /* If emummc is enabled, we need to decompress fs .text. */ - if (emummc_enabled) { + if (emummc_driver_enabled) { fs_meta->patch_segments |= (1 << 0); } @@ -876,7 +876,7 @@ namespace ams::nxboot { return static_cast(fs_version); } - void RebuildPackage2(ams::TargetFirmware target_firmware, bool emummc_enabled) { + void RebuildPackage2(ams::TargetFirmware target_firmware, bool emummc_driver_enabled) { /* Get the external package. */ const auto &external_package = GetExternalPackage(); @@ -909,7 +909,7 @@ namespace ams::nxboot { /* Read emummc, if needed. */ const InitialProcessHeader *emummc; s64 emummc_size; - if (emummc_enabled) { + if (emummc_driver_enabled) { emummc = static_cast(ReadFile(std::addressof(emummc_size), "sdmc:/atmosphere/emummc.kip")); if (emummc == nullptr) { emummc = reinterpret_cast(external_package.kips + external_package.header.emummc_meta.offset); @@ -958,7 +958,7 @@ namespace ams::nxboot { /* If necessary, inject emummc. */ u32 addl_text_offset = 0; - if (dst_kip->program_id == FsProgramId && emummc_enabled) { + if (dst_kip->program_id == FsProgramId && emummc_driver_enabled) { /* Get emummc extents. */ addl_text_offset = emummc->bss_address + emummc->bss_size; if ((emummc->flags & 7) || !util::IsAligned(addl_text_offset, 0x1000)) { 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..784a0c007 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::EmummcEmmcType_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,55 @@ 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; + /* id currently unused */ + u32 id; + 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) == 0x10); + + 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;