Implement chainloader selector menu (can be called with START, the START payload can now be booted with L+START

This commit is contained in:
Aurora 2016-11-13 18:10:59 +01:00
parent bc167dde2d
commit 2e1b943805
4 changed files with 156 additions and 67 deletions

View File

@ -226,7 +226,9 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption), u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption),
singleOptionsAmount = sizeof(singleOptions) / sizeof(struct singleOption), singleOptionsAmount = sizeof(singleOptions) / sizeof(struct singleOption),
totalIndexes = multiOptionsAmount + singleOptionsAmount - 1, totalIndexes = multiOptionsAmount + singleOptionsAmount - 1,
selectedOption; selectedOption,
singleSelected;
bool isMultiOption;
//Parse the existing options //Parse the existing options
for(u32 i = 0; i < multiOptionsAmount; i++) for(u32 i = 0; i < multiOptionsAmount; i++)
@ -314,9 +316,22 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
if(selectedOption < multiOptionsAmount) 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; 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(singleOptions[singleOldSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
} }
if(selectedOption < multiOptionsAmount) if(isMultiOption) drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED);
drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED); else drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED);
else
{
u32 singleSelected = selectedOption - multiOptionsAmount;
drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED);
}
clearScreens(false, true, false); clearScreens(false, true, false);
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE); drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
@ -348,7 +358,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
else else
{ {
//The selected option's status changed, print the 'x's accordingly //The selected option's status changed, print the 'x's accordingly
if(selectedOption < multiOptionsAmount) if(isMultiOption)
{ {
u32 oldEnabled = multiOptions[selectedOption].enabled; u32 oldEnabled = multiOptions[selectedOption].enabled;
drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK); 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 else
{ {
bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled; bool oldEnabled = singleOptions[singleSelected].enabled;
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled; singleOptions[singleSelected].enabled = !oldEnabled;
if(oldEnabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK); 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' //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) if(isMultiOption) drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
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);
else
{
u32 singleSelected = selectedOption - multiOptionsAmount;
if(singleOptions[singleSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
}
} }
//Preserve the last-used boot options (first 9 bits) //Preserve the last-used boot options (first 9 bits)

View File

@ -26,6 +26,8 @@
#include "crypto.h" #include "crypto.h"
#include "cache.h" #include "cache.h"
#include "screen.h" #include "screen.h"
#include "draw.h"
#include "utils.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
#include "buttons.h" #include "buttons.h"
#include "../build/bundled.h" #include "../build/bundled.h"
@ -126,8 +128,15 @@ void fileDelete(const char *path)
f_unlink(path); f_unlink(path);
} }
void loadPayload(u32 pressed) void loadPayload(u32 pressed, const char *payloadPath)
{ {
u32 *loaderAddress = (u32 *)0x24FFFE00;
u8 *payloadAddress = (u8 *)0x24F00000;
u32 payloadSize = 0,
maxPayloadSize = (u32)((u8 *)loaderAddress - payloadAddress);
if(payloadPath == NULL)
{
const char *pattern; const char *pattern;
if(pressed & BUTTON_LEFT) pattern = PATTERN("left"); if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
@ -144,9 +153,10 @@ void loadPayload(u32 pressed)
DIR dir; DIR dir;
FILINFO info; FILINFO info;
FRESULT result;
char path[22] = "payloads"; char path[22] = "payloads";
FRESULT result = f_findfirst(&dir, &info, path, pattern); result = f_findfirst(&dir, &info, path, pattern);
if(result == FR_OK) if(result == FR_OK)
{ {
@ -154,18 +164,17 @@ void loadPayload(u32 pressed)
if(info.fname[0] != 0) if(info.fname[0] != 0)
{ {
u32 *loaderAddress = (u32 *)0x24FFFE00;
u8 *payloadAddress = (u8 *)0x24F00000;
memcpy(loaderAddress, loader_bin, loader_bin_size);
concatenateStrings(path, "/"); concatenateStrings(path, "/");
concatenateStrings(path, info.altname); concatenateStrings(path, info.altname);
payloadSize = fileRead(payloadAddress, path, maxPayloadSize);
u32 payloadSize = fileRead(payloadAddress, path, (u32)((u8 *)loaderAddress - payloadAddress)); }
}
}
else payloadSize = fileRead(payloadAddress, payloadPath, maxPayloadSize);
if(payloadSize > 0) if(payloadSize > 0)
{ {
memcpy(loaderAddress, loader_bin, loader_bin_size);
loaderAddress[1] = payloadSize; loaderAddress[1] = payloadSize;
backupAndRestoreShaHash(true); backupAndRestoreShaHash(true);
@ -176,6 +185,80 @@ void loadPayload(u32 pressed)
((void (*)())loaderAddress)(); ((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(payloadNum > 0)
{
char selected = '*';
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, payloadList[selectedPayload]);
loadPayload(0, path);
error("The payload is too large or corrupted.");
} }
} }
} }

View File

@ -31,6 +31,7 @@ u32 fileRead(void *dest, const char *path, u32 maxSize);
u32 getFileSize(const char *path); u32 getFileSize(const char *path);
bool fileWrite(const void *buffer, const char *path, u32 size); bool fileWrite(const void *buffer, const char *path, u32 size);
void fileDelete(const char *path); 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); u32 firmRead(void *dest, u32 firmType);
void findDumpFile(const char *path, char *fileName); void findDumpFile(const char *path, char *fileName);

View File

@ -157,12 +157,12 @@ void main(void)
if(splashMode == 1 && loadSplash()) pressed = HID_PAD; 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, /* If L and R/A/Select or one of the single payload buttons are pressed,
chainload an external payload */ chainload an external payload */
bool shouldLoadPayload = ((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1)); ((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
if(shouldLoadPayload) loadPayload(pressed);
if(splashMode == 2) loadSplash(); if(splashMode == 2) loadSplash();