diff --git a/include/arm9/menu.h b/include/arm9/menu.h index ab93234..f5cb6c0 100644 --- a/include/arm9/menu.h +++ b/include/arm9/menu.h @@ -5,6 +5,7 @@ MENU_STATE_NAND_MENU, MENU_STATE_OPTIONS_MENU, MENU_STATE_OPTIONS_MODE, + MENU_STATE_FIRM_LAUNCH_SETTINGS, MENU_STATE_NAND_BACKUP, MENU_STATE_NAND_RESTORE, MENU_STATE_FIRM_LAUNCH, diff --git a/source/arm9/config.c b/source/arm9/config.c index c347a10..9a7d169 100644 --- a/source/arm9/config.c +++ b/source/arm9/config.c @@ -37,6 +37,7 @@ static bool parseConfigFile(); static bool parseBootOption(AttributeEntryType *attr); +static bool writeBootOption(AttributeEntryType *attr, void *newData, int key); static bool parseBootOptionPad(AttributeEntryType *attr); static bool parseBootMode(AttributeEntryType *attr); static bool writeBootMode(AttributeEntryType *attr, void *newData, int key); @@ -55,12 +56,13 @@ }; static FunctionsEntryType keyFunctions[] = { - { parseBootOption, NULL }, - { parseBootOption, NULL }, - { parseBootOption, NULL }, - { parseBootOption, NULL }, - { parseBootOption, NULL }, - { parseBootOption, NULL }, + { parseBootOption, writeBootOption }, + { parseBootOption, writeBootOption }, + { parseBootOption, writeBootOption }, + /* use the same functions for nand image option */ + { parseBootOption, writeBootOption }, + { parseBootOption, writeBootOption }, + { parseBootOption, writeBootOption }, { parseBootOptionPad, NULL }, { parseBootOptionPad, NULL }, { parseBootOptionPad, NULL }, @@ -153,6 +155,20 @@ return false; } +bool createConfigFile() +{ + filebuf = (char *) malloc(MAX_FILE_SIZE + 1); + + if(!filebuf) + return false; + + filebuf[0] = 0x0d; + filebuf[1] = 0x0a; + filebuf[2] = 0x00; + + return writeConfigFile(); +} + /* returns the start of an attribute's data. */ static char *findDefinition(const char *attrName) { @@ -281,11 +297,11 @@ if(diff) { if(curTextLen < newLen) - memcpy(textData + newLen - curTextLen, textData + curTextLen, - curLen - (filebuf - textData + newLen - curTextLen)); + memcpy(textData + diff, textData + curTextLen, + curLen - (filebuf - textData + diff) + 1); else memcpy(textData + newLen, textData + curTextLen, - curLen - (filebuf - textData + curTextLen)); + curLen - (filebuf - textData + curTextLen) + 1); for(u32 key=0; keytextData) @@ -371,6 +387,45 @@ return true; } +static bool writeBootOption(AttributeEntryType *attr, void *newData, int key) +{ + u32 len; + char *buf; + const char *path = (const char *) newData; + + if(!path) + return false; + + if(!isValidPath(path)) + return false; + + len = strlen(path); + + if(!attr->data) + { + buf = (char *) malloc(len + 1); + if(!attr->data) + return false; + } + else if(len != attr->textLength) + { + free(attr->data); + buf = (char *) malloc(len + 1); + if(!attr->data) + return false; + } + + memcpy(buf, path, len); + buf[len] = '\0'; + + attr->data = buf; + attr->textLength = len; + + writeAttributeText(attr, path, key); + + return true; +} + static bool parseBootOptionPad(AttributeEntryType *attr) { char c; @@ -512,3 +567,13 @@ return keyFunctions[key].write(attr, data, key); } +void configRestoreDefaults() +{ + for(int key=0; key= 3) - return false; - - return true; -} - void clearConsoles() { consoleSelect(&con_bottom); diff --git a/source/arm9/menu.c b/source/arm9/menu.c index 53c3578..1bd8cca 100644 --- a/source/arm9/menu.c +++ b/source/arm9/menu.c @@ -25,7 +25,7 @@ const menu_state_options menu_main = { 5, { - {"Launch FIRM", MENU_STATE_FIRM_LAUNCH}, + {"Launch FIRM", MENU_STATE_FIRM_LAUNCH_SETTINGS}, {"NAND tools...", MENU_STATE_NAND_MENU}, {"Options...", MENU_STATE_OPTIONS_MENU}, {"Browse FIRM...", MENU_STATE_BROWSER}, @@ -73,7 +73,8 @@ consoleSelect(&con_top); drawConsoleWindow(&con_top, 2, color); - printf("\n\t\t\t\t\t3DS Bootloader v%" PRIu16 ".%" PRIu16 "\n\n\n\n", BOOTLOADER_VERSION>>16, BOOTLOADER_VERSION & 0xFFFFu); + printf("\n\t\t\t\t\t3DS Bootloader v%" PRIu16 ".%" PRIu16 "\n\n\n\n", + BOOTLOADER_VERSION>>16, BOOTLOADER_VERSION & 0xFFFFu); printf(" Model: %s\n", bootInfo.model); printf(" \x1B[33m%s\e[0m\n", bootInfo.boot_env); @@ -111,19 +112,17 @@ // caller requested to enter a submenu? if(initial_state != MENU_STATE_MAIN) { - menuSetEnterNextState(initial_state); - menuUpdateGlobalState(); - menuActState(); + menuRunOnce(initial_state); + goto exitAndLaunchFirm; } + + menuSetEnterNextState(MENU_STATE_MAIN); + menuActState(); + // Menu main loop for(;;) { - hidScanInput(); - keys = hidKeysDown(); - - rewindConsole(); - const menu_state_options *cur_options = options_lookup[menu_state]; switch(menu_state) @@ -131,13 +130,19 @@ case MENU_STATE_MAIN: case MENU_STATE_NAND_MENU: case MENU_STATE_OPTIONS_MENU: - + + hidScanInput(); + keys = hidKeysDown(); + + rewindConsole(); + menu_main_draw_top(); // print all the options of the current state consoleSelect(&con_bottom); for(int i=0; i < cur_options->count; i++) - printf("\t\t\t%s\e[0m %s\n", cursor_pos == i ? "\x1B[33m*" : " ", cur_options->options[i].name); + printf("\t\t\t%s\e[0m %s\n", cursor_pos == i ? "\x1B[33m*" : " ", + cur_options->options[i].name); if(keys & KEY_DUP) { @@ -176,6 +181,11 @@ clearConsoles(); break; + case MENU_STATE_FIRM_LAUNCH_SETTINGS: + if(!menuTryLoadFirmwareFromSettings()) + clearConsoles(); + break; + case MENU_STATE_BROWSER: path = browseForFile("sdmc:"); clearConsoles(); @@ -186,9 +196,8 @@ break; case MENU_STATE_TEST_CONFIG: - consoleClear(); + clearConsoles(); consoleSelect(&con_top); - consoleClear(); printf("Key Text Data:\n"); for(int i=0; i"); } TIMER_sleep(6000); + clearConsoles(); menuSetReturnToState(STATE_PREVIOUS); break; + case MENU_STATE_EXIT: + goto exitAndLaunchFirm; + break; + default: printf("OOPS!\n"); break; } switch(menuUpdateGlobalState()) { - case MENU_EVENT_HOME_PRESSED: - break; - case MENU_EVENT_STATE_CHANGE: - if(menu_next_state == MENU_STATE_EXIT) - goto exitAndLaunchFirm; - else - clearConsole(0); - default: - break; + case MENU_EVENT_HOME_PRESSED: + break; + case MENU_EVENT_STATE_CHANGE: + if(menu_next_state == MENU_STATE_EXIT) + goto exitAndLaunchFirm; + else + clearConsole(0); + break; + default: + break; } menuActState(); @@ -244,6 +259,20 @@ return 0; } +void menuRunOnce(int state) +{ + switch(state) + { + case MENU_STATE_FIRM_LAUNCH_SETTINGS: + if(!menuTryLoadFirmwareFromSettings()) + clearConsoles(); + break; + + default: + panic(); + } +} + void menuSetReturnToState(int state) { int i; @@ -268,9 +297,6 @@ menu_previous_states_count = i; } } - - if(i == 0) - menu_previous_states_count = 0; } menu_next_state = state; diff --git a/source/arm9/menu_firmloader.c b/source/arm9/menu_firmloader.c index e831dd9..967884f 100644 --- a/source/arm9/menu_firmloader.c +++ b/source/arm9/menu_firmloader.c @@ -11,10 +11,18 @@ #include "arm9/timer.h" #include "arm9/menu.h" #include "arm9/firm.h" +#include "arm9/config.h" + +static bool firmLoaded = 0; static bool tryLoadFirmware(const char *filepath); static u32 loadFirmSd(const char *filePath); +bool isFirmLoaded(void) +{ + return firmLoaded; +} + bool menuLaunchFirm(const char *filePath) { u32 keys; @@ -22,10 +30,10 @@ if(!filePath) return false; - consoleSelect(&con_bottom); - consoleClear(); + firmLoaded = 0; + + clearConsoles(); consoleSelect(&con_top); - consoleClear(); printf("FIRM Loader\n\n"); @@ -45,6 +53,8 @@ goto fail; } + firmLoaded = 1; + printf("\n\x1B[32mFirmware verification SUCCESS!\e[0m\n\n"); printf("Attempting to run firmware, press B to exit...\n"); @@ -68,6 +78,8 @@ TIMER_sleep(2000); + firmLoaded = 0; + menuSetReturnToState(STATE_PREVIOUS); return false; @@ -78,6 +90,8 @@ { FILINFO fileStat; u32 fileSize; + + ensure_mounted(filePath); if(strncmp(filePath, "sdmc:", 5) == 0) { @@ -96,6 +110,139 @@ return false; } +bool tryLoadFirmwareFromSettings(void) +{ + const char *path; + int keyBootOption, keyPad; + int i; + u32 padValue, expectedPadValue; + + firmLoaded = 0; + + clearConsoles(); + consoleSelect(&con_top); + + printf("Loading FIRM from settings\n\n"); + + keyBootOption = KBootOption1; + keyPad = KBootOption1Buttons; + + for(i=0; i<3; i++, keyBootOption++, keyPad++) + { + path = (const char *)configGetData(keyBootOption); + if(path) + { + printf("\nBoot Option #%i:\n%s\n", i + 1, path); + + // check pad value + const u32 *temp; + temp = (const u32 *)configGetData(keyPad); + if(temp) + { + expectedPadValue = *temp; + hidScanInput(); + padValue = HID_KEY_MASK_ALL & hidKeysHeld(); + if(padValue != expectedPadValue) + { + printf("Skipping, right buttons are not pressed.\n"); + printf("%x %x\n", padValue, expectedPadValue); + continue; + } + } + + // check if fw still exists + if(!statFirmware(path)) + { + printf("Couldn't find firmware...\n"); + continue; + } + + if(menuLaunchFirm(path)) + break; + else + { + clearConsoles(); + consoleSelect(&con_top); + } + } + + // ... we failed, try next one + } + + if(i >= 3) + return false; + + return true; +} + +bool menuTryLoadFirmwareFromSettings(void) +{ + const char *path; + int keyBootOption, keyPad; + int i; + u32 padValue, expectedPadValue; + + clearConsoles(); + consoleSelect(&con_top); + + printf("Loading FIRM from settings\n\n"); + + keyBootOption = KBootOption1; + keyPad = KBootOption1Buttons; + + for(i=0; i<3; i++, keyBootOption++, keyPad++) + { + path = (const char *)configGetData(keyBootOption); + if(path) + { + printf("\nBoot Option #%i:\n%s\n", i + 1, path); + + // check if fw still exists + if(!statFirmware(path)) + { + printf("Couldn't find firmware...\n"); + continue; + } + + // check pad value + const u32 *temp; + temp = (const u32 *)configGetData(keyPad); + if(temp) + { + expectedPadValue = *temp; + hidScanInput(); + padValue = HID_KEY_MASK_ALL & hidKeysHeld(); + if(padValue != expectedPadValue) + { + printf("Skipping, right buttons are not pressed.\n"); + printf("%x %x\n", padValue, expectedPadValue); + continue; + } + } + + if(menuLaunchFirm(path)) + break; + else + { + clearConsoles(); + consoleSelect(&con_top); + } + } + + // ... we failed, try next one + } + + if(i >= 3) + { + menuSetReturnToState(STATE_PREVIOUS); + return false; + } + + menuSetReturnToState(MENU_STATE_EXIT); + + return true; +} + static bool tryLoadFirmware(const char *filepath) { u32 fw_size; @@ -103,7 +250,7 @@ if(!filepath) return false; - printf("Loading firmware:\n%s\n", filepath); + printf("Loading firmware:\n%s\n\n", filepath); if(strncmp(filepath, "sdmc:", 5) == 0) fw_size = loadFirmSd(filepath); @@ -137,7 +284,7 @@ return 0; } - if(fileSize > FIRM_MAX_SIZE) + if(fileSize == 0 || FIRM_MAX_SIZE > FIRM_MAX_SIZE) { f_close(&file); return 0;