diff --git a/source/config.c b/source/config.c index cbd31ee..3af1714 100644 --- a/source/config.c +++ b/source/config.c @@ -226,7 +226,9 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption), singleOptionsAmount = sizeof(singleOptions) / sizeof(struct singleOption), totalIndexes = multiOptionsAmount + singleOptionsAmount - 1, - selectedOption; + selectedOption, + singleSelected; + bool isMultiOption; //Parse the existing options for(u32 i = 0; i < multiOptionsAmount; i++) @@ -314,9 +316,22 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) if(selectedOption < multiOptionsAmount) { - if(multiOptions[selectedOption].visible) break; + if(multiOptions[selectedOption].visible) + { + isMultiOption = true; + break; + } + } + else + { + singleSelected = selectedOption - multiOptionsAmount; + + if(singleOptions[singleSelected].visible) + { + isMultiOption = false; + break; + } } - else if(singleOptions[selectedOption - multiOptionsAmount].visible) break; } if(selectedOption == oldSelectedOption) continue; @@ -334,13 +349,8 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE); } - if(selectedOption < multiOptionsAmount) - drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED); - else - { - u32 singleSelected = selectedOption - multiOptionsAmount; - drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED); - } + if(isMultiOption) drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED); + else drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED); clearScreens(false, true, false); drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE); @@ -348,7 +358,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) else { //The selected option's status changed, print the 'x's accordingly - if(selectedOption < multiOptionsAmount) + if(isMultiOption) { u32 oldEnabled = multiOptions[selectedOption].enabled; drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK); @@ -358,20 +368,15 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) } else { - bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled; - singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled; - if(oldEnabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK); + bool oldEnabled = singleOptions[singleSelected].enabled; + singleOptions[singleSelected].enabled = !oldEnabled; + if(oldEnabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_BLACK); } } //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, true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED); - else - { - u32 singleSelected = selectedOption - multiOptionsAmount; - if(singleOptions[singleSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED); - } + if(isMultiOption) drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED); + else if(singleOptions[singleSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED); } //Preserve the last-used boot options (first 9 bits) diff --git a/source/fs.c b/source/fs.c index e1f8b58..f383bc6 100644 --- a/source/fs.c +++ b/source/fs.c @@ -26,6 +26,8 @@ #include "crypto.h" #include "cache.h" #include "screen.h" +#include "draw.h" +#include "utils.h" #include "fatfs/ff.h" #include "buttons.h" #include "../build/bundled.h" @@ -126,56 +128,137 @@ void fileDelete(const char *path) f_unlink(path); } -void loadPayload(u32 pressed) +void loadPayload(u32 pressed, const char *payloadPath) { - const char *pattern; + u32 *loaderAddress = (u32 *)0x24FFFE00; + u8 *payloadAddress = (u8 *)0x24F00000; + u32 payloadSize = 0, + maxPayloadSize = (u32)((u8 *)loaderAddress - payloadAddress); - if(pressed & BUTTON_LEFT) pattern = PATTERN("left"); - else if(pressed & BUTTON_RIGHT) pattern = PATTERN("right"); - else if(pressed & BUTTON_UP) pattern = PATTERN("up"); - else if(pressed & BUTTON_DOWN) pattern = PATTERN("down"); - else if(pressed & BUTTON_START) pattern = PATTERN("start"); - else if(pressed & BUTTON_B) pattern = PATTERN("b"); - else if(pressed & BUTTON_X) pattern = PATTERN("x"); - else if(pressed & BUTTON_Y) pattern = PATTERN("y"); - else if(pressed & BUTTON_R1) pattern = PATTERN("r"); - else if(pressed & BUTTON_A) pattern = PATTERN("a"); - else pattern = PATTERN("select"); - - DIR dir; - FILINFO info; - char path[22] = "payloads"; - - FRESULT result = f_findfirst(&dir, &info, path, pattern); - - if(result == FR_OK) + if(payloadPath == NULL) { + const char *pattern; + + if(pressed & BUTTON_LEFT) pattern = PATTERN("left"); + else if(pressed & BUTTON_RIGHT) pattern = PATTERN("right"); + else if(pressed & BUTTON_UP) pattern = PATTERN("up"); + else if(pressed & BUTTON_DOWN) pattern = PATTERN("down"); + else if(pressed & BUTTON_START) pattern = PATTERN("start"); + else if(pressed & BUTTON_B) pattern = PATTERN("b"); + else if(pressed & BUTTON_X) pattern = PATTERN("x"); + else if(pressed & BUTTON_Y) pattern = PATTERN("y"); + else if(pressed & BUTTON_R1) pattern = PATTERN("r"); + else if(pressed & BUTTON_A) pattern = PATTERN("a"); + else pattern = PATTERN("select"); + + DIR dir; + FILINFO info; + FRESULT result; + char path[22] = "payloads"; + + result = f_findfirst(&dir, &info, path, pattern); + + if(result == FR_OK) + { + f_closedir(&dir); + + if(info.fname[0] != 0) + { + concatenateStrings(path, "/"); + concatenateStrings(path, info.altname); + payloadSize = fileRead(payloadAddress, path, maxPayloadSize); + } + } + } + else payloadSize = fileRead(payloadAddress, payloadPath, maxPayloadSize); + + if(payloadSize > 0) + { + memcpy(loaderAddress, loader_bin, loader_bin_size); + loaderAddress[1] = payloadSize; + + backupAndRestoreShaHash(true); + initScreens(); + + flushDCacheRange(loaderAddress, loader_bin_size); + flushICacheRange(loaderAddress, loader_bin_size); + + ((void (*)())loaderAddress)(); + } +} + +void payloadMenu(void) +{ + DIR dir; + char path[_MAX_LFN + 10] = "payloads"; + + if(f_opendir(&dir, path) == FR_OK) + { + u32 payloadNum = 0; + + FILINFO info; + char payloadList[21][_MAX_LFN + 1]; + + while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 21) + if(info.fname[0] != '.' && memcmp(info.altname + 8, ".BIN", 4) == 0 && strlen(info.fname) < 48) + memcpy(payloadList[payloadNum++], info.fname, sizeof(info.fname)); + f_closedir(&dir); - if(info.fname[0] != 0) + if(payloadNum > 0) { - u32 *loaderAddress = (u32 *)0x24FFFE00; - u8 *payloadAddress = (u8 *)0x24F00000; + char selected = '*'; - memcpy(loaderAddress, loader_bin, loader_bin_size); + initScreens(); + + drawString("Luma3DS chainloader - Press A to select", true, 10, 10, COLOR_TITLE); + + for(u32 i = 0, posY = 30; i < payloadNum; i++, posY += SPACING_Y) + drawString(payloadList[i], true, 10 + 2 * (SPACING_X), posY, COLOR_WHITE); + + drawCharacter(selected, true, 10, 30, COLOR_RED); + + u32 pressed = 0, + selectedPayload = 0; + + while(pressed != BUTTON_A) + { + do + { + pressed = waitInput(); + } + while(!(pressed & MENU_BUTTONS)); + + u32 oldSelectedPayload = selectedPayload; + + switch(pressed) + { + case BUTTON_UP: + selectedPayload = !selectedPayload ? payloadNum - 1 : selectedPayload - 1; + break; + case BUTTON_DOWN: + selectedPayload = selectedPayload == payloadNum - 1 ? 0 : selectedPayload + 1; + break; + case BUTTON_LEFT: + selectedPayload = 0; + break; + case BUTTON_RIGHT: + selectedPayload = payloadNum - 1; + break; + default: + continue; + } + + if(oldSelectedPayload == selectedPayload) continue; + + drawCharacter(selected, true, 10, 30 + oldSelectedPayload * SPACING_Y, COLOR_BLACK); + drawCharacter(selected, true, 10, 30 + selectedPayload * SPACING_Y, COLOR_RED); + } concatenateStrings(path, "/"); - concatenateStrings(path, info.altname); - - u32 payloadSize = fileRead(payloadAddress, path, (u32)((u8 *)loaderAddress - payloadAddress)); - - if(payloadSize > 0) - { - loaderAddress[1] = payloadSize; - - backupAndRestoreShaHash(true); - initScreens(); - - flushDCacheRange(loaderAddress, loader_bin_size); - flushICacheRange(loaderAddress, loader_bin_size); - - ((void (*)())loaderAddress)(); - } + concatenateStrings(path, payloadList[selectedPayload]); + loadPayload(0, path); + error("The payload is too large or corrupted."); } } } diff --git a/source/fs.h b/source/fs.h index fffb530..14f26c0 100644 --- a/source/fs.h +++ b/source/fs.h @@ -31,6 +31,7 @@ u32 fileRead(void *dest, const char *path, u32 maxSize); u32 getFileSize(const char *path); bool fileWrite(const void *buffer, const char *path, u32 size); void fileDelete(const char *path); -void loadPayload(u32 pressed); +void loadPayload(u32 pressed, const char *payloadPath); +void payloadMenu(void); u32 firmRead(void *dest, u32 firmType); void findDumpFile(const char *path, char *fileName); \ No newline at end of file diff --git a/source/main.c b/source/main.c index 8e34806..9ea3831 100644 --- a/source/main.c +++ b/source/main.c @@ -157,12 +157,12 @@ void main(void) if(splashMode == 1 && loadSplash()) pressed = HID_PAD; + if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START) payloadMenu(); + /* If L and R/A/Select or one of the single payload buttons are pressed, chainload an external payload */ - bool shouldLoadPayload = ((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || - ((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1)); - - if(shouldLoadPayload) loadPayload(pressed); + else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || + ((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL); if(splashMode == 2) loadSplash();