From 0674c4b64f3ea6b54cfaff5257a64c5ccd9b51f0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 11 Apr 2018 21:56:11 -0600 Subject: [PATCH] Stratosphere: Add support for custom KIPs/INI in Fusee --- fusee/fusee-secondary/src/kip.h | 2 +- fusee/fusee-secondary/src/package2.c | 19 +++-- fusee/fusee-secondary/src/stratosphere.c | 101 +++++++++++++++++++++++ fusee/fusee-secondary/src/stratosphere.h | 15 ++++ 4 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 fusee/fusee-secondary/src/stratosphere.c create mode 100644 fusee/fusee-secondary/src/stratosphere.h diff --git a/fusee/fusee-secondary/src/kip.h b/fusee/fusee-secondary/src/kip.h index f1bd8b7fa..b0e9a5711 100644 --- a/fusee/fusee-secondary/src/kip.h +++ b/fusee/fusee-secondary/src/kip.h @@ -14,7 +14,7 @@ typedef struct { uint32_t size; uint32_t num_processes; uint32_t _0xC; - char kip_data[]; + unsigned char kip_data[]; } ini1_header_t; typedef struct { diff --git a/fusee/fusee-secondary/src/package2.c b/fusee/fusee-secondary/src/package2.c index 831a3833d..1c3092711 100644 --- a/fusee/fusee-secondary/src/package2.c +++ b/fusee/fusee-secondary/src/package2.c @@ -1,5 +1,6 @@ #include "utils.h" #include "masterkey.h" +#include "stratosphere.h" #include "package2.h" #include "kip.h" #include "se.h" @@ -9,7 +10,6 @@ /* This *greatly* simplifies logic. */ unsigned char g_patched_package2[PACKAGE2_SIZE_MAX]; unsigned char g_package2_sections[PACKAGE2_SECTION_MAX][PACKAGE2_SIZE_MAX]; -unsigned char g_package2_work_buffer[PACKAGE2_SIZE_MAX]; package2_header_t *g_patched_package2_header = (package2_header_t *)g_patched_package2; @@ -36,7 +36,7 @@ void package2_patch(void *package2_address) { package2_fixup_header_and_section_hashes(); /* Relocate Package2. */ - memcpy(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, g_patched_package2, PACKAGE2_SIZE_MAX); + memcpy(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, g_patched_package2, sizeof(g_patched_package2)); } static void package2_crypt_ctr(unsigned int master_key_rev, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) { @@ -211,14 +211,15 @@ void package2_patch_kernel(void) { /* TODO: What kind of patching do we want to try to do here? */ } + void package2_patch_ini1(void) { - ini1_header_t *ini_header = (ini1_header_t *)g_package2_sections[PACKAGE2_SECTION_INI1]; - if (ini_header->magic != MAGIC_INI1) { - printk("Error: INI1 section appears to not contain an INI1!\n"); - generic_panic(); - } - - /* TODO */ + /* TODO: Do we want to support loading another INI from sd:/whatever/INI1.bin? */ + ini1_header_t *inis_to_merge[STRATOSPHERE_INI1_MAX] = {0}; + inis_to_merge[STRATOSPHERE_INI1_EMBEDDED] = stratosphere_get_ini1(); + inis_to_merge[STRATOSPHERE_INI1_PACKAGE2] = (ini1_header_t *)g_package2_sections[PACKAGE2_SECTION_INI1]; + + /* Merge all of the INI1s. */ + stratosphere_merge_inis(g_package2_sections[PACKAGE2_SECTION_INI1], inis_to_merge, STRATOSPHERE_INI1_MAX); } void package2_fixup_header_and_section_hashes(void) { diff --git a/fusee/fusee-secondary/src/stratosphere.c b/fusee/fusee-secondary/src/stratosphere.c new file mode 100644 index 000000000..cb0544241 --- /dev/null +++ b/fusee/fusee-secondary/src/stratosphere.c @@ -0,0 +1,101 @@ +#include "utils.h" +#include "package2.h" +#include "stratosphere.h" +#include "sd_utils.h" +#include "lib/printk.h" + +unsigned char g_stratosphere_ini1[PACKAGE2_SIZE_MAX]; +static bool g_initialized_stratosphere_ini1 = false; + +unsigned char g_ini1_buffer[PACKAGE2_SIZE_MAX]; + +ini1_header_t *stratosphere_get_ini1(void) { + ini1_header_t *ini1_header = (ini1_header_t *)g_stratosphere_ini1; + if (g_initialized_stratosphere_ini1) { + return ini1_header; + } + ini1_header->magic = MAGIC_INI1; + ini1_header->size = sizeof(ini1_header_t); + ini1_header->num_processes = 0; + ini1_header->_0xC = 0; + + /* TODO: When we have processes, copy them into ini1_header->kip_data here. */ + + g_initialized_stratosphere_ini1 = true; + return ini1_header; +} + +/* Merges some number of INI1s into a single INI1. It's assumed that the INIs are in order of preference. */ +void stratosphere_merge_inis(void *dst, ini1_header_t **inis, unsigned int num_inis) { + char sd_path[0x300] = {0}; + /* Validate all ini headers. */ + for (unsigned int i = 0; i < num_inis; i++) { + if (inis[i] == NULL || inis[i]->magic != MAGIC_INI1 || inis[i]->num_processes > INI1_MAX_KIPS) { + printk("Error: INI1s[%d] section appears to not contain an INI1!\n", i); + generic_panic(); + } + } + + uint64_t process_list[INI1_MAX_KIPS] = {0}; + + memset(g_ini1_buffer, 0, sizeof(g_ini1_buffer)); + ini1_header_t *merged = (ini1_header_t *)g_ini1_buffer; + merged->magic = MAGIC_INI1; + merged->num_processes = 0; + merged->_0xC = 0; + size_t remaining_size = PACKAGE2_SIZE_MAX - sizeof(ini1_header_t); + + unsigned char *current_dst_kip = merged->kip_data; + + /* Actually merge into the inis. */ + for (unsigned int i = 0; i < num_inis; i++) { + uint64_t offset = 0; + for (unsigned int p = 0; p < inis[i]->num_processes; p++) { + kip1_header_t *current_kip = (kip1_header_t *)(inis[i]->kip_data + offset); + if (current_kip->magic != MAGIC_KIP1) { + printk("Error: INI1s[%d][%d] appears not to be a KIP1!\n", i, p); + generic_panic(); + } + + + bool already_loaded = false; + for (unsigned int j = 0; j < merged->num_processes; j++) { + if (process_list[j] == current_kip->title_id) { + already_loaded = true; + break; + } + } + if (already_loaded) { + continue; + } + + /* Try to load an override KIP from SD, if possible. */ + if (read_sd_file(current_dst_kip, remaining_size, sd_path)) { + kip1_header_t *sd_kip = (kip1_header_t *)(current_dst_kip); + if (sd_kip->magic != MAGIC_KIP1) { + printk("Error: %s is not a KIP1?\n", sd_path); + generic_panic(); + } else if (sd_kip->title_id != current_kip->title_id) { + printk("Error: %s has wrong Title ID!\n", sd_path); + generic_panic(); + } + current_dst_kip += kip1_get_size_from_header(sd_kip); + } else { + uint64_t current_kip_size = kip1_get_size_from_header(current_kip); + if (current_kip_size > remaining_size) { + printk("Error: Not enough space for all the KIP1s!\n"); + generic_panic(); + } + memcpy(current_dst_kip, current_kip, current_kip_size); + remaining_size -= current_kip_size; + current_dst_kip += current_kip_size; + } + + process_list[merged->num_processes++] = current_kip->title_id; + } + } + merged->size = sizeof(ini1_header_t) + (uint32_t)(current_dst_kip - merged->kip_data); + + /* Copy merged INI1 to destination. */ + memcpy(dst, merged, merged->size); +} \ No newline at end of file diff --git a/fusee/fusee-secondary/src/stratosphere.h b/fusee/fusee-secondary/src/stratosphere.h new file mode 100644 index 000000000..c611ac2c7 --- /dev/null +++ b/fusee/fusee-secondary/src/stratosphere.h @@ -0,0 +1,15 @@ +#ifndef FUSEE_STRATOSPHERE_H +#define FUSEE_STRATOSPHERE_H + +#include "utils.h" +#include "kip.h" + +#define STRATOSPHERE_INI1_EMBEDDED 0x0 +#define STRATOSPHERE_INI1_PACKAGE2 0x1 +#define STRATOSPHERE_INI1_MAX 0x2 + +ini1_header_t *stratosphere_get_ini1(void); + +void stratosphere_merge_inis(void *dst, ini1_header_t **inis, unsigned int num_inis); + +#endif \ No newline at end of file