From 4160037c813e7a3af30b5b0fff06531020c55b4d Mon Sep 17 00:00:00 2001 From: CTCaer Date: Mon, 27 Apr 2020 09:30:53 +0300 Subject: [PATCH] emummc: Add boot entry emuMMC selection Using the key `emupath` on a boot entry will load the selected emuMMC. This can also be forced by using the correct boot cfg storage bit and writing the path at the emummc path offset. Check readme for these. This can only be used if the emuMMC was created via Nyx. because of the raw_based and file_based files that have emuMMC info. (emupath=emuMMC/RAW1, emupath=emuMMC/SD00, etc) --- README.md | 18 +++++---- bootloader/main.c | 73 ++++++++++++++++++++++++++++++++----- bootloader/storage/emummc.c | 41 ++++++++++++++++++++- bootloader/storage/emummc.h | 1 + bootloader/utils/types.h | 2 + nyx/nyx_gui/utils/types.h | 2 + 6 files changed, 117 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 909bd94..e663dff 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ You can find a template [Here](./res/hekate_ipl_template.ini) | fullsvcperm=1 | Disables SVC verification (full services permission) | | debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. | | atmosphere=1 | Enables Atmosphère patching. | +| emupath={SD folder} | Forces emuMMC to use the selected one. (=emuMMC/RAW1, =emuMMC/SD00, etc). emuMMC must be created by hekate because it uses the raw_based/file_based files. | | nouserexceptions=1 | Disables usermode exception handlers when paired with Exosphère. | | userpmu=1 | Allows user access to PMU when paired with Exosphère. | | emummc_force_disable=1 | Disabled emuMMC if it's enabled. | @@ -97,14 +98,15 @@ This is in case the kips are incompatible between them. If compatible, you can o hekate has a boot storage in the binary that helps it configure it outside of BPMP enviroment: -| Offset / Name | Description | -| -------------------- | ----------------------------------------------------------------- | -| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: Boot from ID, bit7: sept run. | -| '0x95' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. | -| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. | -| '0x97' extra_cfg | bit7: Force Nyx to run `Dump pkg1/2`. | -| '0x98' id[8] | When Boot from ID is set, it will search all inis automatically and find the boot entry with that id and boot it. Must be NULL terminated. | -| '0x98' xt_str[128] | Depends on the set cfg bits. | +| Offset / Name | Description | +| ----------------------- | ----------------------------------------------------------------- | +| '0x94' boot_cfg | bit0: `Force AutoBoot`, bit1: `Show launch log`, bit2: Boot from ID, bit3: `Boot to emuMMC`, bit7: `sept run`. | +| '0x95' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. | +| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. | +| '0x97' extra_cfg | bit7: Force Nyx to run `Dump pkg1/2`. | +| '0x98' xt_str[128] | Depends on the set cfg bits. | +| '0x98' id[8] | When `Boot from ID` is set, it will search all inis automatically and find the boot entry with that id and boot it. Must be NULL terminated. | +| '0xA0' emummc_path[120] | When `Boot to emuMMC` is set, it will override the current emuMMC (boot entry or emummc.ini). Must be NULL terminated. | If the main .ini is not found, it is created on the first hekate boot. diff --git a/bootloader/main.c b/bootloader/main.c index c66cbec..6f4c263 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -280,7 +280,7 @@ bool is_ipl_updated(void *buf, char *path, bool force) f_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS); f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL); - + // Write needed tag in case injected ipl uses old versioning. f_write(&fp, "ICTC49", 6, NULL); @@ -326,7 +326,7 @@ int launch_payload(char *path, bool update) if (f_read(&fp, buf, size, NULL)) { f_close(&fp); - + goto out; } @@ -476,6 +476,7 @@ void ini_list_launcher() { u8 max_entries = 61; char *payload_path = NULL; + char *emummc_path = NULL; ini_sec_t *cfg_sec = NULL; LIST_INIT(ini_list_sections); @@ -539,6 +540,20 @@ void ini_list_launcher() payload_path = ini_check_payload_section(cfg_sec); + if (cfg_sec) + { + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) + { + if (!strcmp("emummc_force_disable", kv->key)) + h_cfg.emummc_force_disable = atoi(kv->val); + else if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; + } + } + + if (emummc_path) + emummc_set_path(emummc_path); + if (cfg_sec && !payload_path) check_sept(cfg_sec); @@ -569,6 +584,13 @@ void ini_list_launcher() else if (!hos_launch(cfg_sec)) { EPRINTF("Failed to launch firmware."); + + if (emummc_path) + { + sd_mount(); + emummc_load_cfg(); + } + btn_wait(); } @@ -581,6 +603,7 @@ void launch_firmware() { u8 max_entries = 61; char *payload_path = NULL; + char *emummc_path = NULL; ini_sec_t *cfg_sec = NULL; LIST_INIT(ini_sections); @@ -663,9 +686,14 @@ void launch_firmware() { if (!strcmp("emummc_force_disable", kv->key)) h_cfg.emummc_force_disable = atoi(kv->val); + if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; } } + if (emummc_path) + emummc_set_path(emummc_path); + if (cfg_sec && !payload_path) check_sept(cfg_sec); @@ -699,7 +727,14 @@ void launch_firmware() free(payload_path); } else if (!hos_launch(cfg_sec)) + { EPRINTF("Failed to launch firmware."); + if (emummc_path) + { + sd_mount(); + emummc_load_cfg(); + } + } out: sd_unmount(); @@ -771,7 +806,7 @@ void nyx_load_run() (*nyx_ptr)(); } -static ini_sec_t *get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry) +static ini_sec_t *get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path) { ini_sec_t *cfg_sec = NULL; @@ -788,10 +823,13 @@ static ini_sec_t *get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomE *bootlogoCustomEntry = kv->val; if (!strcmp("emummc_force_disable", kv->key)) h_cfg.emummc_force_disable = atoi(kv->val); + if (!strcmp("emupath", kv->key)) + *emummc_path = kv->val; } if (!cfg_sec) { *bootlogoCustomEntry = NULL; + *emummc_path = NULL; h_cfg.emummc_force_disable = false; } @@ -812,6 +850,7 @@ static void _auto_launch_firmware() u8 *BOOTLOGO = NULL; char *payload_path = NULL; + char *emummc_path = NULL; u32 btn = 0; bool boot_from_id = (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) && (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN); if (boot_from_id) @@ -902,7 +941,7 @@ static void _auto_launch_firmware() } if (boot_from_id) - cfg_sec = get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry); + cfg_sec = get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path); else if (h_cfg.autoboot == boot_entry_id && configEntry) { cfg_sec = ini_sec; @@ -910,8 +949,10 @@ static void _auto_launch_firmware() { if (!strcmp("logopath", kv->key)) bootlogoCustomEntry = kv->val; - if (!strcmp("emummc_force_disable", kv->key)) + else if (!strcmp("emummc_force_disable", kv->key)) h_cfg.emummc_force_disable = atoi(kv->val); + else if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; } } if (cfg_sec) @@ -942,7 +983,7 @@ static void _auto_launch_firmware() continue; if (boot_from_id) - cfg_sec = get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry); + cfg_sec = get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path); else if (h_cfg.autoboot == boot_entry_id) { h_cfg.emummc_force_disable = false; @@ -951,8 +992,10 @@ static void _auto_launch_firmware() { if (!strcmp("logopath", kv->key)) bootlogoCustomEntry = kv->val; - if (!strcmp("emummc_force_disable", kv->key)) + else if (!strcmp("emummc_force_disable", kv->key)) h_cfg.emummc_force_disable = atoi(kv->val); + else if (!strcmp("emupath", kv->key)) + emummc_path = kv->val; } } if (cfg_sec) @@ -1064,9 +1107,19 @@ skip_list: } else { + if (b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC) + emummc_set_path(b_cfg.emummc_path); + else if (emummc_path) + emummc_set_path(emummc_path); check_sept(cfg_sec); hos_launch(cfg_sec); + if (emummc_path || b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC) + { + sd_mount(); + emummc_load_cfg(); + } + EPRINTF("\nFailed to launch HOS!"); gfx_printf("\nPress any key...\n"); msleep(500); @@ -1077,9 +1130,9 @@ out: gfx_con.mute = false; // Clear boot reasons from binary. - if (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) + if (b_cfg.boot_cfg & (BOOT_CFG_FROM_ID | BOOT_CFG_TO_EMUMMC)) memset(b_cfg.xt_str, 0, sizeof(b_cfg.xt_str)); - b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH | BOOT_CFG_FROM_ID); + b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH | BOOT_CFG_FROM_ID | BOOT_CFG_TO_EMUMMC); h_cfg.emummc_force_disable = false; nyx_load_run(); @@ -1254,7 +1307,7 @@ static void _check_low_battery() free(battery_icon); free(charging_icon); free(no_charging_icon); - + // Re enable Low Battery Monitor shutdown. max77620_low_battery_monitor_config(true); } diff --git a/bootloader/storage/emummc.c b/bootloader/storage/emummc.c index e3eb7ae..fa38f0f 100644 --- a/bootloader/storage/emummc.c +++ b/bootloader/storage/emummc.c @@ -38,7 +38,6 @@ extern void sd_unmount(); void emummc_load_cfg() { - sd_mount(); emu_cfg.enabled = 0; emu_cfg.path = NULL; emu_cfg.nintendo_path = NULL; @@ -47,7 +46,8 @@ void emummc_load_cfg() emu_cfg.file_based_part_size = 0; emu_cfg.active_part = 0; emu_cfg.fs_ver = 0; - emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + if (!emu_cfg.emummc_file_based_path) + emu_cfg.emummc_file_based_path = (char *)malloc(0x80); LIST_INIT(ini_sections); if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) @@ -78,6 +78,43 @@ void emummc_load_cfg() } } +void emummc_set_path(char *path) +{ + FIL fp; + bool found = false; + + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/raw_based"); + + if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + if (!f_read(&fp, &emu_cfg.sector, 4, NULL)) + if (emu_cfg.sector) + found = true; + } + else + { + strcpy(emu_cfg.emummc_file_based_path, path); + strcat(emu_cfg.emummc_file_based_path, "/file_based"); + + if (!f_stat(emu_cfg.emummc_file_based_path, NULL)) + { + emu_cfg.sector = 0; + emu_cfg.path = path; + + found = true; + } + } + + if (found) + { + emu_cfg.enabled = 1; + emu_cfg.id = 0; + strcpy(emu_cfg.nintendo_path, path); + strcpy(emu_cfg.nintendo_path, "/Nintendo"); + } +} + static int emummc_raw_get_part_off(int part_idx) { switch (part_idx) diff --git a/bootloader/storage/emummc.h b/bootloader/storage/emummc.h index 5ef8cfd..8a34f20 100644 --- a/bootloader/storage/emummc.h +++ b/bootloader/storage/emummc.h @@ -50,6 +50,7 @@ typedef struct _emummc_cfg_t emummc_cfg_t emu_cfg; void emummc_load_cfg(); +void emummc_set_path(char *path); int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); int emummc_storage_end(sdmmc_storage_t *storage); int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); diff --git a/bootloader/utils/types.h b/bootloader/utils/types.h index e0c43fe..96044dc 100644 --- a/bootloader/utils/types.h +++ b/bootloader/utils/types.h @@ -55,6 +55,7 @@ typedef int bool; #define BOOT_CFG_AUTOBOOT_EN (1 << 0) #define BOOT_CFG_FROM_LAUNCH (1 << 1) #define BOOT_CFG_FROM_ID (1 << 2) +#define BOOT_CFG_TO_EMUMMC (1 << 3) #define BOOT_CFG_SEPT_RUN (1 << 7) #define EXTRA_CFG_KEYS (1 << 0) @@ -75,6 +76,7 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t struct { char id[8]; + char emummc_path[0x78]; }; u8 xt_str[0x80]; }; diff --git a/nyx/nyx_gui/utils/types.h b/nyx/nyx_gui/utils/types.h index e0c43fe..96044dc 100644 --- a/nyx/nyx_gui/utils/types.h +++ b/nyx/nyx_gui/utils/types.h @@ -55,6 +55,7 @@ typedef int bool; #define BOOT_CFG_AUTOBOOT_EN (1 << 0) #define BOOT_CFG_FROM_LAUNCH (1 << 1) #define BOOT_CFG_FROM_ID (1 << 2) +#define BOOT_CFG_TO_EMUMMC (1 << 3) #define BOOT_CFG_SEPT_RUN (1 << 7) #define EXTRA_CFG_KEYS (1 << 0) @@ -75,6 +76,7 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t struct { char id[8]; + char emummc_path[0x78]; }; u8 xt_str[0x80]; };