From bfa5847e4852e1cb594110d4776345e9655fdcd0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 16 Oct 2018 15:08:06 -0700 Subject: [PATCH] fusee: Greatly simplify and improve KIP loading --- fusee/fusee-secondary/src/package2.c | 1 + fusee/fusee-secondary/src/stratosphere.c | 141 ++++++++++++++++++----- fusee/fusee-secondary/src/stratosphere.h | 8 +- 3 files changed, 116 insertions(+), 34 deletions(-) diff --git a/fusee/fusee-secondary/src/package2.c b/fusee/fusee-secondary/src/package2.c index 50eada5f8..f5ac7041d 100644 --- a/fusee/fusee-secondary/src/package2.c +++ b/fusee/fusee-secondary/src/package2.c @@ -283,6 +283,7 @@ static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target ini1_header_t *inis_to_merge[STRATOSPHERE_INI1_MAX] = {0}; ini1_header_t *merged; + inis_to_merge[STRATOSPHERE_INI1_SDFILES] = stratosphere_get_sd_files_ini1(); inis_to_merge[STRATOSPHERE_INI1_EMBEDDED] = stratosphere_get_ini1(target_firmware); inis_to_merge[STRATOSPHERE_INI1_PACKAGE2] = ini1; diff --git a/fusee/fusee-secondary/src/stratosphere.c b/fusee/fusee-secondary/src/stratosphere.c index 2223a2247..a90a966c8 100644 --- a/fusee/fusee-secondary/src/stratosphere.c +++ b/fusee/fusee-secondary/src/stratosphere.c @@ -17,11 +17,13 @@ #include #include #include +#include #include "exocfg.h" #include "utils.h" #include "package2.h" #include "stratosphere.h" #include "fs_utils.h" +#include "lib/log.h" #define u8 uint8_t #define u32 uint32_t @@ -34,6 +36,7 @@ #undef u32 static ini1_header_t *g_stratosphere_ini1 = NULL; +static ini1_header_t *g_sd_files_ini1 = NULL; static bool g_stratosphere_loader_enabled = true; static bool g_stratosphere_sm_enabled = true; @@ -137,13 +140,111 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) { } void stratosphere_free_ini1(void) { - free(g_stratosphere_ini1); - g_stratosphere_ini1 = NULL; + if (g_stratosphere_ini1 != NULL) { + free(g_stratosphere_ini1); + g_stratosphere_ini1 = NULL; + } + if (g_sd_files_ini1 != NULL) { + free(g_sd_files_ini1); + g_sd_files_ini1 = NULL; + } +} + + + +static void try_add_sd_kip(ini1_header_t *ini1, const char *kip_path) { + size_t file_size = get_file_size(kip_path); + + if (ini1->size + file_size > PACKAGE2_SIZE_MAX) { + fatal_error("Failed to load %s: INI1 would be too large!\n", kip_path); + } + + kip1_header_t kip_header; + if (read_from_file(&kip_header, sizeof(kip_header), kip_path) != sizeof(kip_header) || kip_header.magic != MAGIC_KIP1) { + return; + } + + size_t kip_size = kip1_get_size_from_header(&kip_header); + if (kip_size > file_size) { + fatal_error("Failed to load %s: KIP size is corrupt!\n", kip_path); + } + + if (read_from_file(ini1->kip_data + ini1->size - sizeof(ini1_header_t), kip_size, kip_path) != kip_size) { + /* TODO: is this error fatal? */ + return; + } + + ini1->size += kip_size; + ini1->num_processes++; +} + +ini1_header_t *stratosphere_get_sd_files_ini1(void) { + if (g_sd_files_ini1 != NULL) { + return g_sd_files_ini1; + } + + /* Allocate space. */ + g_sd_files_ini1 = (ini1_header_t *)malloc(PACKAGE2_SIZE_MAX); + g_sd_files_ini1->magic = MAGIC_INI1; + g_sd_files_ini1->size = sizeof(ini1_header_t); + g_sd_files_ini1->num_processes = 0; + g_sd_files_ini1->_0xC = 0; + + /* Load all kips from /atmosphere/kips/<*>.kip or /atmosphere/kips/<*>/<*>.kip. */ + DIR *kips_dir = opendir("atmosphere/kips"); + struct dirent *ent; + if (kips_dir != NULL) { + while ((ent = readdir(kips_dir)) != NULL) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { + continue; + } + + char kip_path[0x301] = {0}; + snprintf(kip_path, 0x300, "atmosphere/kips/%s", ent->d_name); + + struct stat kip_stat; + if (stat(kip_path, &kip_stat) == -1) { + continue; + } + + if ((kip_stat.st_mode & S_IFMT) == S_IFREG) { + /* If file, add to ini1. */ + try_add_sd_kip(g_sd_files_ini1, kip_path); + } else if ((kip_stat.st_mode & S_IFMT) == S_IFDIR) { + /* Otherwise, allow one level of nesting. */ + DIR *sub_dir = opendir(kip_path); + struct dirent *sub_ent; + if (sub_dir != NULL) { + while ((sub_ent = readdir(sub_dir)) != NULL) { + if (strcmp(sub_ent->d_name, ".") == 0 || strcmp(sub_ent->d_name, "..") == 0) { + continue; + } + + /* Reuse kip path variable. */ + memset(kip_path, 0, sizeof(kip_path)); + snprintf(kip_path, 0x300, "atmosphere/kips/%s/%s", ent->d_name, sub_ent->d_name); + + if (stat(kip_path, &kip_stat) == -1) { + continue; + } + + if ((kip_stat.st_mode & S_IFMT) == S_IFREG) { + /* If file, add to ini1. */ + try_add_sd_kip(g_sd_files_ini1, kip_path); + } + } + closedir(sub_dir); + } + } + } + closedir(kips_dir); + } + + return g_sd_files_ini1; } /* 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) { - char sd_path[0x100] = {0}; uint32_t total_num_processes = 0; /* Validate all ini headers. */ @@ -170,7 +271,6 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { merged->num_processes = 0; merged->_0xC = 0; size_t remaining_size = PACKAGE2_SIZE_MAX - sizeof(ini1_header_t); - size_t read_size; unsigned char *current_dst_kip = merged->kip_data; @@ -196,34 +296,13 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { continue; } - /* TODO: What folder should these be read out of? */ - snprintf(sd_path, sizeof(sd_path), "atmosphere/titles/%016llX/%016llX.kip", current_kip->title_id, current_kip->title_id); - - /* Try to load an override KIP from SD, if possible. */ - read_size = read_from_file(current_dst_kip, remaining_size, sd_path); - if (read_size != 0) { - kip1_header_t *sd_kip = (kip1_header_t *)(current_dst_kip); - if (read_size < sizeof(kip1_header_t) || sd_kip->magic != MAGIC_KIP1) { - fatal_error("%s is not a KIP1?\n", sd_path); - } else if (sd_kip->title_id != current_kip->title_id) { - fatal_error("%s has wrong Title ID!\n", sd_path); - } - size_t expected_sd_kip_size = kip1_get_size_from_header(sd_kip); - if (expected_sd_kip_size != read_size) { - fatal_error("%s has wrong size or there is not enough space (expected 0x%zx, read 0x%zx)!\n", - sd_path, expected_sd_kip_size, read_size); - } - remaining_size -= expected_sd_kip_size; - current_dst_kip += expected_sd_kip_size; - } else { - size_t current_kip_size = kip1_get_size_from_header(current_kip); - if (current_kip_size > remaining_size) { - fatal_error("Not enough space for all the KIP1s!\n"); - } - memcpy(current_dst_kip, current_kip, current_kip_size); - remaining_size -= current_kip_size; - current_dst_kip += current_kip_size; + size_t current_kip_size = kip1_get_size_from_header(current_kip); + if (current_kip_size > remaining_size) { + fatal_error("Not enough space for all the KIP1s!\n"); } + 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; } diff --git a/fusee/fusee-secondary/src/stratosphere.h b/fusee/fusee-secondary/src/stratosphere.h index 33915555b..2ae43f1be 100644 --- a/fusee/fusee-secondary/src/stratosphere.h +++ b/fusee/fusee-secondary/src/stratosphere.h @@ -20,11 +20,13 @@ #include "utils.h" #include "kip.h" -#define STRATOSPHERE_INI1_EMBEDDED 0x0 -#define STRATOSPHERE_INI1_PACKAGE2 0x1 -#define STRATOSPHERE_INI1_MAX 0x2 +#define STRATOSPHERE_INI1_SDFILES 0x0 +#define STRATOSPHERE_INI1_EMBEDDED 0x1 +#define STRATOSPHERE_INI1_PACKAGE2 0x2 +#define STRATOSPHERE_INI1_MAX 0x3 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);