Refactor the codebase to limit nested if/elses

This commit is contained in:
Aurora 2016-11-15 19:29:48 +01:00
parent 141c7817a0
commit 9332b9eb33
13 changed files with 1023 additions and 1276 deletions

View File

@ -51,8 +51,8 @@ static inline void loadCFWInfo(void)
{ {
static bool infoLoaded = false; static bool infoLoaded = false;
if(!infoLoaded) if(infoLoaded) return;
{
svcGetCFWInfo(&info); svcGetCFWInfo(&info);
IFile file; IFile file;
@ -61,21 +61,19 @@ static inline void loadCFWInfo(void)
infoLoaded = true; infoLoaded = true;
} }
}
static inline bool secureInfoExists(void) static inline bool secureInfoExists(void)
{ {
static bool exists = false; static bool exists = false;
if(!exists) if(exists) return true;
{
IFile file; IFile file;
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ))) if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
{ {
exists = true; exists = true;
IFile_Close(&file); IFile_Close(&file);
} }
}
return exists; return exists;
} }
@ -90,17 +88,17 @@ static inline void loadCustomVerString(u16 *out, u32 *verStringSize, u32 current
IFile file; IFile file;
if(R_SUCCEEDED(openLumaFile(&file, paths[currentNand]))) if(R_FAILED(openLumaFile(&file, paths[currentNand]))) return;
{
u64 fileSize; u64 fileSize;
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize <= 62) if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > 62) goto exit;
{
u8 buf[fileSize]; u8 buf[62];
u64 total; u64 total;
if(R_SUCCEEDED(IFile_Read(&file, &total, buf, fileSize))) if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) goto exit;
{
static const u8 bom[] = {0xEF, 0xBB, 0xBF}; static const u8 bom[] = {0xEF, 0xBB, 0xBF};
u32 finalSize = 0; u32 finalSize = 0;
@ -131,12 +129,10 @@ static inline void loadCustomVerString(u16 *out, u32 *verStringSize, u32 current
if(finalSize > 5 && finalSize < 19) out[finalSize++] = 0; if(finalSize > 5 && finalSize < 19) out[finalSize++] = 0;
*verStringSize = finalSize * 2; *verStringSize = finalSize * 2;
} }
}
}
exit:
IFile_Close(&file); IFile_Close(&file);
} }
}
static inline u32 loadTitleCodeSection(u64 progId, u8 *code, u32 size) static inline u32 loadTitleCodeSection(u64 progId, u8 *code, u32 size)
{ {
@ -147,10 +143,10 @@ static inline u32 loadTitleCodeSection(u64 progId, u8 *code, u32 size)
progIdToStr(path + 35, progId); progIdToStr(path + 35, progId);
IFile file; IFile file;
u32 ret = 0;
if(R_SUCCEEDED(openLumaFile(&file, path))) if(R_FAILED(openLumaFile(&file, path))) return 0;
{
u32 ret;
u64 fileSize; u64 fileSize;
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = 1; if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = 1;
@ -159,10 +155,10 @@ static inline u32 loadTitleCodeSection(u64 progId, u8 *code, u32 size)
u64 total; u64 total;
if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) ret = 1; if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) ret = 1;
else ret = 0;
} }
IFile_Close(&file); IFile_Close(&file);
}
return ret; return ret;
} }
@ -176,21 +172,27 @@ static inline u32 loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId
progIdToStr(path + 29, progId); progIdToStr(path + 29, progId);
IFile file; IFile file;
u32 ret = 0;
if(R_SUCCEEDED(openLumaFile(&file, path))) if(R_FAILED(openLumaFile(&file, path))) return 0;
{
u32 ret;
u64 fileSize; u64 fileSize;
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8) ret = 1; if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8)
else
{ {
char buf[fileSize]; ret = 1;
goto exit;
}
char buf[8];
u64 total; u64 total;
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) ret = 1; if(R_FAILED(IFile_Read(&file, &total, buf, fileSize)))
else
{ {
ret = 1;
goto exit;
}
u32 i, u32 i,
j; j;
@ -217,11 +219,10 @@ static inline u32 loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId
} }
if(i == 7 || j == 12) ret = 1; if(i == 7 || j == 12) ret = 1;
} else ret = 0;
}
exit:
IFile_Close(&file); IFile_Close(&file);
}
return ret; return ret;
} }
@ -238,15 +239,14 @@ static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4) for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4)
{ {
if(*(u32 *)pos == 0xD8A103F9) if(*(u32 *)pos != 0xD8A103F9) continue;
{
for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++) for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++)
if(*l <= 0x10000000) possible[n++] = *l; if(*l <= 0x10000000) possible[n++] = *l;
} }
}
if(n > 0) if(!n) return NULL;
{
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4) for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4)
{ {
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082}; static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
@ -254,8 +254,8 @@ static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want //There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos; u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1]) if(cmp[0] != CFGU_GetConfigInfoBlk2_endPattern[0] || cmp[1] != CFGU_GetConfigInfoBlk2_endPattern[1]) continue;
{
*CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2); *CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2);
for(u32 i = 0; i < n; i++) for(u32 i = 0; i < n; i++)
@ -263,8 +263,6 @@ static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
CFGU_GetConfigInfoBlk2_endPos += 4; CFGU_GetConfigInfoBlk2_endPos += 4;
} }
}
}
return NULL; return NULL;
} }
@ -277,16 +275,16 @@ static inline u32 patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFG
CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D; CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D;
CFGU_GetConfigInfoBlk2_startPos -= 4); CFGU_GetConfigInfoBlk2_startPos -= 4);
if(CFGU_GetConfigInfoBlk2_startPos >= code) if(CFGU_GetConfigInfoBlk2_startPos < code) return 1;
{
for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4) for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4)
{ {
if(*(u32 *)languageBlkIdPos == 0xA0002) if(*(u32 *)languageBlkIdPos != 0xA0002) continue;
{
for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough
{ {
if(instr[3] == 0xEB) //We're looking for BL if(instr[3] != 0xEB) continue; //We're looking for BL
{
u8 *calledFunction = instr; u8 *calledFunction = instr;
u32 i = 0; u32 i = 0;
bool found; bool found;
@ -299,12 +297,7 @@ static inline u32 patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFG
calledFunction += offset; calledFunction += offset;
found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos; if(calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos)
i++;
}
while(i < 2 && !found && calledFunction[3] == 0xEA);
if(found)
{ {
*((u32 *)instr - 1) = 0xE3A00000 | languageId; //mov r0, sp => mov r0, =languageId *((u32 *)instr - 1) = 0xE3A00000 | languageId; //mov r0, sp => mov r0, =languageId
*(u32 *)instr = 0xE5CD0000; //bl CFGU_GetConfigInfoBlk2 => strb r0, [sp] *(u32 *)instr = 0xE5CD0000; //bl CFGU_GetConfigInfoBlk2 => strb r0, [sp]
@ -313,9 +306,10 @@ static inline u32 patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFG
//We're done //We're done
return 0; return 0;
} }
i++;
} }
} while(i < 2 && !found && calledFunction[3] == 0xEA);
}
} }
} }
@ -330,8 +324,8 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa
u32 *cmp = (u32 *)cmdPos; u32 *cmp = (u32 *)cmdPos;
if(*cmp == cfgSecureInfoGetRegionCmdPattern[1]) if(*cmp != cfgSecureInfoGetRegionCmdPattern[1]) continue;
{
for(u32 i = 1; i < 3; i++) for(u32 i = 1; i < 3; i++)
if((*(cmp - i) & 0xFFFF0FFF) == cfgSecureInfoGetRegionCmdPattern[0] && *((u16 *)cmdPos + 5) == 0xE59F && if((*(cmp - i) & 0xFFFF0FFF) == cfgSecureInfoGetRegionCmdPattern[0] && *((u16 *)cmdPos + 5) == 0xE59F &&
*(u32 *)(cmdPos + 16 + *((u16 *)cmdPos + 4)) == CFGUHandleOffset) *(u32 *)(cmdPos + 16 + *((u16 *)cmdPos + 4)) == CFGUHandleOffset)
@ -346,12 +340,10 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa
} }
} }
} }
}
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
{ {
loadCFWInfo(); loadCFWInfo();
u32 res = 0;
if(((progId == 0x0004003000008F02LL || //USA Home Menu if(((progId == 0x0004003000008F02LL || //USA Home Menu
progId == 0x0004003000008202LL || //JPN Home Menu progId == 0x0004003000008202LL || //JPN Home Menu
@ -375,7 +367,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
sizeof(pattern), -31, sizeof(pattern), -31,
patch, patch,
sizeof(patch), 1 sizeof(patch), 1
)) res++; )) goto error;
} }
else if(progId == 0x0004013000003202LL) //FRIENDS else if(progId == 0x0004013000003202LL) //FRIENDS
@ -388,10 +380,10 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
u8 *off = memsearch(code, pattern, size, sizeof(pattern)); u8 *off = memsearch(code, pattern, size, sizeof(pattern));
if(off == NULL) res++; if(off == NULL) goto error;
//Allow online access to work with old friends modules //Allow online access to work with old friends modules
else if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer; if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer;
} }
else if((progId == 0x0004001000021000LL || //USA MSET else if((progId == 0x0004001000021000LL || //USA MSET
@ -442,7 +434,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
sizeof(pattern) - 2, 0, sizeof(pattern) - 2, 0,
patch, patch,
patchSize, 1 patchSize, 1
)) res++; )) goto error;
} }
else if(progId == 0x0004013000008002LL) //NS else if(progId == 0x0004013000008002LL) //NS
@ -464,7 +456,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
sizeof(patch), 2 sizeof(patch), 2
); );
if(ret == 0 || (ret == 1 && progVer > 0xB)) res++; if(ret == 0 || (ret == 1 && progVer > 0xB)) goto error;
} }
if(LOADERFLAG(ISN3DS)) if(LOADERFLAG(ISN3DS))
@ -479,9 +471,8 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
u32 *off = (u32 *)memsearch(code, pattern, size, sizeof(pattern)); u32 *off = (u32 *)memsearch(code, pattern, size, sizeof(pattern));
if(off == NULL) res++; if(off == NULL) goto error;
else
{
//Patch N3DS CPU Clock and L2 cache setting //Patch N3DS CPU Clock and L2 cache setting
*(off - 4) = *(off - 3); *(off - 4) = *(off - 3);
*(off - 3) = *(off - 1); *(off - 3) = *(off - 1);
@ -490,7 +481,6 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
} }
} }
} }
}
else if(progId == 0x0004013000001702LL) //CFG else if(progId == 0x0004013000001702LL) //CFG
{ {
@ -507,7 +497,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
sizeof(pattern), 0, sizeof(pattern), 0,
patch, patch,
sizeof(patch), 1 sizeof(patch), 1
)) res++; )) goto error;
if(secureInfoExists()) if(secureInfoExists())
{ {
@ -520,7 +510,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
sizeof(pattern) - 2, 22, sizeof(pattern) - 2, 22,
patch, patch,
sizeof(patch) - 2, 2 sizeof(patch) - 2, 2
) != 2) res++; ) != 2) goto error;
} }
} }
@ -539,28 +529,25 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 //mov r0, #0; bx lr 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 //mov r0, #0; bx lr
}; };
//Disable CRR0 signature (RSA2048 with SHA256) check //Disable CRR0 signature (RSA2048 with SHA256) check and CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
if(!patchMemory(code, size, if(!patchMemory(code, size,
pattern, pattern,
sizeof(pattern), -9, sizeof(pattern), -9,
patch, patch,
sizeof(patch), 1 sizeof(patch), 1
)) res++; ) ||
!patchMemory(code, size,
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
if(!patchMemory(code, size,
pattern2, pattern2,
sizeof(pattern2), 1, sizeof(pattern2), 1,
patch, patch,
sizeof(patch), 1 sizeof(patch), 1
)) res++; ) ||
!patchMemory(code, size,
if(!patchMemory(code, size,
pattern3, pattern3,
sizeof(pattern3), -2, sizeof(pattern3), -2,
patch, patch,
sizeof(patch), 1 sizeof(patch), 1
)) res++; )) goto error;
} }
else if(progId == 0x0004003000008A02LL && MULTICONFIG(DEVOPTIONS) == 1) //ErrDisp else if(progId == 0x0004003000008A02LL && MULTICONFIG(DEVOPTIONS) == 1) //ErrDisp
@ -581,39 +568,37 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
sizeof(pattern), -1, sizeof(pattern), -1,
patch, patch,
sizeof(patch), 1 sizeof(patch), 1
)) res++; ) ||
patchMemory(code, size,
if(patchMemory(code, size,
pattern2, pattern2,
sizeof(pattern2), 0, sizeof(pattern2), 0,
patch, patch,
sizeof(patch), 3 sizeof(patch), 3
) != 3) res++; ) != 3) goto error;
} }
else if(CONFIG(USELANGEMUANDCODE) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000) else if(CONFIG(USELANGEMUANDCODE) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
{ {
//External .code section loading
res += loadTitleCodeSection(progId, code, size);
//Language emulation
u8 regionId = 0xFF, u8 regionId = 0xFF,
languageId; languageId;
res += loadTitleLocaleConfig(progId, &regionId, &languageId); if(!loadTitleLocaleConfig(progId, &regionId, &languageId) ||
!loadTitleCodeSection(progId, code, size)) goto error;
if(!res && regionId != 0xFF) if(regionId != 0xFF)
{ {
u32 CFGUHandleOffset; u32 CFGUHandleOffset;
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset); u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
if(CFGU_GetConfigInfoBlk2_endPos == NULL) res++; if(CFGU_GetConfigInfoBlk2_endPos == NULL ||
else patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos)) goto error;
{
res += patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
patchCfgGetRegion(code, size, regionId, CFGUHandleOffset); patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
} }
} }
}
if(res != 0) svcBreak(USERBREAK_ASSERT); return;
error:
svcBreak(USERBREAK_ASSERT);
while(true);
} }

View File

@ -33,27 +33,25 @@ CfgData configData;
bool readConfig(void) bool readConfig(void)
{ {
bool ret;
if(fileRead(&configData, CONFIG_FILE, sizeof(CfgData)) != sizeof(CfgData) || if(fileRead(&configData, CONFIG_FILE, sizeof(CfgData)) != sizeof(CfgData) ||
memcmp(configData.magic, "CONF", 4) != 0 || memcmp(configData.magic, "CONF", 4) != 0 ||
configData.formatVersionMajor != CONFIG_VERSIONMAJOR || configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
configData.formatVersionMinor != CONFIG_VERSIONMINOR) configData.formatVersionMinor != CONFIG_VERSIONMINOR)
{ {
configData.config = 0; configData.config = 0;
ret = false;
}
else ret = true;
return ret; return false;
}
return true;
} }
void writeConfig(ConfigurationStatus needConfig, u32 configTemp) void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
{ {
/* If the configuration is different from previously, overwrite it. /* If the configuration is different from previously, overwrite it.
Just the no-forcing flag being set is not enough */ Just the no-forcing flag being set is not enough */
if(needConfig == CREATE_CONFIGURATION || (configTemp & 0xFFFFFF7F) != configData.config) if(needConfig != CREATE_CONFIGURATION && (configTemp & 0xFFFFFF7F) == configData.config) return;
{
if(needConfig == CREATE_CONFIGURATION) if(needConfig == CREATE_CONFIGURATION)
{ {
memcpy(configData.magic, "CONF", 4); memcpy(configData.magic, "CONF", 4);
@ -67,7 +65,6 @@ void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData))) if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
error("Error writing the configuration file"); error("Error writing the configuration file");
} }
}
void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
{ {
@ -249,21 +246,20 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
//Display all the multiple choice options in white //Display all the multiple choice options in white
for(u32 i = 0; i < multiOptionsAmount; i++) for(u32 i = 0; i < multiOptionsAmount; i++)
{ {
if(multiOptions[i].visible) if(!multiOptions[i].visible) continue;
{
multiOptions[i].posY = endPos + SPACING_Y; multiOptions[i].posY = endPos + SPACING_Y;
endPos = drawString(multiOptionsText[i], true, 10, multiOptions[i].posY, COLOR_WHITE); endPos = drawString(multiOptionsText[i], true, 10, multiOptions[i].posY, COLOR_WHITE);
drawCharacter(selected, true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE); drawCharacter(selected, true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
} }
}
endPos += SPACING_Y / 2; endPos += SPACING_Y / 2;
//Display all the normal options in white except for the first one //Display all the normal options in white except for the first one
for(u32 i = 0, color = COLOR_RED; i < singleOptionsAmount; i++) for(u32 i = 0, color = COLOR_RED; i < singleOptionsAmount; i++)
{ {
if(singleOptions[i].visible) if(!singleOptions[i].visible) continue;
{
singleOptions[i].posY = endPos + SPACING_Y; singleOptions[i].posY = endPos + SPACING_Y;
endPos = drawString(singleOptionsText[i], true, 10, singleOptions[i].posY, color); endPos = drawString(singleOptionsText[i], true, 10, singleOptions[i].posY, color);
if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color); if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color);
@ -275,21 +271,21 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
color = COLOR_WHITE; color = COLOR_WHITE;
} }
} }
}
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE); drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
u32 pressed = 0;
//Boring configuration menu //Boring configuration menu
while(pressed != BUTTON_START) while(true)
{ {
u32 pressed;
do do
{ {
pressed = waitInput(true); pressed = waitInput(true);
} }
while(!(pressed & MENU_BUTTONS)); while(!(pressed & MENU_BUTTONS));
if(pressed == BUTTON_START) break;
if(pressed != BUTTON_A) if(pressed != BUTTON_A)
{ {
//Remember the previously selected option //Remember the previously selected option
@ -319,23 +315,21 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
if(selectedOption < multiOptionsAmount) if(selectedOption < multiOptionsAmount)
{ {
if(multiOptions[selectedOption].visible) if(!multiOptions[selectedOption].visible) continue;
{
isMultiOption = true; isMultiOption = true;
break; break;
} }
}
else else
{ {
singleSelected = selectedOption - multiOptionsAmount; singleSelected = selectedOption - multiOptionsAmount;
if(singleOptions[singleSelected].visible) if(!singleOptions[singleSelected].visible) continue;
{
isMultiOption = false; isMultiOption = false;
break; break;
} }
} }
}
if(selectedOption == oldSelectedOption) continue; if(selectedOption == oldSelectedOption) continue;

View File

@ -401,11 +401,7 @@ void set6x7xKeys(void)
bool decryptExeFs(Cxi *cxi) bool decryptExeFs(Cxi *cxi)
{ {
bool isCxi; if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return false;
if(memcmp(cxi->ncch.magic, "NCCH", 4) == 0)
{
isCxi = true;
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200; u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200; u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
@ -419,19 +415,13 @@ bool decryptExeFs(Cxi *cxi)
aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x2C); aes_use_keyslot(0x2C);
aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
else isCxi = false;
return isCxi && memcmp(cxi, "FIRM", 4) == 0; return memcmp(cxi, "FIRM", 4) == 0;
} }
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize) bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
{ {
bool isTicket; if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return false;
if(memcmp(ticket->sigIssuer, "Root", 4) == 0)
{
isTicket = true;
__attribute__((aligned(4))) const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C}; __attribute__((aligned(4))) const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
__attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE], __attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE],
@ -448,10 +438,8 @@ bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x16); aes_use_keyslot(0x16);
aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
else isTicket = false;
return isTicket && decryptExeFs(cxi); return decryptExeFs(cxi);
} }
void kernel9Loader(Arm9Bin *arm9Section) void kernel9Loader(Arm9Bin *arm9Section)
@ -550,11 +538,11 @@ void computePinHash(u8 *outbuf, const u8 *inbuf)
void backupAndRestoreShaHash(bool isRestore) void backupAndRestoreShaHash(bool isRestore)
{ {
if(!ISA9LH) return;
static bool didShaHashBackup = false; static bool didShaHashBackup = false;
__attribute__((aligned(4))) static u8 shaHashBackup[SHA_256_HASH_SIZE]; __attribute__((aligned(4))) static u8 shaHashBackup[SHA_256_HASH_SIZE];
if(ISA9LH)
{
if(isRestore) if(isRestore)
{ {
if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup)); if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup));
@ -565,4 +553,3 @@ void backupAndRestoreShaHash(bool isRestore)
didShaHashBackup = true; didShaHashBackup = true;
} }
} }
}

View File

@ -38,30 +38,23 @@ bool loadSplash(void)
*bottomSplashFile = "splashbottom.bin"; *bottomSplashFile = "splashbottom.bin";
bool isTopSplashValid = getFileSize(topSplashFile) == SCREEN_TOP_FBSIZE, bool isTopSplashValid = getFileSize(topSplashFile) == SCREEN_TOP_FBSIZE,
isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE, isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE;
ret;
//Don't delay boot nor init the screens if no splash images or invalid splash images are on the SD //Don't delay boot nor init the screens if no splash images or invalid splash images are on the SD
if(!isTopSplashValid && !isBottomSplashValid) ret = false; if(!isTopSplashValid && !isBottomSplashValid) return false;
else
{
initScreens(); initScreens();
clearScreens(true); clearScreens(true);
if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE; if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE;
if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE; if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
if(!isTopSplashValid && !isBottomSplashValid) ret = false; if(!isTopSplashValid && !isBottomSplashValid) return false;
else
{
swapFramebuffers(true); swapFramebuffers(true);
wait(false, 3ULL); wait(false, 3ULL);
ret = true; return true;
}
}
return ret;
} }
void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color) void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color)

View File

@ -36,7 +36,6 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
static u8 __attribute__((aligned(4))) temp[0x200]; static u8 __attribute__((aligned(4))) temp[0x200];
static u32 nandSize = 0, static u32 nandSize = 0,
fatStart; fatStart;
bool found = false;
if(!nandSize) if(!nandSize)
{ {
@ -45,7 +44,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
fatStart = *(u32 *)(temp + 0x1C6); //First sector of the FAT partition fatStart = *(u32 *)(temp + 0x1C6); //First sector of the FAT partition
} }
for(u32 i = 0; i < 3 && !found; i++) for(u32 i = 0; i < 3; i++)
{ {
static const u32 roundedMinsizes[] = {0x1D8000, 0x26E000}; static const u32 roundedMinsizes[] = {0x1D8000, 0x26E000};
@ -72,7 +71,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
{ {
emuOffset = nandOffset + 1; emuOffset = nandOffset + 1;
*emuHeader = nandOffset + 1; *emuHeader = nandOffset + 1;
found = true; return;
} }
//Check for Gateway EmuNAND //Check for Gateway EmuNAND
@ -80,7 +79,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
{ {
emuOffset = nandOffset; emuOffset = nandOffset;
*emuHeader = nandOffset + nandSize; *emuHeader = nandOffset + nandSize;
found = true; return;
} }
} }
@ -88,8 +87,6 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
} }
//Fallback to the first EmuNAND if there's no second/third/fourth one, or to SysNAND if there isn't any //Fallback to the first EmuNAND if there's no second/third/fourth one, or to SysNAND if there isn't any
if(!found)
{
if(*nandType != FIRMWARE_EMUNAND) if(*nandType != FIRMWARE_EMUNAND)
{ {
*nandType = FIRMWARE_EMUNAND; *nandType = FIRMWARE_EMUNAND;
@ -97,105 +94,80 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
} }
else *nandType = FIRMWARE_SYSNAND; else *nandType = FIRMWARE_SYSNAND;
} }
}
static inline u32 getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space) static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
{ {
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
u32 ret;
//Looking for the last free space before Process9 //Looking for the last free space before Process9
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern)); *freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
if(*freeK9Space == NULL) ret = 1; if(*freeK9Space == NULL) return false;
else
{
*freeK9Space += 0x455; *freeK9Space += 0x455;
ret = 0; return true;
}
return ret;
} }
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc) static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
{ {
//Look for struct code //Look for struct code
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
u32 ret;
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
*sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD); *sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
ret = 0; return 0;
}
return ret;
} }
static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset) static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
{ {
//Look for read/write code //Look for read/write code
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
u32 ret;
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(readOffset == NULL) ret = 1; if(readOffset == NULL) return 1;
else
{
readOffset -= 3; readOffset -= 3;
u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)); u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern));
if(writeOffset == NULL) ret = 1; if(writeOffset == NULL) return 1;
else
{
writeOffset -= 3; writeOffset -= 3;
*readOffset = *writeOffset = 0x4C00; *readOffset = *writeOffset = 0x4C00;
readOffset[1] = writeOffset[1] = 0x47A0; readOffset[1] = writeOffset[1] = 0x47A0;
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset; ((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset;
ret = 0; return 0;
}
}
return ret;
} }
static inline u32 patchMpu(u8 *pos, u32 size) static inline u32 patchMpu(u8 *pos, u32 size)
{ {
//Look for MPU pattern //Look for MPU pattern
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[1] = 0x0036; off[1] = 0x0036;
off[0xC] = off[0x12] = 0x0603; off[0xC] = off[0x12] = 0x0603;
ret = 0; return 0;
}
return ret;
} }
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u32 emuHeader, u8 *kernel9Address) u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u32 emuHeader, u8 *kernel9Address)
{ {
u8 *freeK9Space;
if(!getFreeK9Space(arm9Section, kernel9Size, &freeK9Space)) return 1;
u32 ret = 0; u32 ret = 0;
u8 *freeK9Space;
ret += getFreeK9Space(arm9Section, kernel9Size, &freeK9Space);
if(!ret)
{
//Copy EmuNAND code //Copy EmuNAND code
memcpy(freeK9Space, emunand_bin, emunand_bin_size); memcpy(freeK9Space, emunand_bin, emunand_bin_size);
@ -217,7 +189,6 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce
//Set MPU //Set MPU
ret += patchMpu(arm9Section, kernel9Size); ret += patchMpu(arm9Section, kernel9Size);
}
return ret; return ret;
} }

View File

@ -47,7 +47,6 @@ void installArm9Handlers(void)
u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset) u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset)
{ {
u32 ret;
u32 *endPos = exceptionsPage + 0x400; u32 *endPos = exceptionsPage + 0x400;
u32 *initFPU; u32 *initFPU;
@ -59,9 +58,8 @@ u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffse
u32 *mcuReboot; u32 *mcuReboot;
for(mcuReboot = exceptionsPage; mcuReboot < endPos && *mcuReboot != 0xE3A0A0C2; mcuReboot++); for(mcuReboot = exceptionsPage; mcuReboot < endPos && *mcuReboot != 0xE3A0A0C2; mcuReboot++);
if(initFPU == endPos || freeSpace == endPos || mcuReboot == endPos || *(u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 36) != 0xFFFFFFFF) ret = 1; if(initFPU == endPos || freeSpace == endPos || mcuReboot == endPos || *(u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 36) != 0xFFFFFFFF) return 1;
else
{
initFPU += 3; initFPU += 3;
mcuReboot -= 2; mcuReboot -= 2;
@ -84,18 +82,15 @@ u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffse
} }
} }
ret = 0; return 0;
}
return ret;
} }
void detectAndProcessExceptionDumps(void) void detectAndProcessExceptionDumps(void)
{ {
volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000; volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000;
if(dumpHeader->magic[0] == 0xDEADC0DE && dumpHeader->magic[1] == 0xDEADCAFE && (dumpHeader->processor == 9 || dumpHeader->processor == 11)) if(dumpHeader->magic[0] != 0xDEADC0DE || dumpHeader->magic[1] == 0xDEADCAFE || (dumpHeader->processor != 9 && dumpHeader->processor != 11)) return;
{
const vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader)); const vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader));
const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize; const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize;
const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize; const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize;
@ -207,4 +202,3 @@ void detectAndProcessExceptionDumps(void)
waitInput(false); waitInput(false);
mcuPowerOff(); mcuPowerOff();
} }
}

View File

@ -36,7 +36,7 @@
static Firm *firm = (Firm *)0x24000000; static Firm *firm = (Firm *)0x24000000;
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode) static inline bool loadFirmFromStorage(FirmwareType firmType)
{ {
const char *firmwareFiles[] = { const char *firmwareFiles[] = {
"firmware.bin", "firmware.bin",
@ -53,6 +53,30 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
"cetk_sysupdater" "cetk_sysupdater"
}; };
u32 firmSize = fileRead(firm, firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200);
if(!firmSize) return false;
if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid.");
if(memcmp(firm, "FIRM", 4) != 0)
{
u8 cetk[0xA50];
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk) ||
!decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize))
error("The FIRM in /luma is encrypted or corrupted.");
}
//Check that the FIRM is right for the console from the ARM9 section address
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
error("The FIRM in /luma is not for this console.");
return true;
}
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
{
//Load FIRM from CTRNAND //Load FIRM from CTRNAND
u32 firmVersion = firmRead(firm, (u32)*firmType); u32 firmVersion = firmRead(firm, (u32)*firmType);
@ -77,32 +101,8 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
else if(firmVersion < 0x25) mustLoadFromStorage = true; else if(firmVersion < 0x25) mustLoadFromStorage = true;
} }
if(loadFromStorage || mustLoadFromStorage) if((loadFromStorage || mustLoadFromStorage) && loadFirmFromStorage(*firmType)) firmVersion = 0xFFFFFFFF;
{ else
u32 firmSize = fileRead(firm, *firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)*firmType], 0x400000 + sizeof(Cxi) + 0x200);
if(firmSize > 0)
{
if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid.");
if(memcmp(firm, "FIRM", 4) != 0)
{
u8 cetk[0xA50];
if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) != sizeof(cetk) ||
!decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize))
error("The FIRM in /luma is encrypted or corrupted.");
}
//Check that the FIRM is right for the console from the ARM9 section address
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
error("The FIRM in /luma is not for this console.");
firmVersion = 0xFFFFFFFF;
}
}
if(firmVersion != 0xFFFFFFFF)
{ {
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot."); if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot.");
if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted."); if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted.");
@ -310,10 +310,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200; srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200;
const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle; const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
bool loadedModule; if(loadFromStorage)
if(!loadFromStorage) loadedModule = false;
else
{ {
char fileName[24] = "sysmodules/"; char fileName[24] = "sysmodules/";
@ -323,8 +320,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
dstModuleSize = getFileSize(fileName); dstModuleSize = getFileSize(fileName);
if(dstModuleSize == 0) loadedModule = false; if(dstModuleSize != 0)
else
{ {
if(dstModuleSize > maxModuleSize) error(extModuleSizeError); if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
@ -334,12 +330,10 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0) memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
error("An external FIRM module is invalid or corrupted."); error("An external FIRM module is invalid or corrupted.");
loadedModule = true; continue;
} }
} }
if(!loadedModule)
{
const u8 *module; const u8 *module;
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0) if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
@ -358,7 +352,6 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
memcpy(dst, module, dstModuleSize); memcpy(dst, module, dstModuleSize);
} }
} }
}
void launchFirm(FirmwareType firmType, bool loadFromStorage) void launchFirm(FirmwareType firmType, bool loadFromStorage)
{ {

View File

@ -66,17 +66,16 @@ bool mountFs(bool isSd, bool switchToCtrNand)
u32 fileRead(void *dest, const char *path, u32 maxSize) u32 fileRead(void *dest, const char *path, u32 maxSize)
{ {
FIL file; FIL file;
if(f_open(&file, path, FA_READ) != FR_OK) return 0;
u32 ret; u32 ret;
if(f_open(&file, path, FA_READ) != FR_OK) ret = 0;
else
{
u32 size = f_size(&file); u32 size = f_size(&file);
if(dest == NULL) ret = size; if(dest == NULL) ret = size;
else if(size <= maxSize) else if(size <= maxSize)
f_read(&file, dest, size, (unsigned int *)&ret); f_read(&file, dest, size, (unsigned int *)&ret);
f_close(&file); f_close(&file);
}
return ret; return ret;
} }
@ -89,7 +88,6 @@ 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)
{ {
FIL file; FIL file;
bool ret;
switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS)) switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS))
{ {
@ -100,8 +98,7 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
f_truncate(&file); f_truncate(&file);
f_close(&file); f_close(&file);
ret = (u32)written == size; return (u32)written == size;
break;
} }
case FR_NO_PATH: case FR_NO_PATH:
for(u32 i = 1; path[i] != 0; i++) for(u32 i = 1; path[i] != 0; i++)
@ -113,14 +110,10 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
f_mkdir(folder); f_mkdir(folder);
} }
ret = fileWrite(buffer, path, size); return fileWrite(buffer, path, size);
break;
default: default:
ret = false; return false;
break;
} }
return ret;
} }
void fileDelete(const char *path) void fileDelete(const char *path)
@ -158,22 +151,20 @@ void loadPayload(u32 pressed, const char *payloadPath)
result = f_findfirst(&dir, &info, path, pattern); result = f_findfirst(&dir, &info, path, pattern);
if(result == FR_OK) if(result != FR_OK) return;
{
f_closedir(&dir); f_closedir(&dir);
if(info.fname[0] != 0) if(!info.fname[0]) return;
{
concatenateStrings(path, "/"); concatenateStrings(path, "/");
concatenateStrings(path, info.altname); concatenateStrings(path, info.altname);
payloadSize = fileRead(payloadAddress, path, maxPayloadSize); payloadSize = fileRead(payloadAddress, path, maxPayloadSize);
} }
}
}
else payloadSize = fileRead(payloadAddress, payloadPath, maxPayloadSize); else payloadSize = fileRead(payloadAddress, payloadPath, maxPayloadSize);
if(payloadSize > 0) if(!payloadSize) return;
{
memcpy(loaderAddress, loader_bin, loader_bin_size); memcpy(loaderAddress, loader_bin, loader_bin_size);
loaderAddress[1] = payloadSize; loaderAddress[1] = payloadSize;
@ -185,35 +176,34 @@ void loadPayload(u32 pressed, const char *payloadPath)
((void (*)())loaderAddress)(); ((void (*)())loaderAddress)();
} }
}
void payloadMenu(void) void payloadMenu(void)
{ {
DIR dir; DIR dir;
char path[62] = "payloads"; char path[62] = "payloads";
if(f_opendir(&dir, path) == FR_OK) if(f_opendir(&dir, path) != FR_OK) return;
{
FILINFO info; FILINFO info;
u32 payloadNum = 0; u32 payloadNum = 0;
char payloadList[20][49]; char payloadList[20][49];
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 20) while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 20)
if(info.fname[0] != '.' && memcmp(info.altname + 8, ".BIN", 4) == 0)
{ {
if(info.fname[0] == '.' || memcmp(info.altname + 8, ".BIN", 4) != 0) continue;
u32 nameLength = strlen(info.fname) - 4; u32 nameLength = strlen(info.fname) - 4;
if(nameLength < 49)
{ if(nameLength > 48) continue;
memcpy(payloadList[payloadNum], info.fname, nameLength); memcpy(payloadList[payloadNum], info.fname, nameLength);
payloadList[payloadNum][nameLength] = 0; payloadList[payloadNum][nameLength] = 0;
payloadNum++; payloadNum++;
} }
}
f_closedir(&dir); f_closedir(&dir);
if(payloadNum > 0) if(!payloadNum) return;
{
initScreens(); initScreens();
drawString("Luma3DS chainloader", true, 10, 10, COLOR_TITLE); drawString("Luma3DS chainloader", true, 10, 10, COLOR_TITLE);
@ -274,8 +264,6 @@ void payloadMenu(void)
while(HID_PAD & MENU_BUTTONS); while(HID_PAD & MENU_BUTTONS);
wait(false, 2ULL); wait(false, 2ULL);
} }
}
}
u32 firmRead(void *dest, u32 firmType) u32 firmRead(void *dest, u32 firmType)
{ {
@ -292,15 +280,15 @@ u32 firmRead(void *dest, u32 firmType)
DIR dir; DIR dir;
u32 firmVersion = 0xFFFFFFFF; u32 firmVersion = 0xFFFFFFFF;
if(f_opendir(&dir, path) == FR_OK) if(f_opendir(&dir, path) != FR_OK) goto exit;
{
FILINFO info; FILINFO info;
//Parse the target directory //Parse the target directory
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0) while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
{ {
//Not a cxi //Not a cxi
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue; if(info.fname[9] == 'a' && strlen(info.fname) != 12) continue;
u32 tempVersion = hexAtoi(info.altname, 8); u32 tempVersion = hexAtoi(info.altname, 8);
@ -310,8 +298,8 @@ u32 firmRead(void *dest, u32 firmType)
f_closedir(&dir); f_closedir(&dir);
if(firmVersion != 0xFFFFFFFF) if(firmVersion == 0xFFFFFFFF) goto exit;
{
//Complete the string with the .app name //Complete the string with the .app name
concatenateStrings(path, "/00000000.app"); concatenateStrings(path, "/00000000.app");
@ -319,9 +307,8 @@ u32 firmRead(void *dest, u32 firmType)
hexItoa(firmVersion, path + 35, 8, false); hexItoa(firmVersion, path + 35, 8, false);
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF; if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF;
}
}
exit:
return firmVersion; return firmVersion;
} }

View File

@ -78,9 +78,10 @@ void main(void)
nandType = (FirmwareSource)BOOTCFG_NAND; nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM; firmSource = (FirmwareSource)BOOTCFG_FIRM;
isA9lhInstalled = BOOTCFG_A9LH != 0; isA9lhInstalled = BOOTCFG_A9LH != 0;
goto boot;
} }
else
{
if(ISA9LH) if(ISA9LH)
{ {
detectAndProcessExceptionDumps(); detectAndProcessExceptionDumps();
@ -104,25 +105,24 @@ void main(void)
{ {
nandType = FIRMWARE_SYSNAND; nandType = FIRMWARE_SYSNAND;
firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM; firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing //Flag to prevent multiple boot options-forcing
configTemp |= 1 << 7; configTemp |= 1 << 7;
goto boot;
} }
/* Else, force the last used boot options unless a button is pressed /* Else, force the last used boot options unless a button is pressed
or the no-forcing flag is set */ or the no-forcing flag is set */
else if(!pressed && !BOOTCFG_NOFORCEFLAG) if(!pressed && !BOOTCFG_NOFORCEFLAG)
{ {
nandType = (FirmwareSource)BOOTCFG_NAND; nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM; firmSource = (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
goto boot;
} }
} }
//Boot options aren't being forced
if(needConfig != DONT_CONFIGURE)
{
u32 pinMode = MULTICONFIG(PIN); u32 pinMode = MULTICONFIG(PIN);
bool pinExists = pinMode != 0 && verifyPin(pinMode); bool pinExists = pinMode != 0 && verifyPin(pinMode);
@ -150,9 +150,10 @@ void main(void)
while(HID_PAD & PIN_BUTTONS); while(HID_PAD & PIN_BUTTONS);
wait(false, 2ULL); wait(false, 2ULL);
} }
goto boot;
} }
else
{
u32 splashMode = MULTICONFIG(SPLASH); u32 splashMode = MULTICONFIG(SPLASH);
if(splashMode == 1 && loadSplash()) pressed = HID_PAD; if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
@ -215,9 +216,8 @@ void main(void)
if(nandType == FIRMWARE_EMUNAND) nandType = tempNand; if(nandType == FIRMWARE_EMUNAND) nandType = tempNand;
else firmSource = tempNand; else firmSource = tempNand;
} }
}
} boot:
}
//If we need to boot EmuNAND, make sure it exists //If we need to boot EmuNAND, make sure it exists
if(nandType != FIRMWARE_SYSNAND) if(nandType != FIRMWARE_SYSNAND)

View File

@ -35,6 +35,29 @@
#include "utils.h" #include "utils.h"
#include "../build/bundled.h" #include "../build/bundled.h"
static inline void pathChanger(u8 *pos)
{
const char *pathFile = "path.txt";
u32 pathSize = getFileSize(pathFile);
if(pathSize < 6 || pathSize > 57) return;
u8 path[pathSize];
fileRead(path, pathFile, pathSize);
if(path[pathSize - 1] == 0xA) pathSize--;
if(path[pathSize - 1] == 0xD) pathSize--;
if(pathSize < 6 || pathSize > 57 || path[0] != '/' || memcmp(&path[pathSize - 4], ".bin", 4) != 0) return;
u16 finalPath[pathSize];
for(u32 i = 0; i < pathSize; i++)
finalPath[i] = (u16)path[i];
u8 *posPath = memsearch(pos, u"sd", reboot_bin_size, 4) + 0xA;
memcpy(posPath, finalPath, pathSize * 2);
}
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
{ {
u8 *temp = memsearch(pos, "NCCH", size, 4); u8 *temp = memsearch(pos, "NCCH", size, 4);
@ -51,32 +74,24 @@ u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage) u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage)
{ {
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5},
bool res = true; pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
*arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); *arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
*freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2));
if(*arm11ExceptionsPage == NULL || *freeK11Space == NULL) error("Failed to get Kernel11 data.");
u32 *arm11SvcTable; u32 *arm11SvcTable;
if(*arm11ExceptionsPage == NULL) res = false;
else
{
*arm11ExceptionsPage -= 0xB; *arm11ExceptionsPage -= 0xB;
u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
u32 pointedInstructionVA = 0xFFFF0008 - svcOffset; u32 pointedInstructionVA = 0xFFFF0008 - svcOffset;
*baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case *baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case
arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address
while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL)
}
const u8 pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; (*freeK11Space)++;
*freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2));
if(*freeK11Space == NULL) res = false;
else (*freeK11Space)++;
if(!res) error("Failed to get Kernel11 data.");
return arm11SvcTable; return arm11SvcTable;
} }
@ -86,36 +101,28 @@ u32 patchSignatureChecks(u8 *pos, u32 size)
//Look for signature checks //Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2)); u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
if(off == NULL || temp == NULL) ret = 1; if(off == NULL || temp == NULL) return 1;
else
{
u16 *off2 = (u16 *)(temp - 1);
u16 *off2 = (u16 *)(temp - 1);
*off = off2[0] = 0x2000; *off = off2[0] = 0x2000;
off2[1] = 0x4770; off2[1] = 0x4770;
ret = 0; return 0;
}
return ret;
} }
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr) u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
{ {
//Look for firmlaunch code //Look for firmlaunch code
const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90}; const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90};
u32 ret;
u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off -= 0x13; off -= 0x13;
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 //Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
@ -128,165 +135,105 @@ u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4); u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
*pos_fopen = fOpenOffset; *pos_fopen = fOpenOffset;
ret = 0; if(CONFIG(USECUSTOMPATH)) pathChanger(off);
if(CONFIG(USECUSTOMPATH)) return 0;
{
const char *pathFile = "path.txt";
u32 pathSize = getFileSize(pathFile);
if(pathSize > 5 && pathSize < 58)
{
u8 path[pathSize];
fileRead(path, pathFile, pathSize);
if(path[pathSize - 1] == 0xA) pathSize--;
if(path[pathSize - 1] == 0xD) pathSize--;
if(pathSize > 5 && pathSize < 56 && path[0] == '/' && memcmp(&path[pathSize - 4], ".bin", 4) == 0)
{
u16 finalPath[pathSize];
for(u32 i = 0; i < pathSize; i++)
finalPath[i] = (u16)path[i];
u8 *pos_path = memsearch(off, u"sd", reboot_bin_size, 4) + 0xA;
memcpy(pos_path, finalPath, pathSize * 2);
}
}
}
}
return ret;
} }
u32 patchFirmWrites(u8 *pos, u32 size) u32 patchFirmWrites(u8 *pos, u32 size)
{ {
u32 ret;
//Look for FIRM writing code //Look for FIRM writing code
u8 *off = memsearch(pos, "exe:", size, 4); u8 *off = memsearch(pos, "exe:", size, 4);
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern)); u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern));
if(off2 == NULL) ret = 1; if(off2 == NULL) return 1;
else
{
off2[0] = 0x2000; off2[0] = 0x2000;
off2[1] = 0x46C0; off2[1] = 0x46C0;
ret = 0; return 0;
}
}
return ret;
} }
u32 patchOldFirmWrites(u8 *pos, u32 size) u32 patchOldFirmWrites(u8 *pos, u32 size)
{ {
//Look for FIRM writing code //Look for FIRM writing code
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB}; const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[0] = 0x2400; off[0] = 0x2400;
off[1] = 0xE01D; off[1] = 0xE01D;
ret = 0; return 0;
}
return ret;
} }
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion) u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion)
{ {
const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02}; const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02};
u32 ret;
u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = firmVersion == 0xFFFFFFFF ? 0 : 1; if(off == NULL) return firmVersion == 0xFFFFFFFF ? 0 : 1;
else
{
off++; off++;
memset32(off, 0, 8); //Zero out the first TitleID in the list //Zero out the first TitleID in the list
memset32(off, 0, 8);
ret = 0; return 0;
}
return ret;
} }
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size) u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x28, 0x2A, 0xD0, 0x08}; const u8 pattern[] = {0x28, 0x2A, 0xD0, 0x08};
u32 ret;
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) ret = 1; if(temp == NULL) return 1;
else
{
u16 *off = (u16 *)(temp - 1);
u16 *off = (u16 *)(temp - 1);
*off = 0x2001; //mov r0, #1 *off = 0x2001; //mov r0, #1
ret = 0; return 0;
}
return ret;
} }
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size) u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x07, 0xD1, 0x28, 0x7A}; const u8 pattern[] = {0x07, 0xD1, 0x28, 0x7A};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off--;
off--;
*off = 0x2001; //mov r0, #1 *off = 0x2001; //mov r0, #1
ret = 0; return 0;
}
return ret;
} }
u32 patchCheckForDevCommonKey(u8 *pos, u32 size) u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x03, 0x7C, 0x28, 0x00}; const u8 pattern[] = {0x03, 0x7C, 0x28, 0x00};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
*off = 0x2301; //mov r3, #1 *off = 0x2301; //mov r3, #1
ret = 0; return 0;
}
return ret;
} }
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space) u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space)
{ {
u32 ret = 0; if(arm11SvcTable[0x7B] != 0) return 0;
//Official implementation of svcBackdoor //Official implementation of svcBackdoor
const u8 svcBackdoor[] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff const u8 svcBackdoor[] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
@ -300,28 +247,20 @@ u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
0x11, 0xFF, 0x2F, 0xE1}; //bx r1 0x11, 0xFF, 0x2F, 0xE1}; //bx r1
if(!arm11SvcTable[0x7B]) if(*(u32 *)(*freeK11Space + sizeof(svcBackdoor) - 4) != 0xFFFFFFFF) return 1;
{
if(*(u32 *)(*freeK11Space + sizeof(svcBackdoor) - 4) != 0xFFFFFFFF) ret = 1;
else
{
memcpy(*freeK11Space, svcBackdoor, sizeof(svcBackdoor)); memcpy(*freeK11Space, svcBackdoor, sizeof(svcBackdoor));
arm11SvcTable[0x7B] = baseK11VA + *freeK11Space - pos; arm11SvcTable[0x7B] = baseK11VA + *freeK11Space - pos;
*freeK11Space += sizeof(svcBackdoor); *freeK11Space += sizeof(svcBackdoor);
}
}
return ret; return 0;
} }
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode) u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode)
{ {
u32 ret; if(*(u32 *)(*freeK11Space + svcGetCFWInfo_bin_size - 4) != 0xFFFFFFFF) return 1;
if(*(u32 *)(*freeK11Space + svcGetCFWInfo_bin_size - 4) != 0xFFFFFFFF) ret = 1;
else
{
memcpy(*freeK11Space, svcGetCFWInfo_bin, svcGetCFWInfo_bin_size); memcpy(*freeK11Space, svcGetCFWInfo_bin, svcGetCFWInfo_bin_size);
struct CfwInfo struct CfwInfo
@ -355,37 +294,30 @@ u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free
else isRelease = rev[4] == 0; else isRelease = rev[4] == 0;
if(isRelease) info->flags = 1; if(isRelease) info->flags = 1;
if(ISN3DS) info->flags |= 1 << 4; if(ISN3DS) info->flags |= 1 << 4;
if(isSafeMode) info->flags |= 1 << 5; if(isSafeMode) info->flags |= 1 << 5;
arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc
*freeK11Space += svcGetCFWInfo_bin_size; *freeK11Space += svcGetCFWInfo_bin_size;
ret = 0; return 0;
}
return ret;
} }
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C}; const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C};
u32 ret;
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) ret = 1; if(temp == NULL) return 1;
else
{
u32 *off = (u32 *)(temp - 0xA); u32 *off = (u32 *)(temp - 0xA);
for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40
{ {
//Discard everything that's not str rX, [r0, #imm](!) //Discard everything that's not str rX, [r0, #imm](!)
if((*off & 0xFE5F0000) == 0xE4000000) if((*off & 0xFE5F0000) != 0xE4000000) continue;
{
u32 rD = (*off >> 12) & 0xF, u32 rD = (*off >> 12) & 0xF,
offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1); offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1);
bool writeback = ((*off >> 21) & 1) != 0, bool writeback = ((*off >> 21) & 1) != 0,
@ -398,39 +330,24 @@ u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
if(!pre) addr += offset; if(!pre) addr += offset;
if(writeback) r0 = addr; if(writeback) r0 = addr;
} }
}
ret = 0; return 0;
}
return ret;
} }
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset) u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset)
{ {
const u8 pattern[] = {0x1B, 0x50, 0xA0, 0xE3}, //Get TitleID from CodeSet const u8 pattern[] = {0x1B, 0x50, 0xA0, 0xE3}, //Get TitleID from CodeSet
pattern2[] = {0xE8, 0x13, 0x00, 0x02}; //Call exception dispatcher pattern2[] = {0xE8, 0x13, 0x00, 0x02}; //Call exception dispatcher
bool ret = true;
u32 *loadCodeSet = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); u32 *loadCodeSet = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
if(loadCodeSet == NULL) ret = false;
else
{
loadCodeSet -= 2;
*codeSetOffset = *loadCodeSet & 0xFFF;
}
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2)); u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
u32 stackAddress; if(loadCodeSet == NULL || temp == NULL) error("Failed to get ARM11 exception handlers data.");
if(temp == NULL) ret = false; loadCodeSet -= 2;
else stackAddress = *(u32 *)(temp + 9); *codeSetOffset = *loadCodeSet & 0xFFF;
if(!ret) error("Failed to get ARM11 exception handlers data."); return *(u32 *)(temp + 9);
return stackAddress;
} }
u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
@ -439,22 +356,17 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
//Look for the svc handler //Look for the svc handler
const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr
u32 ret;
u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
if(arm9SvcTable == NULL) ret = 1; if(arm9SvcTable == NULL) return 1;
else
{
while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL) while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL)
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address);
*addr = 0xE12FFF7F; *addr = 0xE12FFF7F;
ret = 0; return 0;
}
return ret;
} }
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable) void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable)
@ -467,76 +379,54 @@ void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable)
u32 patchKernel9Panic(u8 *pos, u32 size) u32 patchKernel9Panic(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0}; const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0};
u32 ret;
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) ret = 1; if(temp == NULL) return 1;
else
{
u32 *off = (u32 *)(temp - 0x12); u32 *off = (u32 *)(temp - 0x12);
*off = 0xE12FFF7E; *off = 0xE12FFF7E;
ret = 0; return 0;
}
return ret;
} }
u32 patchKernel11Panic(u8 *pos, u32 size) u32 patchKernel11Panic(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2}; const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2};
u32 ret;
u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
*off = 0xE12FFF7E; *off = 0xE12FFF7E;
ret = 0; return 0;
}
return ret;
} }
u32 patchP9AccessChecks(u8 *pos, u32 size) u32 patchP9AccessChecks(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x00, 0x08, 0x49, 0x68}; const u8 pattern[] = {0x00, 0x08, 0x49, 0x68};
u32 ret;
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) ret = 1; if(temp == NULL) return 1;
else
{
u16 *off = (u16 *)(temp - 3);
u16 *off = (u16 *)(temp - 3);
off[0] = 0x2001; //mov r0, #1 off[0] = 0x2001; //mov r0, #1
off[1] = 0x4770; //bx lr off[1] = 0x4770; //bx lr
ret = 0; return 0;
}
return ret;
} }
u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos) u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos)
{ {
u32 ret;
while(*arm11SvcHandler != 0xE11A0E1B && arm11SvcHandler < endPos) arm11SvcHandler++; //TST R10, R11,LSL LR while(*arm11SvcHandler != 0xE11A0E1B && arm11SvcHandler < endPos) arm11SvcHandler++; //TST R10, R11,LSL LR
if(arm11SvcHandler == endPos) ret = 1; if(arm11SvcHandler == endPos) return 1;
else
{
*arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1 *arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1
ret = 0; return 0;
}
return ret;
} }
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space) u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space)
@ -544,20 +434,16 @@ u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space)
/* We have to detour a function in the ARM11 kernel because builtin modules /* We have to detour a function in the ARM11 kernel because builtin modules
are compressed in memory and are only decompressed at runtime */ are compressed in memory and are only decompressed at runtime */
u32 ret;
//Check that we have enough free space //Check that we have enough free space
if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) ret = 0; if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) return 0;
else
{
//Look for the code that decompresses the .code section of the builtin modules //Look for the code that decompresses the .code section of the builtin modules
const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D}; const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) ret = 1; if(temp == NULL) return 1;
else
{
//Inject our code into the free space //Inject our code into the free space
memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size); memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size);
@ -568,190 +454,139 @@ u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space)
*freeK11Space += k11modules_bin_size; *freeK11Space += k11modules_bin_size;
ret = 0; return 0;
}
}
return ret;
} }
u32 patchUnitInfoValueSet(u8 *pos, u32 size) u32 patchUnitInfoValueSet(u8 *pos, u32 size)
{ {
//Look for UNITINFO value being set during kernel sync //Look for UNITINFO value being set during kernel sync
const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13}; const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13};
u32 ret;
u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[0] = ISDEVUNIT ? 0 : 1; off[0] = ISDEVUNIT ? 0 : 1;
off[3] = 0xE3; off[3] = 0xE3;
ret = 0; return 0;
}
return ret;
} }
u32 patchLgySignatureChecks(u8 *pos, u32 size) u32 patchLgySignatureChecks(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49}; const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49};
u32 ret;
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) ret = 1; if(temp == NULL) return 1;
else
{
u16 *off = (u16 *)(temp + 1);
u16 *off = (u16 *)(temp + 1);
off[0] = 0x2000; off[0] = 0x2000;
off[1] = 0xB04E; off[1] = 0xB04E;
off[2] = 0xBD70; off[2] = 0xBD70;
ret = 0; return 0;
}
return ret;
} }
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size) u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F}; const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F};
u32 ret;
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) ret = 1; if(temp == NULL) return 1;
else
{
u16 *off = (u16 *)(temp - 1);
u16 *off = (u16 *)(temp - 1);
*off = 0x2001; //mov r0, #1 *off = 0x2001; //mov r0, #1
ret = 0; return 0;
}
return ret;
} }
u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size) u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0}; const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[1] = 0x2000; off[1] = 0x2000;
off[2] = 0; off[2] = 0;
ret = 0; return 0;
}
return ret;
} }
u32 patchTwlWhitelistChecks(u8 *pos, u32 size) u32 patchTwlWhitelistChecks(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x22, 0x00, 0x20, 0x30}; const u8 pattern[] = {0x22, 0x00, 0x20, 0x30};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[2] = 0x2000; off[2] = 0x2000;
off[3] = 0; off[3] = 0;
ret = 0; return 0;
}
return ret;
} }
u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion) u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion)
{ {
const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E}; const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E};
u32 ret;
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
if(temp == NULL) if(temp == NULL)
{ {
if(firmVersion == 0xFFFFFFFF) ret = patchOldTwlFlashcartChecks(pos, size); if(firmVersion == 0xFFFFFFFF) return patchOldTwlFlashcartChecks(pos, size);
else ret = 1;
}
else
{
u16 *off = (u16 *)(temp + 3);
return 1;
}
u16 *off = (u16 *)(temp + 3);
off[0] = off[6] = off[0xC] = 0x2001; //mov r0, #1 off[0] = off[6] = off[0xC] = 0x2001; //mov r0, #1
off[1] = off[7] = off[0xD] = 0; //nop off[1] = off[7] = off[0xD] = 0; //nop
ret = 0; return 0;
}
return ret;
} }
u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size) u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD}; const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[0] = off[6] = 0x2001; //mov r0, #1 off[0] = off[6] = 0x2001; //mov r0, #1
off[1] = off[7] = 0; //nop off[1] = off[7] = 0; //nop
ret = 0; return 0;
}
return ret;
} }
u32 patchTwlShaHashChecks(u8 *pos, u32 size) u32 patchTwlShaHashChecks(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22}; const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22};
u32 ret;
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[0] = 0x2001; //mov r0, #1 off[0] = 0x2001; //mov r0, #1
off[1] = 0x4770; off[1] = 0x4770;
ret = 0; return 0;
}
return ret;
} }
u32 patchAgbBootSplash(u8 *pos, u32 size) u32 patchAgbBootSplash(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF}; const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF};
u32 ret;
u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
if(off == NULL) ret = 1; if(off == NULL) return 1;
else
{
off[2] = 0x26; off[2] = 0x26;
ret = 0; return 0;
}
return ret;
} }

View File

@ -85,9 +85,14 @@ void newPin(bool allowSkipping, u32 pinMode)
if(pressed & BUTTON_START) return; if(pressed & BUTTON_START) return;
if(pressed & BUTTON_SELECT) reset = true; if(pressed & BUTTON_SELECT)
else if(pressed != 0)
{ {
reset = true;
continue;
}
if(!pressed) continue;
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password
//Visualize character on screen //Visualize character on screen
@ -95,7 +100,6 @@ void newPin(bool allowSkipping, u32 pinMode)
cnt++; cnt++;
} }
}
PinData pin; PinData pin;
@ -188,16 +192,21 @@ bool verifyPin(u32 pinMode)
pressed &= PIN_BUTTONS; pressed &= PIN_BUTTONS;
if(pressed & BUTTON_SELECT) reset = true; if(pressed & BUTTON_SELECT)
else if(pressed != 0)
{ {
reset = true;
continue;
}
if(!pressed) continue;
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password
//Visualize character on screen //Visualize character on screen
drawCharacter((char)enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE); drawCharacter((char)enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
if(++cnt >= lengthBlock[0]) if(++cnt < lengthBlock[0]) continue;
{
computePinHash(tmp, enteredPassword); computePinHash(tmp, enteredPassword);
unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0; unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0;
@ -208,8 +217,6 @@ bool verifyPin(u32 pinMode)
drawString("Wrong PIN, try again", true, 10, 10 + 5 * SPACING_Y, COLOR_RED); drawString("Wrong PIN, try again", true, 10, 10 + 5 * SPACING_Y, COLOR_RED);
} }
} }
}
}
return true; return true;
} }

View File

@ -57,6 +57,7 @@ void __attribute__((naked)) arm11Stub(void)
static void invokeArm11Function(void (*func)()) static void invokeArm11Function(void (*func)())
{ {
static bool hasCopiedStub = false; static bool hasCopiedStub = false;
if(!hasCopiedStub) if(!hasCopiedStub)
{ {
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30); memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);

View File

@ -56,7 +56,6 @@ static u64 chrono(bool isMilliseconds)
u32 waitInput(bool isMenu) u32 waitInput(bool isMenu)
{ {
static u64 dPadDelay = 0ULL; static u64 dPadDelay = 0ULL;
bool pressedKey = false;
u32 key, u32 key,
oldKey = HID_PAD; oldKey = HID_PAD;
@ -66,23 +65,24 @@ u32 waitInput(bool isMenu)
startChrono(); startChrono();
} }
while(!pressedKey) while(true)
{ {
key = HID_PAD; key = HID_PAD;
if(!key) if(!key)
{ {
if(i2cReadRegister(I2C_DEV_MCU, 0x10) == 1) mcuPowerOff(); if(i2cReadRegister(I2C_DEV_MCU, 0x10) == 1) mcuPowerOff();
oldKey = key; oldKey = 0;
dPadDelay = 0; dPadDelay = 0;
continue;
} }
else if((key != oldKey) || (isMenu && (key & DPAD_BUTTONS) != 0 && (chrono(true) >= dPadDelay)))
{ if(key == oldKey && (!isMenu || (!(key & DPAD_BUTTONS) || chrono(true) < dPadDelay))) continue;
//Make sure the key is pressed //Make sure the key is pressed
u32 i; u32 i;
for(i = 0; i < 0x13000 && key == HID_PAD; i++); for(i = 0; i < 0x13000 && key == HID_PAD; i++);
if(i == 0x13000) pressedKey = true; if(i == 0x13000) break;
}
} }
return key; return key;