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_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!");

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 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;

View file

@ -25,6 +25,7 @@
#include <unistd.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_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 <atmosphere.h>
#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))

View file

@ -21,6 +21,7 @@
#include <string.h>
#include <ctype.h>
#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);
}

View file

@ -17,12 +17,16 @@
#ifndef FUSEE_IPS_H
#define FUSEE_IPS_H
#include <stdint.h>
#include "utils.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);
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);

View file

@ -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", &sector);
uintptr_t sector = 0;
sscanf(value, "%x", &sector);
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");

View file

@ -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;

View file

@ -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();

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);
}
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

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;
/* 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)

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 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;
}

View file

@ -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;