fusee: add automatic emummc injection support

This commit is contained in:
Michael Scire 2019-06-14 06:37:25 -07:00
parent 4f8ab5c599
commit 8bd79e8299
14 changed files with 315 additions and 37 deletions

View file

@ -59,6 +59,7 @@ typedef struct {
emummc_partition_config_t partition_cfg; emummc_partition_config_t partition_cfg;
emummc_file_config_t file_cfg; emummc_file_config_t file_cfg;
}; };
//char emu_dir_path[EMUMMC_FILE_PATH_MAX];
} exo_emummc_config_t; } exo_emummc_config_t;
_Static_assert(sizeof(exo_emummc_config_t) == 0x90, "exo_emummc_config_t definition!"); _Static_assert(sizeof(exo_emummc_config_t) == 0x90, "exo_emummc_config_t definition!");

View file

@ -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 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; int rc = 0;
uint64_t target_sector = 0; uint64_t target_sector = sector;
char target_path[0x300 + 1] = {0}; char target_path[0x300 + 1] = {0};
/* Perform initialization steps, if necessary. */ /* 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 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; int rc = 0;
uint64_t target_sector = 0; uint64_t target_sector = sector;
char target_path[0x300 + 1] = {0}; char target_path[0x300 + 1] = {0};
/* Perform initialization steps, if necessary. */ /* Perform initialization steps, if necessary. */
@ -214,7 +214,7 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src
} }
} else { } else {
/* Write partition data. */ /* Write partition data. */
rc = devpart->writer(devpart, src, sector, num_sectors); rc = devpart->writer(devpart, src, target_sector, num_sectors);
} }
return rc; return rc;

View file

@ -25,6 +25,7 @@
#include <unistd.h> #include <unistd.h>
#include "emu_dev.h" #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_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
static int emudev_close(struct _reent *r, void *fd); static int emudev_close(struct _reent *r, void *fd);

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_EMUMMC_CONFIG_H
#define EXOSPHERE_EMUMMC_CONFIG_H
#include <stdint.h>
#include <atmosphere.h>
/* "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

View file

@ -19,6 +19,7 @@
#include <stdint.h> #include <stdint.h>
#include <atmosphere.h> #include <atmosphere.h>
#include "emummc_cfg.h"
/* This serves to set configuration for *exosphere itself*, separate from the SecMon Exosphere mimics. */ /* 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 magic;
uint32_t target_firmware; uint32_t target_firmware;
uint32_t flags; uint32_t flags;
uint32_t reserved; uint32_t reserved[5];
uint64_t emunand_config; exo_emummc_config_t emummc_cfg;
} exosphere_config_t; } 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)) #define MAILBOX_EXOSPHERE_CONFIGURATION ((volatile exosphere_config_t *)(0x8000F000ull))

View file

@ -21,6 +21,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "utils.h" #include "utils.h"
#include "exocfg.h"
#include "se.h" #include "se.h"
#include "lib/log.h" #include "lib/log.h"
#include "ips.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; kip1_header_t new_header = *kip;
for (unsigned int i = 0; i < 3; i++) { for (unsigned int i = 0; i < 3; i++) {
new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size; 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; 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]; uint8_t hash[0x20];
se_calculate_sha256(hash, kip, kip_size); 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))) { 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); fatal_error("[NXBOOT]: Missing default patch for KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id);
} }

View file

@ -17,12 +17,16 @@
#ifndef FUSEE_IPS_H #ifndef FUSEE_IPS_H
#define FUSEE_IPS_H #define FUSEE_IPS_H
#include <stdint.h>
#include "utils.h" #include "utils.h"
#include "kip.h" #include "kip.h"
#include <stdint.h> #include "exocfg.h"
#define FS_TITLE_ID 0x0100000000000000ull
void apply_kernel_ips_patches(void *kernel, size_t kernel_size); 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); void kip_patches_set_enable_nogc(void);

View file

@ -109,8 +109,8 @@ static int emummc_ini_handler(void *user, const char *section, const char *name,
emummc_cfg->enabled = (tmp != 0); emummc_cfg->enabled = (tmp != 0);
} }
if (strcmp(name, EMUMMC_SECTOR_KEY) == 0) { if (strcmp(name, EMUMMC_SECTOR_KEY) == 0) {
uint64_t sector = 0; uintptr_t sector = 0;
sscanf(value, "%llu", &sector); sscanf(value, "%x", &sector);
emummc_cfg->sector = sector; emummc_cfg->sector = sector;
} else if (strcmp(name, EMUMMC_PATH_KEY) == 0) { } else if (strcmp(name, EMUMMC_PATH_KEY) == 0) {
strncpy(emummc_cfg->path, value, sizeof(emummc_cfg->path) - 1); 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 = ""}; emummc_config_t emummc_cfg = {.enabled = false, .sector = -1, .path = ""};
/* Load emummc settings from BCT.ini file. */ /* 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"); 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.enabled) {
if (emummc_cfg.sector >= 0) { 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. */ /* Mount emulated NAND from SD card partition. */
if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) { if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) {
fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n"); fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n");
} }
} else if (is_valid_folder(emummc_cfg.path)) { } 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; int num_parts = 0;
uint64_t part_limit = 0; uint64_t part_limit = 0;
char emummc_boot0_path[0x300 + 1] = {0}; char emummc_boot0_path[0x300 + 1] = {0};
@ -267,11 +279,13 @@ static bool nxboot_configure_emummc() {
return emummc_cfg.enabled; 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}; exosphere_config_t exo_cfg = {0};
exo_cfg.magic = MAGIC_EXOSPHERE_CONFIG; exo_cfg.magic = MAGIC_EXOSPHERE_CONFIG;
exo_cfg.target_firmware = target_firmware; exo_cfg.target_firmware = target_firmware;
memcpy(&exo_cfg.emummc_cfg, exo_emummc_cfg, sizeof(*exo_emummc_cfg));
if (keygen_type) { if (keygen_type) {
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT | EXOSPHERE_FLAG_PERFORM_620_KEYGEN; exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT | EXOSPHERE_FLAG_PERFORM_620_KEYGEN;
} else { } else {
@ -421,15 +435,35 @@ uint32_t nxboot_main(void) {
void *warmboot_memaddr; void *warmboot_memaddr;
void *package1loader; void *package1loader;
size_t package1loader_size; size_t package1loader_size;
void *emummc_kip;
size_t emummc_kip_size;
uint32_t available_revision; uint32_t available_revision;
FILE *boot0, *pk2file; FILE *boot0, *pk2file;
void *exosphere_memaddr; void *exosphere_memaddr;
exo_emummc_config_t exo_emummc_cfg;
/* Configure emummc or mount the real NAND. */ /* 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) { if (nxfs_mount_emmc() < 0) {
fatal_error("[NXBOOT] Failed to mount eMMC!\n"); 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. */ /* Allocate memory for reading Package2. */
@ -562,7 +596,7 @@ uint32_t nxboot_main(void) {
} }
/* Setup boot configuration for Exosphère. */ /* 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. */ /* Initialize Boot Reason on older firmware versions. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { 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"); print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Configured Stratosphere...\n");
/* Patch package2, adding Thermosphère + custom KIPs. */ /* 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"); print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Reading Exosphère...\n");

View file

@ -36,6 +36,8 @@ static bool g_fsdev_ready = false;
static bool g_rawdev_ready = false; static bool g_rawdev_ready = false;
static bool g_emudev_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_sd_sdmmc = {0};
static sdmmc_t g_emmc_sdmmc = {0}; static sdmmc_t g_emmc_sdmmc = {0};
@ -106,6 +108,9 @@ static void mmc_partition_finalize(device_partition_t *devpart) {
/* Finalize hardware. */ /* Finalize hardware. */
if (mmcpart->device == &g_sd_device) { if (mmcpart->device == &g_sd_device) {
if (g_is_emummc) {
return;
}
if (g_sd_device_initialized) { if (g_sd_device_initialized) {
sdmmc_device_finish(&g_sd_device); sdmmc_device_finish(&g_sd_device);
g_sd_device_initialized = false; g_sd_device_initialized = false;
@ -571,7 +576,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
/* Failed to register boot0 device. */ /* Failed to register boot0 device. */
if (rc == -1) { if (rc == -1) {
return -1; return -2;
} }
/* Setup an emulation template for boot1. */ /* Setup an emulation template for boot1. */
@ -585,7 +590,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
/* Failed to mount boot1. */ /* Failed to mount boot1. */
if (rc == -1) { if (rc == -1) {
return -1; return -3;
} }
/* Don't register emulated boot1 for now. */ /* Don't register emulated boot1 for now. */
@ -601,7 +606,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
/* Failed to mount raw NAND. */ /* Failed to mount raw NAND. */
if (rc == -1) { if (rc == -1) {
return -1; return -4;
} }
/* Register emulated raw NAND device. */ /* 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. */ /* Failed to register raw NAND device. */
if (rc == -1) { if (rc == -1) {
return -1; return -5;
} }
/* Open emulated raw NAND device. */ /* 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. */ /* Failed to open emulated raw NAND device. */
if (rawnand == NULL) { if (rawnand == NULL) {
return -1; return -6;
} }
/* Iterate the GPT and mount each emulated raw NAND partition. */ /* 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. */ /* All emulated devices are ready. */
if (rc == 0) { if (rc == 0) {
g_emudev_ready = true; g_emudev_ready = true;
g_is_emummc = true;
} }
return rc; 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. */ /* All emulated devices are ready. */
if (rc == 0) { if (rc == 0) {
g_emudev_ready = true; g_emudev_ready = true;
g_is_emummc = true;
} }
return rc; return rc;

View file

@ -36,7 +36,7 @@
static void package2_decrypt(package2_header_t *package2); 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_src_section(void **section, package2_header_t *package2, unsigned int id);
static size_t package2_get_thermosphere(void **thermosphere); 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_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); 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; 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; package2_header_t *rebuilt_package2;
size_t rebuilt_package2_size; size_t rebuilt_package2_size;
void *kernel; 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.) */ /* 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"); print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilt INI1...\n");
/* Allocate the rebuilt package2. */ /* Allocate the rebuilt package2. */
@ -317,7 +317,7 @@ static size_t package2_get_thermosphere(void **thermosphere) {
return 0; 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? */ /* 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 *inis_to_merge[STRATOSPHERE_INI1_MAX] = {0};
ini1_header_t *merged; 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; inis_to_merge[STRATOSPHERE_INI1_PACKAGE2] = ini1;
/* Merge all of the INI1s. */ /* 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. */ /* Free temporary buffer. */
stratosphere_free_ini1(); stratosphere_free_ini1();

View file

@ -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); 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 #endif

View file

@ -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; device->is_block_sdhc = true;
/* We asked for low voltage support and the card accepted. */ /* 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. */ /* Voltage switching is only valid for SDMMC1. */
if (device->sdmmc->controller == SDMMC_1) if (device->sdmmc->controller == SDMMC_1)

View file

@ -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 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; 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. */ /* GCC doesn't consider the size as const... we have to write it ourselves. */
ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) { 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) { static void try_add_sd_kip(ini1_header_t *ini1, const char *kip_path) {
size_t file_size = get_file_size(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++; 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) { ini1_header_t *stratosphere_get_sd_files_ini1(void) {
if (g_sd_files_ini1 != NULL) { if (g_sd_files_ini1 != NULL) {
return g_sd_files_ini1; 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. */ /* 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; uint32_t total_num_processes = 0;
/* Validate all ini headers. */ /* 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"); 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) { if (patched_kip != NULL) {
size_t patched_kip_size = kip1_get_size_from_header(patched_kip); size_t patched_kip_size = kip1_get_size_from_header(patched_kip);
if (patched_kip_size > remaining_size) { 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); memcpy(current_dst_kip, patched_kip, patched_kip_size);
remaining_size -= 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); 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; return merged;
} }

View file

@ -19,6 +19,7 @@
#include "utils.h" #include "utils.h"
#include "kip.h" #include "kip.h"
#include "exocfg.h"
#define STRATOSPHERE_INI1_SDFILES 0x0 #define STRATOSPHERE_INI1_SDFILES 0x0
#define STRATOSPHERE_INI1_EMBEDDED 0x1 #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); ini1_header_t *stratosphere_get_sd_files_ini1(void);
void stratosphere_free_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 { typedef struct {
bool has_nogc_config; bool has_nogc_config;