From e9449f86bfa972b72a99a7ca85eeb3c8c10571a0 Mon Sep 17 00:00:00 2001 From: Aurora Date: Tue, 12 Apr 2016 23:18:07 +0200 Subject: [PATCH] Rewrote config menu to allow for multiple choice settings, made the N3DS CPU patch configurable in the NTR way, changed the config.bin format to be more future-proof (settings are on the leftmost part), added more macros to read settings --- injector/source/patcher.c | 13 ++- source/config.c | 212 ++++++++++++++++++++++---------------- source/config.h | 5 +- source/firm.c | 44 ++++---- source/fs.c | 11 +- source/screeninit.c | 2 +- 6 files changed, 162 insertions(+), 125 deletions(-) diff --git a/injector/source/patcher.c b/injector/source/patcher.c index 6c0adfa..2ea5f0c 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -5,6 +5,9 @@ #ifndef PATH_MAX #define PATH_MAX 255 +#define CONFIG(a) ((config >> (a + 16)) & 1) +#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3) +#define BOOTCONFIG(a, b) ((config >> a) & b) #endif static u32 config = 0; @@ -206,11 +209,11 @@ void patchCode(u64 progId, u8 *code, u32 size) case 0x0004001000027000LL: // KOR MSET case 0x0004001000028000LL: // TWN MSET { - if(R_SUCCEEDED(loadConfig()) && ((config >> 6) & 1)) + if(R_SUCCEEDED(loadConfig()) && CONFIG(6)) { static const u16 verPattern[] = u"Ver."; - const u32 currentNand = ((config >> 16) & 3); - const u32 matchingFirm = ((config >> 18) & 1) == (currentNand != 0); + const u32 currentNand = BOOTCONFIG(0, 3); + const u32 matchingFirm = BOOTCONFIG(2, 1) == (currentNand != 0); //Patch Ver. string patchMemory(code, size, @@ -242,7 +245,7 @@ void patchCode(u64 progId, u8 *code, u32 size) sizeof(stopCartUpdatesPatch), 2 ); - if(R_SUCCEEDED(loadConfig()) && ((config >> 4) & 1)) + if(R_SUCCEEDED(loadConfig()) && MULTICONFIG(1)) { static const u8 cfgN3dsCpuPattern[] = { 0x40, 0xA0, 0xE1, 0x07, 0x00 @@ -254,7 +257,7 @@ void patchCode(u64 progId, u8 *code, u32 size) if(cfgN3dsCpuLoc != NULL) { *(u32 *)(cfgN3dsCpuLoc + 3) = 0xE1A00000; - *(u32 *)(cfgN3dsCpuLoc + 0x1F) = 0xE3A00003; + *(u32 *)(cfgN3dsCpuLoc + 0x1F) = 0xE3A00000 + MULTICONFIG(1); } } diff --git a/source/config.c b/source/config.c index 9cf57c0..9f0711e 100644 --- a/source/config.c +++ b/source/config.c @@ -19,128 +19,162 @@ void configureCFW(const char *configPath) drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE); drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE); - const char *optionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )", - "( ) Autoboot SysNAND", - "( ) Updated SysNAND mode (A9LH-only)", - "( ) Force A9LH detection", - "( ) Use second EmuNAND as default", - "( ) Force max N3DS clock speed and L2 cache", - "( ) Use developer UNITINFO", - "( ) Show current NAND in System Settings", - "( ) Show GBA boot screen in patched AGB_FIRM", - "( ) Enable splash screen with no screen-init" }; + const char *multiOptionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )", + "New 3DS CPU: Off( ) L2( ) Clock( ) L2+Clock( )" }; - u32 optionsAmount = sizeof(optionsText) / sizeof(char *); + const char *singleOptionsText[] = { "( ) Autoboot SysNAND", + "( ) Updated SysNAND mode (A9LH-only)", + "( ) Force A9LH detection", + "( ) Use second EmuNAND as default", + "( ) Use developer UNITINFO", + "( ) Show current NAND in System Settings", + "( ) Show GBA boot screen in patched AGB_FIRM", + "( ) Enable splash screen with no screen-init" }; - struct option { + struct multiOption { int posY; u32 enabled; - } options[optionsAmount]; + int posXs[4]; + } multiOptions[] = { + { .posXs = {26, 31, 36, 41} }, + { .posXs = {17, 23, 32, 44} } + }; - //Parse the existing configuration - options[0].enabled = CONFIG(14, 3); - for(u32 i = optionsAmount - 1; i; i--) - options[i].enabled = CONFIG((i - 1), 1); + //Calculate the amount of the various kinds of options and pre-select the first single one + u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption), + singleOptionsAmount = sizeof(singleOptionsText) / sizeof(char *), + totalOptions = multiOptionsAmount + singleOptionsAmount, + selectedOption = multiOptionsAmount; - //Pre-select the first configuration option - u32 selectedOption = 1, - oldSelectedOption = 0, - optionChanged = 0; + struct singleOption { + int posY; + u32 enabled; + } singleOptions[singleOptionsAmount]; + + //Parse the existing options + for(u32 i = 0; i < multiOptionsAmount; i++) + multiOptions[i].enabled = MULTICONFIG(i); + for(u32 i = 0; i < singleOptionsAmount; i++) + singleOptions[i].enabled = CONFIG(i); //Character to display a selected option char selected = 'x'; - //Starting position - options[0].posY = 52; + int endPos = 42; - //Display all the normal options in white, brightness will be displayed later - for(u32 i = 1; i < optionsAmount; i++) + //Display all the normal options in white + for(u32 i = 0; i < multiOptionsAmount; i++) { - static int endPos = 59; - options[i].posY = endPos + SPACING_Y; - endPos = drawString(optionsText[i], 10, options[i].posY, COLOR_WHITE); - if(options[i].enabled) drawCharacter(selected, 10 + SPACING_X, options[i].posY, COLOR_WHITE); + multiOptions[i].posY = endPos + SPACING_Y; + endPos = drawString(multiOptionsText[i], 10, multiOptions[i].posY, COLOR_WHITE); + drawCharacter(selected, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE); } - //Boring configuration menu - while(1) + //Display the first normal option in red + singleOptions[0].posY = endPos + SPACING_Y + SPACING_Y / 2; + endPos = drawString(singleOptionsText[0], 10, singleOptions[0].posY, COLOR_RED); + + //Display all the multiple choice options in white except for the first + for(u32 i = 1; i < singleOptionsAmount; i++) { - u32 pressed = 0; + singleOptions[i].posY = endPos + SPACING_Y; + endPos = drawString(singleOptionsText[i], 10, singleOptions[i].posY, COLOR_WHITE); + if(singleOptions[i].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[i].posY, COLOR_WHITE); + } + + u32 pressed = 0; + + //Boring configuration menu + while(pressed != BUTTON_START) + { + pressed = 0; do { - //The status of the selected option changed, black out the previously visible 'x' if needed - if(optionChanged) - { - if(!selectedOption) - drawCharacter(selected, 10 + (26 + 5 * (optionChanged - 1)) * SPACING_X, options[0].posY, COLOR_BLACK); - else if(!options[selectedOption].enabled) - drawCharacter(selected, 10 + SPACING_X, options[selectedOption].posY, COLOR_BLACK); - - optionChanged = 0; - } - - //The selected option changed, draw the new one in red and the old one (with its 'x') in white - else if(selectedOption != oldSelectedOption) - { - drawString(optionsText[oldSelectedOption], 10, options[oldSelectedOption].posY, COLOR_WHITE); - drawString(optionsText[selectedOption], 10, options[selectedOption].posY, COLOR_RED); - - if(!oldSelectedOption) - drawCharacter(selected, 10 + (26 + 5 * options[0].enabled) * SPACING_X, options[0].posY, COLOR_WHITE); - else if(options[oldSelectedOption].enabled) - drawCharacter(selected, 10 + SPACING_X, options[oldSelectedOption].posY, COLOR_WHITE); - } - - //In any case, if the current option is enabled (or brightness is selected) we must display a red 'x' - if(!selectedOption) - drawCharacter(selected, 10 + (26 + 5 * options[0].enabled) * SPACING_X, options[0].posY, COLOR_RED); - else if(options[selectedOption].enabled) - drawCharacter(selected, 10 + SPACING_X, options[selectedOption].posY, COLOR_RED); + //In any case, if the current option is enabled (or a multiple choice option is selected) we must display a red 'x' + if(selectedOption < multiOptionsAmount) + drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED); + else if(singleOptions[selectedOption - multiOptionsAmount].enabled) + drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_RED); pressed = waitInput(); } while(!(pressed & MENU_BUTTONS)); //Remember the previously selected option + static u32 oldSelectedOption; oldSelectedOption = selectedOption; - switch(pressed) + if(pressed != BUTTON_A) { - case BUTTON_UP: - selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1; - break; - case BUTTON_DOWN: - selectedOption = selectedOption == (optionsAmount - 1) ? 1 : selectedOption + 1; - break; - case BUTTON_LEFT: - selectedOption = 1; - break; - case BUTTON_RIGHT: - selectedOption = optionsAmount - 1; - break; - case BUTTON_A: - optionChanged = 1; - if(selectedOption) options[selectedOption].enabled = !options[selectedOption].enabled; - else - { - optionChanged += options[0].enabled; - options[0].enabled = options[0].enabled == 3 ? 0 : options[0].enabled + 1; - } - break; - } + switch(pressed) + { + case BUTTON_UP: + selectedOption = !selectedOption ? totalOptions - 1 : selectedOption - 1; + break; + case BUTTON_DOWN: + selectedOption = selectedOption == (totalOptions - 1) ? 0 : selectedOption + 1; + break; + case BUTTON_LEFT: + if(!selectedOption) continue; + selectedOption = 0; + break; + case BUTTON_RIGHT: + if(selectedOption == totalOptions - 1) continue; + selectedOption = totalOptions - 1; + break; + default: + continue; + } - if(pressed == BUTTON_START) break; + //The user moved to a different option, print the old option in white and the new one in white. Only print 'x's if necessary + if(oldSelectedOption < multiOptionsAmount) + { + drawString(multiOptionsText[oldSelectedOption], 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE); + drawCharacter(selected, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE); + } + else + { + u32 singleOldSelected = oldSelectedOption - multiOptionsAmount; + drawString(singleOptionsText[singleOldSelected], 10, singleOptions[singleOldSelected].posY, COLOR_WHITE); + if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE); + } + + if(selectedOption < multiOptionsAmount) + drawString(multiOptionsText[selectedOption], 10, multiOptions[selectedOption].posY, COLOR_RED); + else + { + u32 singleSelected = selectedOption - multiOptionsAmount; + drawString(singleOptionsText[singleSelected], 10, singleOptions[singleSelected].posY, COLOR_RED); + } + } + else + { + //The selected option's status changed, print the 'x's accordingly. + if(selectedOption < multiOptionsAmount) + { + u32 oldEnabled = multiOptions[selectedOption].enabled; + drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK); + multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1; + } + else + { + u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled; + singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled; + if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK); + } + } } //Preserve the last-used boot options (last 12 bits) - config &= 0xFF0000; + config &= 0x3F; //Parse and write the new configuration - config |= options[0].enabled << 14; - for(u32 i = optionsAmount - 1; i; i--) - config |= options[i].enabled << (i - 1); + for(u32 i = 0; i < multiOptionsAmount; i++) + config |= multiOptions[i].enabled << (i * 2 + 6); + for(u32 i = 0; i < singleOptionsAmount; i++) + config |= singleOptions[i].enabled << (i + 16); - fileWrite(&config, configPath, 3); + fileWrite(&config, configPath, 4); //Zero the last booted FIRM flag CFG_BOOTENV = 0; diff --git a/source/config.h b/source/config.h index 9aa0838..7444e00 100644 --- a/source/config.h +++ b/source/config.h @@ -9,7 +9,10 @@ #include "types.h" #define CFG_BOOTENV (*(vu32 *)0x10010000) -#define CONFIG(a, b) ((config >> a) & b) + +#define CONFIG(a) ((config >> (a + 16)) & 1) +#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3) +#define BOOTCONFIG(a, b) ((config >> a) & b) extern u32 config; diff --git a/source/firm.c b/source/firm.c index d73d68d..60094b6 100755 --- a/source/firm.c +++ b/source/firm.c @@ -48,7 +48,7 @@ void main(void) //Attempt to read the configuration file const char configPath[] = "/aurei/config.bin"; - if(fileRead(&config, configPath, 3)) needConfig = 1; + if(fileRead(&config, configPath, 4)) needConfig = 1; else { config = 0; @@ -63,10 +63,10 @@ void main(void) //'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM firmType = *(vu8 *)0x23F00005 - '0'; - nandType = CONFIG(16, 3); - firmSource = CONFIG(18, 1); - a9lhInstalled = CONFIG(19, 1); - updatedSys = (a9lhInstalled && CONFIG(1, 1)) ? 1 : 0; + nandType = BOOTCONFIG(0, 3); + firmSource = BOOTCONFIG(2, 1); + a9lhInstalled = BOOTCONFIG(3, 1); + updatedSys = (a9lhInstalled && CONFIG(1)) ? 1 : 0; } else { @@ -83,10 +83,10 @@ void main(void) u32 pressed = HID_PAD; //Determine if we need to autoboot sysNAND - u32 autoBootSys = CONFIG(0, 1); + u32 autoBootSys = CONFIG(0); //Determine if A9LH is installed and the user has an updated sysNAND - if(a9lhBoot || CONFIG(2, 1)) + if(a9lhBoot || CONFIG(2)) { if(pressed == SAFE_MODE) error("Using Safe Mode would brick you, or remove A9LH!"); @@ -94,7 +94,7 @@ void main(void) a9lhInstalled = 1; //Check setting for > 9.2 sysNAND - updatedSys = CONFIG(1, 1); + updatedSys = CONFIG(1); } else { @@ -102,7 +102,7 @@ void main(void) updatedSys = 0; } - newConfig = a9lhInstalled << 19; + newConfig = a9lhInstalled << 3; /* If booting with A9LH, it's a MCU reboot and a previous configuration exists, try to force boot options */ @@ -112,18 +112,18 @@ void main(void) if(previousFirm == 7) { nandType = 0; - firmSource = updatedSys ? 0 : CONFIG(18, 1); + firmSource = updatedSys ? 0 : BOOTCONFIG(0, 3); needConfig = 0; //Flag to prevent multiple boot options-forcing - newConfig |= 1 << 20; + newConfig |= 1 << 4; } /* Else, force the last used boot options unless a payload button or A/L/R are pressed or the no-forcing flag is set */ - else if(!(pressed & OVERRIDE_BUTTONS) && !CONFIG(20, 1)) + else if(!(pressed & OVERRIDE_BUTTONS) && !BOOTCONFIG(4, 1)) { - nandType = CONFIG(16, 3); - firmSource = CONFIG(18, 1); + nandType = BOOTCONFIG(0, 3); + firmSource = BOOTCONFIG(2, 1); needConfig = 0; } } @@ -142,14 +142,14 @@ void main(void) configureCFW(configPath); //If screens are inited or the corresponding option is set, load splash screen - if(PDN_GPU_CNT != 1 || CONFIG(8, 1)) loadSplash(); + if(PDN_GPU_CNT != 1 || CONFIG(7)) loadSplash(); //Determine if we need to boot an emuNAND or sysNAND nandType = (pressed & BUTTON_L1) ? autoBootSys : ((pressed & BUTTON_R1) ? updatedSys : !autoBootSys); /* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed, or vice-versa, boot the second emuNAND */ - if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3, 1))) nandType++; + if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3))) nandType++; //Determine the NAND we should take the FIRM from firmSource = (pressed & BUTTON_R1) ? !nandType : (nandType != 0); @@ -169,16 +169,16 @@ void main(void) if(!bootType) { - newConfig |= (nandType << 16) | (firmSource << 18); + newConfig |= nandType | (firmSource << 2); /* If the boot configuration is different from previously, overwrite it. Just the no-forcing flag being set is not enough */ - if((newConfig & 0xEF0000) != (config & 0xFF0000)) + if((newConfig & 0x2F) != (config & 0xFF)) { //Preserve user settings (first 2 bytes) - newConfig |= config & 0xFFFF; + newConfig |= config & 0xFFFFFFC0; - fileWrite(&newConfig, configPath, 3); + fileWrite(&newConfig, configPath, 4); } } @@ -271,7 +271,7 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhInstalle *(u16 *)sigOffset2 = sigPatch[0]; *((u16 *)sigOffset2 + 1) = sigPatch[1]; - if(CONFIG(5, 1)) + if(CONFIG(4)) { //Apply UNITINFO patch u8 *unitInfoOffset = getUnitInfoValueSet(arm9Section, section[2].size); @@ -383,7 +383,7 @@ static inline void patchTwlAgbFirm(u32 firmType) /* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM if the matching option was enabled (keep it as last) */ - u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) : (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(7, 1)); + u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) : (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6)); const patchData *patches = firmType == 1 ? twlPatches : agbPatches; //Patch diff --git a/source/fs.c b/source/fs.c index d6e17cb..1b17301 100644 --- a/source/fs.c +++ b/source/fs.c @@ -96,8 +96,8 @@ void firmRead(void *dest, const char *firmFolder) u32 tempId = 0; for(char *tmp = info.fname; (*tmp) != '.'; tmp++) { - if((*tmp) > '9') tempId = (tempId << 4) + ((*tmp) - 'A') + 9; - else tempId = (tempId << 4) + (*tmp) - '0'; + tempId <<= 4; + tempId += *tmp > '9' ? (*tmp - 'A') + 9 : (*tmp) - '0'; } //Found a newer cxi @@ -116,13 +116,10 @@ void firmRead(void *dest, const char *firmFolder) while(id > 15) { u32 remainder = (id % 16); - if(remainder > 9) path[i] = remainder - 9 + 'A'; - else path[i] = remainder + '0'; + path[i--] = remainder > 9 ? remainder - 9 + 'A' : remainder + '0'; id /= 16; - i--; } - if(id > 9) path[i] = id - 9 + 'A'; - else path[i] = id + '0'; + path[i] = id > 9 ? id - 9 + 'A' : id + '0'; fileRead(dest, path, 0); } \ No newline at end of file diff --git a/source/screeninit.c b/source/screeninit.c index 04fb723..df090ad 100644 --- a/source/screeninit.c +++ b/source/screeninit.c @@ -54,7 +54,7 @@ void initScreens(void) memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size); //Write brightness level for the stub to pick up - *(vu32 *)(SCREENINIT_ADDRESS + 8) = CONFIG(14, 3); + *(vu32 *)(SCREENINIT_ADDRESS + 8) = MULTICONFIG(0); *arm11Entry = SCREENINIT_ADDRESS; while(*arm11Entry);