diff --git a/exosphere/src/emummc_cfg.h b/exosphere/src/emummc_cfg.h index e9d16bab5..6a2f6d124 100644 --- a/exosphere/src/emummc_cfg.h +++ b/exosphere/src/emummc_cfg.h @@ -59,9 +59,9 @@ typedef struct { emummc_partition_config_t partition_cfg; emummc_file_config_t file_cfg; }; - //char emu_dir_path[EMUMMC_FILE_PATH_MAX]; + char emu_dir_path[EMUMMC_FILE_PATH_MAX]; } exo_emummc_config_t; -_Static_assert(sizeof(exo_emummc_config_t) == 0x90, "exo_emummc_config_t definition!"); +_Static_assert(sizeof(exo_emummc_config_t) == 0x110, "exo_emummc_config_t definition!"); #endif diff --git a/exosphere/src/smc_ams.c b/exosphere/src/smc_ams.c index 3fc1769ee..621a56639 100644 --- a/exosphere/src/smc_ams.c +++ b/exosphere/src/smc_ams.c @@ -228,46 +228,63 @@ uint32_t ams_write_address(smc_args_t *args) { uint32_t ams_get_emummc_config(smc_args_t *args) { /* This retrieves configuration for the current emummc context. */ /* args->X[1] = MMC id, must be size-bytes aligned and readable by EL0. */ - /* args->X[2] = Pointer to output (for path for filebased), must be at least 0x80 bytes. */ - upage_ref_t page_ref; + /* args->X[2] = Pointer to output (for paths for filebased + nintendo dir), must be at least 0x100 bytes. */ const uint32_t mmc_id = (uint32_t)args->X[1]; - void *user_address = (void *)args->X[2]; + const uintptr_t dram_address = args->X[2]; + const uintptr_t dram_page_offset = (dram_address & 0xFFFULL); const exo_emummc_config_t *emummc_cfg = exosphere_get_emummc_config(); if (mmc_id != EMUMMC_MMC_NAND) { /* Emummc config for non-NAND storage is not yet implemented. */ return 1; } + + /* Require page alignment for input address. */ + if (!ams_is_user_addr_valid(dram_address) || dram_page_offset > 0x1000 - 0x100) { + return 2; + } + + /* Map pages. */ + ams_map_userpage(dram_address); + + void *user_address = (void *)(AMS_USER_PAGE_SECURE_MONITOR_ADDR + dram_page_offset); + + /* Copy redirection dir out to user. */ + memcpy((void *)((uintptr_t)user_address + sizeof(emummc_cfg->file_cfg)), emummc_cfg->emu_dir_path, sizeof(emummc_cfg->emu_dir_path)); if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_NONE) { /* Just copy base config. */ memset(args, 0, sizeof(*args)); memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg)); _Static_assert(sizeof(emummc_cfg->base_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand base config too big!"); + + /* Unmap pages. */ + ams_unmap_userpage(); return 0; } else if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_PARTITION) { /* Copy base config and partition config. */ memset(args, 0, sizeof(*args)); memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg) + sizeof(emummc_cfg->partition_cfg)); _Static_assert(sizeof(emummc_cfg->base_cfg) + sizeof(emummc_cfg->partition_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand partition config too big!"); + + /* Unmap pages. */ + ams_unmap_userpage(); return 0; } else if (emummc_cfg->base_cfg.type == EMUMMC_TYPE_FILES) { - /* Copy path to userpage. */ - /* Initialize page reference. */ - if (upage_init(&page_ref, user_address) == 0) { - return 2; - } - /* Copy result output back to user. */ - if (secure_copy_to_user(&page_ref, user_address, &emummc_cfg->file_cfg, sizeof(emummc_cfg->file_cfg)) == 0) { - return 2; - } + /* Copy file dir path output to user. */ + memcpy(user_address, &emummc_cfg->file_cfg, sizeof(emummc_cfg->file_cfg)); /* Copy base config afterwards, since this can't fail. */ memset(args, 0, sizeof(*args)); memcpy(&args->X[1], emummc_cfg, sizeof(emummc_cfg->base_cfg)); _Static_assert(sizeof(emummc_cfg->base_cfg) <= sizeof(*args) - sizeof(args->X[0]), "Emunand base config too big!"); + + /* Unmap pages. */ + ams_unmap_userpage(); return 0; } else { + /* Unmap pages. */ + ams_unmap_userpage(); return 2; } } \ No newline at end of file diff --git a/fusee/fusee-secondary/src/emummc_cfg.h b/fusee/fusee-secondary/src/emummc_cfg.h index cc022845b..91d5bb515 100644 --- a/fusee/fusee-secondary/src/emummc_cfg.h +++ b/fusee/fusee-secondary/src/emummc_cfg.h @@ -98,9 +98,9 @@ typedef struct { emummc_partition_config_t partition_cfg; emummc_file_config_t file_cfg; }; - //char emu_dir_path[EMUMMC_FILE_PATH_MAX]; + char emu_dir_path[EMUMMC_FILE_PATH_MAX]; } exo_emummc_config_t; -_Static_assert(sizeof(exo_emummc_config_t) == 0x90, "exo_emummc_config_t definition!"); +_Static_assert(sizeof(exo_emummc_config_t) == 0x110, "exo_emummc_config_t definition!"); #endif diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 376d0f5c9..a6bf7e987 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -112,9 +112,14 @@ static int emummc_ini_handler(void *user, const char *section, const char *name, uintptr_t sector = 0; sscanf(value, "%x", §or); emummc_cfg->sector = sector; + } else if (strcmp(name, EMUMMC_ID_KEY) == 0) { + sscanf(value, "%lx", &emummc_cfg->id); } else if (strcmp(name, EMUMMC_PATH_KEY) == 0) { strncpy(emummc_cfg->path, value, sizeof(emummc_cfg->path) - 1); emummc_cfg->path[sizeof(emummc_cfg->path) - 1] = '\0'; + } else if (strcmp(name, EMUMMC_NINTENDO_PATH_KEY) == 0) { + strncpy(emummc_cfg->nintendo_path, value, sizeof(emummc_cfg->nintendo_path) - 1); + emummc_cfg->nintendo_path[sizeof(emummc_cfg->nintendo_path) - 1] = '\0'; } else { return 0; } @@ -209,7 +214,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) { } static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { - emummc_config_t emummc_cfg = {.enabled = false, .sector = -1, .path = ""}; + emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""}; /* Load emummc settings from BCT.ini file. */ if (ini_parse_string(get_loader_ctx()->bct0, emummc_ini_handler, &emummc_cfg) < 0) { @@ -219,8 +224,10 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { memset(exo_emummc_config, 0, sizeof(*exo_emummc_config)); exo_emummc_config->base_cfg.magic = MAGIC_EMUMMC_CONFIG; exo_emummc_config->base_cfg.type = EMUMMC_TYPE_NONE; - exo_emummc_config->base_cfg.id = 0; /* TODO: Multiple ID support. */ + exo_emummc_config->base_cfg.id = emummc_cfg.id; exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */ + strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path)); + exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0'; if (emummc_cfg.enabled) { if (emummc_cfg.sector >= 0) { @@ -233,8 +240,9 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { } } else if (is_valid_folder(emummc_cfg.path)) { exo_emummc_config->base_cfg.type = EMUMMC_TYPE_FILES; - strncpy(exo_emummc_config->file_cfg.path, emummc_cfg.path, sizeof(exo_emummc_config->file_cfg.path) - 1); - + strncpy(exo_emummc_config->file_cfg.path, emummc_cfg.path, sizeof(exo_emummc_config->file_cfg.path)); + exo_emummc_config->file_cfg.path[sizeof(exo_emummc_config->file_cfg.path) - 1] = '\0'; + int num_parts = 0; uint64_t part_limit = 0; char emummc_boot0_path[0x300 + 1] = {0}; diff --git a/fusee/fusee-secondary/src/nxboot.h b/fusee/fusee-secondary/src/nxboot.h index 3c4585d14..8a736ec26 100644 --- a/fusee/fusee-secondary/src/nxboot.h +++ b/fusee/fusee-secondary/src/nxboot.h @@ -22,11 +22,15 @@ #define EMUMMC_ENABLED_KEY "emummc_enabled" #define EMUMMC_SECTOR_KEY "emummc_sector" #define EMUMMC_PATH_KEY "emummc_path" +#define EMUMMC_NINTENDO_PATH_KEY "emummc_nintendo_path" +#define EMUMMC_ID_KEY "emummc_id" typedef struct { bool enabled; + uint32_t id; uint64_t sector; - char path[0x100]; + char path[0x80]; + char nintendo_path[0x80]; } emummc_config_t; #define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00 diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp index fb47fb79d..0cbcb97f8 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_service.cpp @@ -163,11 +163,11 @@ Result FsMitmService::OpenFileSystemWithId(Out> out_fs) { - /* We only care about redirecting this for NS/Emunand. */ - if (!IsEmunand()) { + /* We only care about redirecting this for NS/Emummc. */ + if (this->title_id != TitleId_Ns) { return ResultAtmosphereMitmShouldForwardToSession; } - if (this->title_id != TitleId_Ns) { + if (!IsEmummc()) { return ResultAtmosphereMitmShouldForwardToSession; } @@ -190,7 +190,7 @@ Result FsMitmService::OpenSdCardFileSystem(Out redir_fs = std::make_shared(new ProxyFileSystem(sd_fs), "/Nintendo", "/Emu/0000" /* TODO: Real Path */); + std::shared_ptr redir_fs = std::make_shared(new ProxyFileSystem(sd_fs), "/Nintendo", GetEmummcNintendoDirPath()); fs = std::make_shared(redir_fs); if (out_fs.IsDomain()) { out_domain_id = sd_fs.s.object_id; diff --git a/stratosphere/ams_mitm/source/utils.cpp b/stratosphere/ams_mitm/source/utils.cpp index d208d7829..52e52090c 100644 --- a/stratosphere/ams_mitm/source/utils.cpp +++ b/stratosphere/ams_mitm/source/utils.cpp @@ -65,6 +65,9 @@ static FsFile g_cal0_file = {0}; static u8 g_cal0_storage_backup[ProdinfoSize]; static u8 g_cal0_backup[ProdinfoSize]; +/* Emummc-related file. */ +static FsFile g_emummc_file = {0}; + static bool IsHexadecimal(const char *str) { while (*str) { if (isxdigit(*str)) { @@ -196,6 +199,14 @@ void Utils::InitializeThreadFunc(void *args) { } Utils::RefreshConfiguration(); + + /* If we're emummc, persist a write handle to prevent other processes from touching the image. */ + if (IsEmummc()) { + const char *emummc_file_path = GetEmummcFilePath(); + if (emummc_file_path != nullptr) { + fsFsOpenFile(&g_sd_filesystem, emummc_file_path, FS_OPEN_READ | FS_OPEN_WRITE, &g_emummc_file); + } + } /* Initialize set:sys. */ DoWithSmSession([&]() { diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 05c58ef00..afcd07535 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 05c58ef00263552d4925ed29ac0828cacdfc2ed1 +Subproject commit afcd075354dec43fae882c3ad4d5220336231d04