From: chaoskagami Date: Mon, 20 Jun 2016 23:20:56 +0000 (-0400) Subject: Finish off the chainloader (now I just need to add compile time cut-out) X-Git-Tag: v0.1.1~8 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=e3413e5db10d88f09c75b9ad7e0f46ba4532cdf1;p=corbenik%2Fcorbenik.git Finish off the chainloader (now I just need to add compile time cut-out) Also removed reverse mode on emunand for now (working on a FS) --- diff --git a/external/bits/chain.s b/external/bits/chain.s index 350dfff..9a3c201 100644 --- a/external/bits/chain.s +++ b/external/bits/chain.s @@ -1,7 +1,23 @@ +// This is a tiny chainloader. It expects r0 to be the +// code to copy, and r1 to be the code's size. + +// As long as GCC follows standard calling conventions, you +// can call it from C once in memory like: + +// void copy(uint8_t* data, uint32_t size) + +// This means NO need to use fatfs with the chainloader since the +// caller itself handles the disk read. + +// The code below is also all PC-relative, meaning you can actually +// run the chainloader from anywhere (as long as it is aligned to +// instruction boundaries/the chainloader isn't overwritten/the +// code isn't copied wrong over itself) + .syntax unified .section .text .global copy -copy: // void copy(uint8_t* data, uint32_t size) +copy: ldr r3, value add r1, r0, r1 diff --git a/source/chain.c b/source/chain.c new file mode 100644 index 0000000..89f58aa --- /dev/null +++ b/source/chain.c @@ -0,0 +1,137 @@ +#include "common.h" +#include "firm/firm.h" +#include "firm/headers.h" + +uint32_t current_chain_index = 0; + +struct options_s *chains = (struct options_s*)FCRAM_CHAIN_LOC; + +int show_menu(struct options_s *options, uint8_t *toggles); + +// TODO - The near same function is called in different places. It would +// be better to have a recursive listing that calls a function for +// each entry (it would cut code density) + +void chainload_file(char* chain_file_data) { + // We copy because it's possible the payload will overwrite us in memory. + char chain_file[256]; + strncpy(chain_file, chain_file_data, 255); + + char code_file[] = PATH_BITS "/chain.bin"; + + uint8_t* bootstrap = (uint8_t*)0x24F00000; + uint32_t size = 0; + uint8_t* chain_data; + + FILE* f = fopen(code_file, "r"); + if (!f) { + // File missing. + abort("Missing chainloader.\n"); + } + + size = fsize(f); + fread(bootstrap, 1, size, f); + fclose(f); + + chain_data = bootstrap + size; + + f = fopen(chain_file, "r"); + if (!f) { + // File missing. + abort("Missing program to chainload?\n"); + } + + size = fsize(f); + fread(chain_data, 1, size, f); + fclose(f); + + fprintf(stderr, "Chaining to copy payload.\n"); + + ((void(*)())0x24F00000)(chain_data, size); +} + +// This function is based on PathDeleteWorker from GodMode9. +// It was easier to just import it. +int +list_chain_build_back(char *fpath) +{ + FILINFO fno = {.lfname = NULL }; + + // this code handles directory content deletion + if (f_stat(fpath, &fno) != FR_OK) + return 1; // fpath does not exist + + if (fno.fattrib & AM_DIR) { // process folder contents + DIR pdir; + char *fname = fpath + strnlen(fpath, 255); + if (f_opendir(&pdir, fpath) != FR_OK) + return 1; + + *(fname++) = '/'; + fno.lfname = fname; + fno.lfsize = fpath + 255 - fname; + + while (f_readdir(&pdir, &fno) == FR_OK) { + if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0)) + continue; // filter out virtual entries + if (fname[0] == 0) + strncpy(fname, fno.fname, fpath + 255 - fname); + if (fno.fname[0] == 0) + break; + else // return value won't matter + list_chain_build_back(fpath); + } + + f_closedir(&pdir); + *(--fname) = '\0'; + } else { + char* basename = &fpath[strlen(fpath) - 1]; + while(basename[0] != '/') basename--; + basename++; + + strncpy(chains[current_chain_index].name, basename, 64); + strncpy(chains[current_chain_index].desc, fpath, 255); + + chains[current_chain_index].index = 0; + chains[current_chain_index].allowed = call_fun; + chains[current_chain_index].a = (uint32_t) chainload_file; + chains[current_chain_index].b = (uint32_t) chains[current_chain_index].desc; + + current_chain_index++; + } + + return 0; +} + +// This is dual purpose. When we actually list +// patches to build the cache - desc_is_fname +// will be set to 1. + +void +list_chain_build(char *name) +{ + current_chain_index = 0; + + strncpy(chains[0].name, "\x1b[40;32mChainloader Payloads\x1b[0m", 64); + strncpy(chains[0].desc, "", 255); + chains[0].index = 0; + chains[0].allowed = not_option; + chains[0].a = 0; + chains[0].b = 0; + + current_chain_index += 1; + + char fpath[256]; + strncpy(fpath, name, 256); + list_chain_build_back(fpath); + chains[current_chain_index].index = -1; + + if (chains[1].index == -1) + chains[0].index = -1; // No chainloadable files. +} + +void chainload_menu() { + list_chain_build(PATH_CHAINS); + + show_menu(chains, NULL); +} diff --git a/source/config.c b/source/config.c index 60d7684..ffff9d3 100644 --- a/source/config.c +++ b/source/config.c @@ -30,7 +30,6 @@ mk_structure() f_mkdir(PATH_PATCHES); f_mkdir(PATH_FIRMWARES); f_mkdir(PATH_MODULES); - f_mkdir(PATH_SVC); f_mkdir(PATH_KEYS); f_mkdir(PATH_EXEFS); f_mkdir(PATH_EXEFS_TEXT); diff --git a/source/config.h b/source/config.h index c960925..9de4341 100644 --- a/source/config.h +++ b/source/config.h @@ -39,7 +39,7 @@ enum type break_menu = 6 }; -typedef void (*func_call_t)(void); +typedef void (*func_call_t)(uint32_t data); struct range_str { @@ -119,7 +119,9 @@ struct options_s // This isn't supported by ANY tools like D9 at the moment // (Though I hope they'll consider it - // there's only benefits to users with multiple EmuNANDs) -#define OPTION_EMUNAND_REVERSE 22 + +// Disable Reverse. We're going to implement an actual filesystem. +// #define OPTION_EMUNAND_REVERSE 22 // Save log files during boot and from loader. // This will slow things down a bit. diff --git a/source/display.c b/source/display.c index bb7b715..ba9303f 100644 --- a/source/display.c +++ b/source/display.c @@ -154,7 +154,7 @@ show_menu(struct options_s *options, uint8_t *toggles) else toggles[options[cursor_y].index]++; } else if (options[cursor_y].allowed == call_fun) { - ((func_call_t)(options[cursor_y].a))(); // Call 'a' as a function. + ((func_call_t)(options[cursor_y].a))(options[cursor_y].b); // Call 'a' as a function. } else if (options[cursor_y].allowed == break_menu) { exit = 1; clear_screen(TOP_SCREEN); diff --git a/source/firm/fcram.h b/source/firm/fcram.h index 6c4395f..3ca5fb1 100644 --- a/source/firm/fcram.h +++ b/source/firm/fcram.h @@ -36,4 +36,7 @@ extern void *fcram_temp; // Path that the font will be loaded at. #define FCRAM_FONT_LOC (FCRAM_PATCHLIST_LOC + (FCRAM_SPACING / 2)) +// Path that the menu for chains will be at +#define FCRAM_CHAIN_LOC (FCRAM_FONT_LOC + FCRAM_SPACING) + #endif diff --git a/source/menu.c b/source/menu.c index 06a6738..e67725d 100644 --- a/source/menu.c +++ b/source/menu.c @@ -16,7 +16,7 @@ static struct options_s options[] = { { OPTION_EMUNAND, "Use EmuNAND", "Redirects NAND write/read to the SD. This supports both Gateway and redirected layouts.", boolean_val, 0, 0 }, { OPTION_EMUNAND_INDEX, " Index", "Which EmuNAND to use. If you only have one, you want 0. Currently the maximum supported is 10 (0-9), but this is arbitrary.", ranged_val, 0, 0x9 }, - { OPTION_EMUNAND_REVERSE, " Reverse layout", "(Warning - Experimental!) Calculate EmuNAND sector from the end of the disk, not the start. This isn't supported by tools like Decrypt9, but has some advantages.", boolean_val, 0, 0x9 }, +// { OPTION_EMUNAND_REVERSE, " Reverse layout", "(Warning - Experimental!) Calculate EmuNAND sector from the end of the disk, not the start. This isn't supported by tools like Decrypt9, but has some advantages.", boolean_val, 0, 0x9 }, { OPTION_AUTOBOOT, "Autoboot", "Boot the system automatically, unless the R key is held while booting.", boolean_val, 0, 0 }, { OPTION_SILENCE, " Silent mode", "Suppress all debug output during autoboot. You'll see the screen turn on and then off once.", boolean_val, 0, 0 }, @@ -300,6 +300,8 @@ poweroff() ; } +void chainload_menu(); + static struct options_s main_s[] = { { 0, "Options", "Internal options for the CFW. These are part of Corbenik itself.", call_fun, (uint32_t)menu_options, 0 }, { 0, "Patches", "External bytecode patches found in `" PATH_PATCHES "`. You can choose which to enable.", call_fun, (uint32_t)menu_patches, 0 }, @@ -308,6 +310,7 @@ static struct options_s main_s[] = { { 0, "Reboot", "Reboots the console.", call_fun, (uint32_t)reset, 0 }, { 0, "Power off", "Powers off the console.", call_fun, (uint32_t)poweroff, 0 }, { 0, "Save Configuration", "Save the configuration. You must do this prior to booting, otherwise nothing is done.", call_fun, (uint32_t)save_config, 0 }, + { 0, "Chainload", "Boot another ARM9 payload file.", call_fun, (uint32_t)chainload_menu, 0 }, { 0, "Boot Firmware", "Generates caches, patches the firmware, and boots it.", break_menu, 0, 0 }, // Sentinel. diff --git a/source/patch/emunand.c b/source/patch/emunand.c index ac2de8c..20237a0 100644 --- a/source/patch/emunand.c +++ b/source/patch/emunand.c @@ -40,16 +40,9 @@ verify_emunand(uint32_t index, uint32_t *off, uint32_t *head) uint32_t offset; if (nandSize > 0x200000) - offset = 0x400000; + offset = 0x400000 * index; else - offset = 0x200000; - - if (config.options[OPTION_EMUNAND_REVERSE]) { - // Subtract offset from back of disk. - offset = (getMMCDevice(1)->total_size - 1) - (offset * (index + 1)); - } else { - offset = offset * index; - } + offset = 0x200000 * index; // Check for RedNAND/Normal physical layout on SD if (!sdmmc_sdcard_readsectors(offset + 1, 1, emunand_temp) && *(uint32_t *)(emunand_temp + 0x100) == NCSD_MAGIC) { diff --git a/source/patch_format.h b/source/patch_format.h index 02e63ae..57d9ab6 100644 --- a/source/patch_format.h +++ b/source/patch_format.h @@ -39,7 +39,8 @@ #define PATH_PATCHES PATH_CFW "/patch" // Patch binary folder. #define PATH_FIRMWARES PATH_CFW "/firmware" // Firmware folder. #define PATH_MODULES PATH_CFW "/module" // Sysmodule location -#define PATH_SVC PATH_CFW "/svc" // Svc code location. + +#define PATH_CHAINS PATH_CFW "/chain" #define PATH_TEMP PATH_CFW "/cache" // Files that are transient and used to speed operation #define PATH_LOADER_CACHE PATH_TEMP "/loader" // Cached patch bytecode for loader.