diff --git a/exosphere/src/emummc_cfg.h b/exosphere/src/emummc_cfg.h index 3a7f01f5b..e9d16bab5 100644 --- a/exosphere/src/emummc_cfg.h +++ b/exosphere/src/emummc_cfg.h @@ -59,6 +59,7 @@ typedef struct { emummc_partition_config_t partition_cfg; emummc_file_config_t file_cfg; }; + //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!"); diff --git a/fusee/fusee-secondary/src/device_partition.c b/fusee/fusee-secondary/src/device_partition.c index 940ae985f..076aaf58d 100644 --- a/fusee/fusee-secondary/src/device_partition.c +++ b/fusee/fusee-secondary/src/device_partition.c @@ -77,7 +77,7 @@ int device_partition_write_data(device_partition_t *devpart, const void *src, ui int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit) { int rc = 0; - uint64_t target_sector = 0; + uint64_t target_sector = sector; char target_path[0x300 + 1] = {0}; /* Perform initialization steps, if necessary. */ @@ -150,7 +150,7 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6 int emu_device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit) { int rc = 0; - uint64_t target_sector = 0; + uint64_t target_sector = sector; char target_path[0x300 + 1] = {0}; /* Perform initialization steps, if necessary. */ @@ -214,7 +214,7 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src } } else { /* Write partition data. */ - rc = devpart->writer(devpart, src, sector, num_sectors); + rc = devpart->writer(devpart, src, target_sector, num_sectors); } return rc; diff --git a/fusee/fusee-secondary/src/emu_dev.c b/fusee/fusee-secondary/src/emu_dev.c index df22a4951..d21d2a686 100644 --- a/fusee/fusee-secondary/src/emu_dev.c +++ b/fusee/fusee-secondary/src/emu_dev.c @@ -25,6 +25,7 @@ #include #include "emu_dev.h" +#include "utils.h" static int emudev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); static int emudev_close(struct _reent *r, void *fd); diff --git a/fusee/fusee-secondary/src/emummc_cfg.h b/fusee/fusee-secondary/src/emummc_cfg.h new file mode 100644 index 000000000..cc022845b --- /dev/null +++ b/fusee/fusee-secondary/src/emummc_cfg.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EXOSPHERE_EMUMMC_CONFIG_H +#define EXOSPHERE_EMUMMC_CONFIG_H + +#include +#include + +/* "EFS0" */ +#define MAGIC_EMUMMC_CONFIG (0x30534645) + +#define EMUMMC_FILE_PATH_MAX (0x80) + +typedef enum { + EMUMMC_TYPE_NONE = 0, + EMUMMC_TYPE_PARTITION = 1, + EMUMMC_TYPE_FILES = 2, +} emummc_type_t; + +typedef enum { + EMUMMC_MMC_NAND = 0, + EMUMMC_MMC_SD = 1, + EMUMMC_MMC_GC = 2, +} emummc_mmc_t; + +typedef enum { + FS_VER_1_0_0 = 0, + + FS_VER_2_0_0, + FS_VER_2_0_0_EXFAT, + + FS_VER_2_1_0, + FS_VER_2_1_0_EXFAT, + + FS_VER_3_0_0, + FS_VER_3_0_0_EXFAT, + + FS_VER_3_0_1, + FS_VER_3_0_1_EXFAT, + + FS_VER_4_0_0, + FS_VER_4_0_0_EXFAT, + + FS_VER_4_1_0, + FS_VER_4_1_0_EXFAT, + + FS_VER_5_0_0, + FS_VER_5_0_0_EXFAT, + + FS_VER_5_1_0, + FS_VER_5_1_0_EXFAT, + + FS_VER_6_0_0, + FS_VER_6_0_0_EXFAT, + + FS_VER_7_0_0, + FS_VER_7_0_0_EXFAT, + + FS_VER_8_0_0, + FS_VER_8_0_0_EXFAT, + + FS_VER_MAX, +} emummc_fs_ver_t; + + +typedef struct { + uint32_t magic; + uint32_t type; + uint32_t id; + uint32_t fs_version; +} emummc_base_config_t; + +typedef struct { + uint64_t start_sector; +} emummc_partition_config_t; + +typedef struct { + char path[EMUMMC_FILE_PATH_MAX]; +} emummc_file_config_t; + +typedef struct { + emummc_base_config_t base_cfg; + union { + emummc_partition_config_t partition_cfg; + emummc_file_config_t file_cfg; + }; + //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!"); + +#endif diff --git a/fusee/fusee-secondary/src/exocfg.h b/fusee/fusee-secondary/src/exocfg.h index 97e505cd7..dc00de45e 100644 --- a/fusee/fusee-secondary/src/exocfg.h +++ b/fusee/fusee-secondary/src/exocfg.h @@ -19,6 +19,7 @@ #include #include +#include "emummc_cfg.h" /* This serves to set configuration for *exosphere itself*, separate from the SecMon Exosphere mimics. */ @@ -35,11 +36,11 @@ typedef struct { uint32_t magic; uint32_t target_firmware; uint32_t flags; - uint32_t reserved; - uint64_t emunand_config; + uint32_t reserved[5]; + exo_emummc_config_t emummc_cfg; } exosphere_config_t; -_Static_assert(sizeof(exosphere_config_t) == 0x18, "exosphere config definition"); +_Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t), "exosphere config definition"); #define MAILBOX_EXOSPHERE_CONFIGURATION ((volatile exosphere_config_t *)(0x8000F000ull)) diff --git a/fusee/fusee-secondary/src/ips.c b/fusee/fusee-secondary/src/ips.c index a4f791bc0..d94b31e5e 100644 --- a/fusee/fusee-secondary/src/ips.c +++ b/fusee/fusee-secondary/src/ips.c @@ -21,6 +21,7 @@ #include #include #include "utils.h" +#include "exocfg.h" #include "se.h" #include "lib/log.h" #include "ips.h" @@ -343,7 +344,7 @@ static void kip1_blz_uncompress(void *hdr_end) { } } -static kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) { +kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) { kip1_header_t new_header = *kip; for (unsigned int i = 0; i < 3; i++) { new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size; @@ -372,10 +373,60 @@ static kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) { return (kip1_header_t *)new_kip; } -kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size) { +static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = { + "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe", /* FS_VER_1_0_0 */ + + "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28", /* FS_VER_2_0_0 */ + "\xe7\x66\x92\xdf\xaa\x04\x20\xe9", /* FS_VER_2_0_0_EXFAT */ + + "\x0d\x70\x05\x62\x7b\x07\x76\x7c", /* FS_VER_2_1_0 */ + "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8", /* FS_VER_2_1_0_EXFAT */ + + "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b", /* FS_VER_3_0_0 */ + "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7", /* FS_VER_3_0_0_EXFAT */ + + "\x57\x39\x7c\x06\x3f\x10\xb6\x31", /* FS_VER_3_0_1 */ + "\x07\x30\x99\xd7\xc6\xad\x7d\x89", /* FS_VER_3_0_1_EXFAT */ + + "\x06\xe9\x07\x19\x59\x5a\x01\x0c", /* FS_VER_4_0_0 */ + "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9", /* FS_VER_4_0_0_EXFAT */ + + "\x80\x96\xaf\x7c\x6a\x35\xaa\x82", /* FS_VER_4_1_0 */ + "\x02\xd5\xab\xaa\xfd\x20\xc8\xb0", /* FS_VER_4_1_0_EXFAT */ + + "\xa6\xf2\x7a\xd9\xac\x7c\x73\xad", /* FS_VER_5_0_0 */ + "\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5", /* FS_VER_5_0_0_EXFAT */ + + "\x76\xf8\x74\x02\xc9\x38\x7c\x0f", /* FS_VER_5_1_0 */ + "\x10\xb2\xd8\x16\x05\x48\x85\x99", /* FS_VER_5_1_0_EXFAT */ + + "\x3a\x57\x4d\x43\x61\x86\x19\x1d", /* FS_VER_6_0_0 */ + "\x33\x05\x53\xf6\xb5\xfb\x55\xc4", /* FS_VER_6_0_0_EXFAT */ + + "\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77", /* FS_VER_7_0_0 */ + "\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E", /* FS_VER_7_0_0_EXFAT */ + + "\xB2\xF5\x17\x6B\x35\x48\x36\x4D", /* FS_VER_8_0_0 */ + "\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", /* FS_VER_8_0_0_EXFAT */ +}; + +kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) { uint8_t hash[0x20]; se_calculate_sha256(hash, kip, kip_size); + if (kip->title_id == FS_TITLE_ID) { + bool found = false; + for (size_t i = 0; i < FS_VER_MAX; i++) { + if (memcmp(hash, g_fs_hashes[i], 0x8) == 0) { + found = true; + *out_fs_ver = (emummc_fs_ver_t)i; + } + } + if (!found) { + fatal_error("[NXBOOT]: Failed to identify FS version..."); + } + } + if (!has_needed_default_kip_patches(kip->title_id, hash, sizeof(hash))) { fatal_error("[NXBOOT]: Missing default patch for KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id); } diff --git a/fusee/fusee-secondary/src/ips.h b/fusee/fusee-secondary/src/ips.h index fbd95e970..5b718fcef 100644 --- a/fusee/fusee-secondary/src/ips.h +++ b/fusee/fusee-secondary/src/ips.h @@ -17,12 +17,16 @@ #ifndef FUSEE_IPS_H #define FUSEE_IPS_H +#include #include "utils.h" #include "kip.h" -#include +#include "exocfg.h" + +#define FS_TITLE_ID 0x0100000000000000ull void apply_kernel_ips_patches(void *kernel, size_t kernel_size); -kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size); +kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver); +kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size); void kip_patches_set_enable_nogc(void); diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index a88b18fcd..376d0f5c9 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -109,8 +109,8 @@ static int emummc_ini_handler(void *user, const char *section, const char *name, emummc_cfg->enabled = (tmp != 0); } if (strcmp(name, EMUMMC_SECTOR_KEY) == 0) { - uint64_t sector = 0; - sscanf(value, "%llu", §or); + uintptr_t sector = 0; + sscanf(value, "%x", §or); emummc_cfg->sector = sector; } else if (strcmp(name, EMUMMC_PATH_KEY) == 0) { strncpy(emummc_cfg->path, value, sizeof(emummc_cfg->path) - 1); @@ -208,7 +208,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) { } } -static bool nxboot_configure_emummc() { +static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { emummc_config_t emummc_cfg = {.enabled = false, .sector = -1, .path = ""}; /* Load emummc settings from BCT.ini file. */ @@ -216,13 +216,25 @@ static bool nxboot_configure_emummc() { fatal_error("[NXBOOT] Failed to parse BCT.ini!\n"); } + 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.fs_version = FS_VER_1_0_0; /* Will be filled out later. */ + if (emummc_cfg.enabled) { if (emummc_cfg.sector >= 0) { + exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION; + exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector; + /* Mount emulated NAND from SD card partition. */ if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) { fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n"); } } 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); + int num_parts = 0; uint64_t part_limit = 0; char emummc_boot0_path[0x300 + 1] = {0}; @@ -267,11 +279,13 @@ static bool nxboot_configure_emummc() { return emummc_cfg.enabled; } -static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int keygen_type) { +static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int keygen_type, exo_emummc_config_t *exo_emummc_cfg) { exosphere_config_t exo_cfg = {0}; exo_cfg.magic = MAGIC_EXOSPHERE_CONFIG; exo_cfg.target_firmware = target_firmware; + memcpy(&exo_cfg.emummc_cfg, exo_emummc_cfg, sizeof(*exo_emummc_cfg)); + if (keygen_type) { exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT | EXOSPHERE_FLAG_PERFORM_620_KEYGEN; } else { @@ -421,15 +435,35 @@ uint32_t nxboot_main(void) { void *warmboot_memaddr; void *package1loader; size_t package1loader_size; + void *emummc_kip; + size_t emummc_kip_size; uint32_t available_revision; FILE *boot0, *pk2file; void *exosphere_memaddr; + exo_emummc_config_t exo_emummc_cfg; /* Configure emummc or mount the real NAND. */ - if (!nxboot_configure_emummc()) { + if (!nxboot_configure_emummc(&exo_emummc_cfg)) { + emummc_kip = NULL; + emummc_kip_size = 0; if (nxfs_mount_emmc() < 0) { fatal_error("[NXBOOT] Failed to mount eMMC!\n"); } + } else { + emummc_kip_size = get_file_size("atmosphere/emummc.kip"); + if (emummc_kip_size == 0) { + fatal_error("[NXBOOT] Could not read emummc kip!\n"); + } + + /* Allocate memory for the TSEC firmware. */ + emummc_kip = memalign(0x100, emummc_kip_size); + + if (emummc_kip == NULL) { + fatal_error("[NXBOOT] Out of memory!\n"); + } + if (read_from_file(emummc_kip, emummc_kip_size, "atmosphere/emummc.kip") != emummc_kip_size) { + fatal_error("[NXBOOT] Could not read the emummc kip!\n"); + } } /* Allocate memory for reading Package2. */ @@ -562,7 +596,7 @@ uint32_t nxboot_main(void) { } /* Setup boot configuration for Exosphère. */ - nxboot_configure_exosphere(target_firmware, keygen_type); + nxboot_configure_exosphere(target_firmware, keygen_type, &exo_emummc_cfg); /* Initialize Boot Reason on older firmware versions. */ if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { @@ -644,7 +678,10 @@ uint32_t nxboot_main(void) { print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Configured Stratosphere...\n"); /* Patch package2, adding Thermosphère + custom KIPs. */ - package2_rebuild_and_copy(package2, MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware); + package2_rebuild_and_copy(package2, MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware, emummc_kip, emummc_kip_size); + + /* Set detected FS version. */ + MAILBOX_EXOSPHERE_CONFIGURATION->emummc_cfg.base_cfg.fs_version = stratosphere_get_fs_version(); print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Reading Exosphère...\n"); diff --git a/fusee/fusee-secondary/src/nxfs.c b/fusee/fusee-secondary/src/nxfs.c index 301ee9f7a..dbe31f749 100644 --- a/fusee/fusee-secondary/src/nxfs.c +++ b/fusee/fusee-secondary/src/nxfs.c @@ -36,6 +36,8 @@ static bool g_fsdev_ready = false; static bool g_rawdev_ready = false; static bool g_emudev_ready = false; +static bool g_is_emummc = false; + static sdmmc_t g_sd_sdmmc = {0}; static sdmmc_t g_emmc_sdmmc = {0}; @@ -106,6 +108,9 @@ static void mmc_partition_finalize(device_partition_t *devpart) { /* Finalize hardware. */ if (mmcpart->device == &g_sd_device) { + if (g_is_emummc) { + return; + } if (g_sd_device_initialized) { sdmmc_device_finish(&g_sd_device); g_sd_device_initialized = false; @@ -189,7 +194,7 @@ static int emummc_partition_read(device_partition_t *devpart, void *dst, uint64_ rc = (fread(dst, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1; fclose(emummc_file); return rc; - } else { + } else { /* Read partition data directly from the SD card device. */ return sdmmc_device_read(&g_sd_device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO; } @@ -571,7 +576,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { /* Failed to register boot0 device. */ if (rc == -1) { - return -1; + return -2; } /* Setup an emulation template for boot1. */ @@ -585,7 +590,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { /* Failed to mount boot1. */ if (rc == -1) { - return -1; + return -3; } /* Don't register emulated boot1 for now. */ @@ -595,13 +600,13 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { model.start_sector = emummc_start_sector + (0x400000 * 2 / model.sector_size); model.num_sectors = (256ull << 30) / model.sector_size; model.emu_use_file = false; - + /* Mount emulated raw NAND device. */ rc = emudev_mount_device("rawnand", &model, NULL); /* Failed to mount raw NAND. */ if (rc == -1) { - return -1; + return -4; } /* Register emulated raw NAND device. */ @@ -609,7 +614,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { /* Failed to register raw NAND device. */ if (rc == -1) { - return -1; + return -5; } /* Open emulated raw NAND device. */ @@ -617,7 +622,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { /* Failed to open emulated raw NAND device. */ if (rawnand == NULL) { - return -1; + return -6; } /* Iterate the GPT and mount each emulated raw NAND partition. */ @@ -629,6 +634,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { /* All emulated devices are ready. */ if (rc == 0) { g_emudev_ready = true; + g_is_emummc = true; } return rc; @@ -772,6 +778,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part /* All emulated devices are ready. */ if (rc == 0) { g_emudev_ready = true; + g_is_emummc = true; } return rc; diff --git a/fusee/fusee-secondary/src/package2.c b/fusee/fusee-secondary/src/package2.c index ee988cf25..de7af5b70 100644 --- a/fusee/fusee-secondary/src/package2.c +++ b/fusee/fusee-secondary/src/package2.c @@ -36,7 +36,7 @@ static void package2_decrypt(package2_header_t *package2); static size_t package2_get_src_section(void **section, package2_header_t *package2, unsigned int id); static size_t package2_get_thermosphere(void **thermosphere); -static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware); +static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware, void *emummc, size_t emummc_size); static void package2_append_section(unsigned int id, package2_header_t *package2, void *data, size_t size); static void package2_fixup_header_and_section_hashes(package2_header_t *package2, size_t size); @@ -44,7 +44,7 @@ static inline size_t align_to_4(size_t s) { return ((s + 3) >> 2) << 2; } -void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware) { +void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *emummc, size_t emummc_size) { package2_header_t *rebuilt_package2; size_t rebuilt_package2_size; void *kernel; @@ -104,7 +104,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm } /* Perform any patches to the INI1, rebuilding it (This is where our built-in sysmodules will be added.) */ - rebuilt_ini1 = package2_rebuild_ini1(orig_ini1, target_firmware); + rebuilt_ini1 = package2_rebuild_ini1(orig_ini1, target_firmware, emummc, emummc_size); print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilt INI1...\n"); /* Allocate the rebuilt package2. */ @@ -317,7 +317,7 @@ static size_t package2_get_thermosphere(void **thermosphere) { return 0; } -static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware) { +static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware, void *emummc, size_t emummc_size) { /* TODO: Do we want to support loading another INI from sd:/whatever/INI1.bin? */ ini1_header_t *inis_to_merge[STRATOSPHERE_INI1_MAX] = {0}; ini1_header_t *merged; @@ -327,7 +327,7 @@ static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target inis_to_merge[STRATOSPHERE_INI1_PACKAGE2] = ini1; /* Merge all of the INI1s. */ - merged = stratosphere_merge_inis(inis_to_merge, STRATOSPHERE_INI1_MAX); + merged = stratosphere_merge_inis(inis_to_merge, STRATOSPHERE_INI1_MAX, emummc, emummc_size); /* Free temporary buffer. */ stratosphere_free_ini1(); diff --git a/fusee/fusee-secondary/src/package2.h b/fusee/fusee-secondary/src/package2.h index dd20869a7..1b3d6d492 100644 --- a/fusee/fusee-secondary/src/package2.h +++ b/fusee/fusee-secondary/src/package2.h @@ -86,6 +86,6 @@ static inline uint8_t package2_meta_get_header_version(const package2_meta_t *me return (uint8_t)((metadata->ctr_dwords[1] ^ (metadata->ctr_dwords[1] >> 16) ^ (metadata->ctr_dwords[1] >> 24)) & 0xFF); } -void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware); +void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *emummc, size_t emummc_size); #endif diff --git a/fusee/fusee-secondary/src/sdmmc/sdmmc.c b/fusee/fusee-secondary/src/sdmmc/sdmmc.c index f5ed83e3c..2c8811210 100644 --- a/fusee/fusee-secondary/src/sdmmc/sdmmc.c +++ b/fusee/fusee-secondary/src/sdmmc/sdmmc.c @@ -494,7 +494,7 @@ static int sdmmc_sd_send_op_cond(sdmmc_device_t *device, bool is_sd_ver2, bool i device->is_block_sdhc = true; /* We asked for low voltage support and the card accepted. */ - if (is_uhs_en && (resp & SD_ROCR_S18A)) + if (false && is_uhs_en && (resp & SD_ROCR_S18A)) { /* Voltage switching is only valid for SDMMC1. */ if (device->sdmmc->controller == SDMMC_1) diff --git a/fusee/fusee-secondary/src/stratosphere.c b/fusee/fusee-secondary/src/stratosphere.c index 954cc2b7d..79fa1ef73 100644 --- a/fusee/fusee-secondary/src/stratosphere.c +++ b/fusee/fusee-secondary/src/stratosphere.c @@ -51,6 +51,12 @@ static bool g_stratosphere_boot_enabled = true; extern const uint8_t loader_kip[], pm_kip[], sm_kip[], spl_kip[], boot_kip[], ams_mitm_kip[]; extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, spl_kip_size, boot_kip_size, ams_mitm_kip_size; +static emummc_fs_ver_t g_fs_ver = FS_VER_1_0_0; + +emummc_fs_ver_t stratosphere_get_fs_version(void) { + return g_fs_ver; +} + /* GCC doesn't consider the size as const... we have to write it ourselves. */ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) { @@ -152,8 +158,6 @@ void stratosphere_free_ini1(void) { } } - - static void try_add_sd_kip(ini1_header_t *ini1, const char *kip_path) { size_t file_size = get_file_size(kip_path); @@ -180,6 +184,60 @@ static void try_add_sd_kip(ini1_header_t *ini1, const char *kip_path) { ini1->num_processes++; } +static kip1_header_t *inject_emummc_kip(kip1_header_t *fs_kip, kip1_header_t *emummc_kip) { + /* Ensure KIPs are uncompressed. */ + size_t fs_kip_size, emummc_kip_size; + fs_kip = kip1_uncompress(fs_kip, &fs_kip_size); + emummc_kip = kip1_uncompress(emummc_kip, &emummc_kip_size); + + /* Allocate kip. */ + kip1_header_t *injected_kip = calloc(1, fs_kip_size + emummc_kip_size); + if (injected_kip == NULL) { + fatal_error("Failed to allocate memory for emummc kip injection!"); + } + memcpy(injected_kip, fs_kip, sizeof(*fs_kip)); + + const size_t fs_contents_size = kip1_get_size_from_header(fs_kip) - sizeof(kip1_header_t); + + const size_t emummc_data_size = emummc_kip->section_headers[3].out_offset + emummc_kip->section_headers[3].out_size; + if (emummc_data_size & 0xFFF) { + fatal_error("Invalid emummc kip!"); + } + + /* Copy over capabilities. */ + memcpy(injected_kip->capabilities, emummc_kip->capabilities, sizeof(emummc_kip->capabilities)); + + /* Add extra cap for 1.0.0 */ + if (stratosphere_get_fs_version() == FS_VER_1_0_0) { + for (size_t i = 0; i < 0x20; i++) { + if (injected_kip->capabilities[i] = 0xFFFFFFFF) { + /* Map PMC registers in. */ + injected_kip->capabilities[i] = 0x07000E7F; + break; + } + } + } + + /* Update sections. */ + injected_kip->section_headers[0].out_size += emummc_data_size; + injected_kip->section_headers[0].compressed_size += emummc_data_size; + for (size_t i = 1; i < 4; i++) { + injected_kip->section_headers[i].out_offset += emummc_data_size; + } + + /* Copy data. */ + { + size_t ofs = 0; + for (size_t i = 0; i < 3; i++) { + memcpy(injected_kip->data + emummc_kip->section_headers[i].out_offset, emummc_kip->data + ofs, emummc_kip->section_headers[i].compressed_size); + ofs += emummc_kip->section_headers[i].compressed_size; + } + } + memcpy(injected_kip->data + emummc_data_size, fs_kip->data, fs_contents_size); + + return injected_kip; +} + ini1_header_t *stratosphere_get_sd_files_ini1(void) { if (g_sd_files_ini1 != NULL) { return g_sd_files_ini1; @@ -246,7 +304,7 @@ ini1_header_t *stratosphere_get_sd_files_ini1(void) { } /* Merges some number of INI1s into a single INI1. It's assumed that the INIs are in order of preference. */ -ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { +ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis, void *emummc, size_t emummc_size) { uint32_t total_num_processes = 0; /* Validate all ini headers. */ @@ -305,11 +363,17 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { fatal_error("Not enough space for all the KIP1s!\n"); } - kip1_header_t *patched_kip = apply_kip_ips_patches(current_kip, current_kip_size); + kip1_header_t *patched_kip = apply_kip_ips_patches(current_kip, current_kip_size, &g_fs_ver); + + if (current_kip->title_id == FS_TITLE_ID && emummc != NULL) { + patched_kip = inject_emummc_kip(patched_kip != NULL ? patched_kip : current_kip, (kip1_header_t *)emummc); + dump_to_file(patched_kip, kip1_get_size_from_header(patched_kip), "DEBUG_EMUMMC.kip"); + } + if (patched_kip != NULL) { size_t patched_kip_size = kip1_get_size_from_header(patched_kip); if (patched_kip_size > remaining_size) { - fatal_error("Not enough space for all the KIP1s!\n"); + fatal_error("Not enough space for all the KIP1s! %08x %08x\n", remaining_size, patched_kip_size); } memcpy(current_dst_kip, patched_kip, patched_kip_size); remaining_size -= patched_kip_size; @@ -326,6 +390,9 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { } } merged->size = sizeof(ini1_header_t) + (uint32_t)(current_dst_kip - merged->kip_data); + if (merged->size & 3) { + merged->size = (merged->size + 3) & ~3; + } return merged; } diff --git a/fusee/fusee-secondary/src/stratosphere.h b/fusee/fusee-secondary/src/stratosphere.h index 64d1d5a89..7e7be848f 100644 --- a/fusee/fusee-secondary/src/stratosphere.h +++ b/fusee/fusee-secondary/src/stratosphere.h @@ -19,6 +19,7 @@ #include "utils.h" #include "kip.h" +#include "exocfg.h" #define STRATOSPHERE_INI1_SDFILES 0x0 #define STRATOSPHERE_INI1_EMBEDDED 0x1 @@ -29,7 +30,9 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware); ini1_header_t *stratosphere_get_sd_files_ini1(void); void stratosphere_free_ini1(void); -ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, unsigned int num_inis); +emummc_fs_ver_t stratosphere_get_fs_version(void); + +ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, unsigned int num_inis, void *emummc, size_t emummc_size); typedef struct { bool has_nogc_config;