Refactor string handling
This commit is contained in:
parent
f5aa63936c
commit
e8d4a98c7b
@ -246,8 +246,8 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString(CONFIG_TITLE, true, 10, 10, COLOR_TITLE);
|
drawString(true, 10, 10, COLOR_TITLE, CONFIG_TITLE);
|
||||||
drawString("Press A to select, START to save", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press A to select, START to save");
|
||||||
|
|
||||||
//Character to display a selected option
|
//Character to display a selected option
|
||||||
char selected = 'x';
|
char selected = 'x';
|
||||||
@ -260,8 +260,8 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
if(!multiOptions[i].visible) continue;
|
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(true, 10, multiOptions[i].posY, COLOR_WHITE, multiOptionsText[i]);
|
||||||
drawCharacter(selected, true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
|
drawCharacter(true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
endPos += SPACING_Y / 2;
|
endPos += SPACING_Y / 2;
|
||||||
@ -272,8 +272,8 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
if(!singleOptions[i].visible) continue;
|
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(true, 10, singleOptions[i].posY, color, singleOptionsText[i]);
|
||||||
if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color);
|
if(singleOptions[i].enabled) drawCharacter(true, 10 + SPACING_X, singleOptions[i].posY, color, selected);
|
||||||
|
|
||||||
if(color == COLOR_RED)
|
if(color == COLOR_RED)
|
||||||
{
|
{
|
||||||
@ -283,7 +283,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
|
drawString(false, 10, 10, COLOR_WHITE, optionsDescription[selectedOption]);
|
||||||
|
|
||||||
//Boring configuration menu
|
//Boring configuration menu
|
||||||
while(true)
|
while(true)
|
||||||
@ -347,21 +347,21 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
|
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
|
||||||
if(oldSelectedOption < multiOptionsAmount)
|
if(oldSelectedOption < multiOptionsAmount)
|
||||||
{
|
{
|
||||||
drawString(multiOptionsText[oldSelectedOption], true, 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
drawString(true, 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE, multiOptionsText[oldSelectedOption]);
|
||||||
drawCharacter(selected, true, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
drawCharacter(true, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE, selected);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
|
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
|
||||||
drawString(singleOptionsText[singleOldSelected], true, 10, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
drawString(true, 10, singleOptions[singleOldSelected].posY, COLOR_WHITE, singleOptionsText[singleOldSelected]);
|
||||||
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
if(singleOptions[singleOldSelected].enabled) drawCharacter(true, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isMultiOption) drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED);
|
if(isMultiOption) drawString(true, 10, multiOptions[selectedOption].posY, COLOR_RED, multiOptionsText[selectedOption]);
|
||||||
else drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED);
|
else drawString(true, 10, singleOptions[singleSelected].posY, COLOR_RED, singleOptionsText[singleSelected]);
|
||||||
|
|
||||||
drawString(optionsDescription[oldSelectedOption], false, 10, 10, COLOR_BLACK);
|
drawString(false, 10, 10, COLOR_BLACK, optionsDescription[oldSelectedOption]);
|
||||||
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
|
drawString(false, 10, 10, COLOR_WHITE, optionsDescription[selectedOption]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -369,7 +369,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
if(isMultiOption)
|
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(true, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK, selected);
|
||||||
multiOptions[selectedOption].enabled = (oldEnabled == 3 || !multiOptions[selectedOption].posXs[oldEnabled + 1]) ? 0 : oldEnabled + 1;
|
multiOptions[selectedOption].enabled = (oldEnabled == 3 || !multiOptions[selectedOption].posXs[oldEnabled + 1]) ? 0 : oldEnabled + 1;
|
||||||
|
|
||||||
if(selectedOption == BRIGHTNESS) updateBrightness(multiOptions[BRIGHTNESS].enabled);
|
if(selectedOption == BRIGHTNESS) updateBrightness(multiOptions[BRIGHTNESS].enabled);
|
||||||
@ -378,13 +378,13 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
{
|
{
|
||||||
bool oldEnabled = singleOptions[singleSelected].enabled;
|
bool oldEnabled = singleOptions[singleSelected].enabled;
|
||||||
singleOptions[singleSelected].enabled = !oldEnabled;
|
singleOptions[singleSelected].enabled = !oldEnabled;
|
||||||
if(oldEnabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_BLACK);
|
if(oldEnabled) drawCharacter(true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_BLACK, selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//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(isMultiOption) drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
|
if(isMultiOption) drawCharacter(true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED, selected);
|
||||||
else if(singleOptions[singleSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
|
else if(singleOptions[singleSelected].enabled) drawCharacter(true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Preserve the last-used boot options (first 9 bits)
|
//Preserve the last-used boot options (first 9 bits)
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "fmt.h"
|
||||||
|
|
||||||
bool loadSplash(void)
|
bool loadSplash(void)
|
||||||
{
|
{
|
||||||
@ -57,7 +59,7 @@ bool loadSplash(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color)
|
void drawCharacter(bool isTopScreen, u32 posX, u32 posY, u32 color, char character)
|
||||||
{
|
{
|
||||||
u8 *select = isTopScreen ? fbs[0].top_left : fbs[0].bottom;
|
u8 *select = isTopScreen ? fbs[0].top_left : fbs[0].bottom;
|
||||||
|
|
||||||
@ -77,7 +79,7 @@ void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 col
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 drawString(const char *string, bool isTopScreen, u32 posX, u32 posY, u32 color)
|
u32 drawString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *string)
|
||||||
{
|
{
|
||||||
for(u32 i = 0, line_i = 0; i < strlen(string); i++)
|
for(u32 i = 0, line_i = 0; i < strlen(string); i++)
|
||||||
switch(string[i])
|
switch(string[i])
|
||||||
@ -100,7 +102,7 @@ u32 drawString(const char *string, bool isTopScreen, u32 posX, u32 posY, u32 col
|
|||||||
if(string[i] == ' ') break; //Spaces at the start look weird
|
if(string[i] == ' ') break; //Spaces at the start look weird
|
||||||
}
|
}
|
||||||
|
|
||||||
drawCharacter(string[i], isTopScreen, posX + line_i * SPACING_X, posY, color);
|
drawCharacter(isTopScreen, posX + line_i * SPACING_X, posY, color, string[i]);
|
||||||
|
|
||||||
line_i++;
|
line_i++;
|
||||||
break;
|
break;
|
||||||
@ -108,3 +110,14 @@ u32 drawString(const char *string, bool isTopScreen, u32 posX, u32 posY, u32 col
|
|||||||
|
|
||||||
return posY;
|
return posY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 drawFormattedString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[DRAW_MAX_FORMATTED_STRING_SIZE + 1];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsprintf(buf, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return drawString(isTopScreen, posX, posY, color, buf);
|
||||||
|
}
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
#define COLOR_BLACK 0x000000
|
#define COLOR_BLACK 0x000000
|
||||||
#define COLOR_YELLOW 0x00FFFF
|
#define COLOR_YELLOW 0x00FFFF
|
||||||
|
|
||||||
|
#define DRAW_MAX_FORMATTED_STRING_SIZE 512
|
||||||
|
|
||||||
bool loadSplash(void);
|
bool loadSplash(void);
|
||||||
void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color);
|
void drawCharacter(bool isTopScreen, u32 posX, u32 posY, u32 color, char character);
|
||||||
u32 drawString(const char *string, bool isTopScreen, u32 posX, u32 posY, u32 color);
|
u32 drawString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *string);
|
||||||
|
u32 drawFormattedString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *fmt, ...);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "fmt.h"
|
||||||
#include "../build/bundled.h"
|
#include "../build/bundled.h"
|
||||||
|
|
||||||
void installArm9Handlers(void)
|
void installArm9Handlers(void)
|
||||||
@ -119,7 +120,7 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
};
|
};
|
||||||
|
|
||||||
const char *specialExceptions[] = {
|
const char *specialExceptions[] = {
|
||||||
"(kernel panic)", "(svcBreak)"
|
"kernel panic", "svcBreak"
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *registerNames[] = {
|
const char *registerNames[] = {
|
||||||
@ -127,99 +128,82 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
"SP", "LR", "PC", "CPSR", "FPEXC"
|
"SP", "LR", "PC", "CPSR", "FPEXC"
|
||||||
};
|
};
|
||||||
|
|
||||||
char hexString[] = "00000000";
|
|
||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("An exception occurred", true, 10, 10, COLOR_RED);
|
drawString(true, 10, 10, COLOR_RED, "An exception occurred");
|
||||||
u32 posY = drawString(dumpHeader->processor == 11 ? "Processor: ARM11 (core )" : "Processor: ARM9", true, 10, 30, COLOR_WHITE);
|
u32 posY;
|
||||||
if(dumpHeader->processor == 11) drawCharacter('0' + dumpHeader->core, true, 10 + 29 * SPACING_X, 30, COLOR_WHITE);
|
if(dumpHeader->processor == 11) posY = drawFormattedString(true, 10, 30, COLOR_WHITE, "Processor: ARM11 (core %u)", dumpHeader->core);
|
||||||
|
else posY = drawString(true, 10, 30, COLOR_WHITE, "Processor: ARM9");
|
||||||
posY = drawString("Exception type: ", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
|
||||||
drawString(handledExceptionNames[dumpHeader->type], true, 10 + 17 * SPACING_X, posY, COLOR_WHITE);
|
|
||||||
|
|
||||||
if(dumpHeader->type == 2)
|
if(dumpHeader->type == 2)
|
||||||
{
|
{
|
||||||
if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4)
|
if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4)
|
||||||
{
|
{
|
||||||
u32 instr = *(vu32 *)(stackDump - 4);
|
u32 instr = *(vu32 *)(stackDump - 4);
|
||||||
if(instr == 0xE12FFF7E) drawString(specialExceptions[0], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
if(instr == 0xE12FFF7E)
|
||||||
else if(instr == 0xEF00003C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[0]);
|
||||||
|
else if(instr == 0xEF00003C)
|
||||||
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[1]);
|
||||||
|
else
|
||||||
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||||
}
|
}
|
||||||
else if((regs[16] & 0x20) != 0 && dumpHeader->codeDumpSize >= 2)
|
else if((regs[16] & 0x20) != 0 && dumpHeader->codeDumpSize >= 2)
|
||||||
{
|
{
|
||||||
u16 instr = *(vu16 *)(stackDump - 2);
|
u16 instr = *(vu16 *)(stackDump - 2);
|
||||||
if(instr == 0xDF3C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
if(instr == 0xDF3C)
|
||||||
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[0]);
|
||||||
|
else
|
||||||
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||||
|
|
||||||
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
||||||
{
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE,
|
||||||
char processName[45] = "Current process: ";
|
"Current process: %.8s (%016llX)", (const char *)additionalData, *(vu64 *)(additionalData + 8));
|
||||||
memcpy(processName + 17, (void *)additionalData, 8);
|
|
||||||
hexItoa(*(vu32 *)(additionalData + 12), hexString, 8, true);
|
|
||||||
concatenateStrings(processName, " (");
|
|
||||||
concatenateStrings(processName, hexString);
|
|
||||||
hexItoa(*(vu32 *)(additionalData + 8), hexString, 8, true);
|
|
||||||
concatenateStrings(processName, hexString);
|
|
||||||
concatenateStrings(processName, ")");
|
|
||||||
posY = drawString(processName, true, 10, posY + SPACING_Y, COLOR_WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
posY += SPACING_Y;
|
posY += SPACING_Y;
|
||||||
|
|
||||||
for(u32 i = 0; i < 17; i += 2)
|
for(u32 i = 0; i < 17; i += 2)
|
||||||
{
|
{
|
||||||
posY = drawString(registerNames[i], true, 10, posY + SPACING_Y, COLOR_WHITE);
|
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "%-7s%08X", registerNames[i], regs[i]);
|
||||||
hexItoa(regs[i], hexString, 8, true);
|
|
||||||
drawString(hexString, true, 10 + 7 * SPACING_X, posY, COLOR_WHITE);
|
|
||||||
|
|
||||||
if(i != 16 || dumpHeader->processor != 9)
|
if(i != 16 || dumpHeader->processor != 9)
|
||||||
{
|
posY = drawFormattedString(true, 10 + 22 * SPACING_X, posY, COLOR_WHITE, "%-7s%08X", registerNames[i + 1], regs[i + 1]);
|
||||||
drawString(registerNames[i + 1], true, 10 + 22 * SPACING_X, posY, COLOR_WHITE);
|
|
||||||
hexItoa(i == 16 ? regs[20] : regs[i + 1], hexString, 8, true);
|
|
||||||
drawString(hexString, true, 10 + 29 * SPACING_X, posY, COLOR_WHITE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
posY += SPACING_Y;
|
posY += SPACING_Y;
|
||||||
|
|
||||||
u32 mode = regs[16] & 0xF;
|
u32 mode = regs[16] & 0xF;
|
||||||
if(dumpHeader->type == 3 && (mode == 7 || mode == 11))
|
if(dumpHeader->type == 3 && (mode == 7 || mode == 11))
|
||||||
posY = drawString("Incorrect dump: failed to dump code and/or stack", true, 10, posY + SPACING_Y, COLOR_YELLOW) + SPACING_Y;
|
posY = drawString(true, 10, posY + SPACING_Y, COLOR_YELLOW, "Incorrect dump: failed to dump code and/or stack") + SPACING_Y;
|
||||||
|
|
||||||
u32 posYBottom = drawString("Stack dump:", false, 10, 10, COLOR_WHITE) + SPACING_Y;
|
u32 posYBottom = drawString(false, 10, 10, COLOR_WHITE, "Stack dump:") + SPACING_Y;
|
||||||
|
|
||||||
for(u32 line = 0; line < 19 && stackDump < additionalData; line++)
|
for(u32 line = 0; line < 19 && stackDump < additionalData; line++)
|
||||||
{
|
{
|
||||||
hexItoa(regs[13] + 8 * line, hexString, 8, true);
|
posYBottom = drawFormattedString(false, 10, posYBottom + SPACING_Y, COLOR_WHITE, "%08X:", regs[13] + 8 * line);
|
||||||
posYBottom = drawString(hexString, false, 10, posYBottom + SPACING_Y, COLOR_WHITE);
|
|
||||||
drawCharacter(':', false, 10 + 8 * SPACING_X, posYBottom, COLOR_WHITE);
|
|
||||||
|
|
||||||
for(u32 i = 0; i < 8 && stackDump < additionalData; i++, stackDump++)
|
for(u32 i = 0; i < 8 && stackDump < additionalData; i++, stackDump++)
|
||||||
{
|
drawFormattedString(false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE, "%02X", *stackDump);
|
||||||
char byteString[] = "00";
|
|
||||||
hexItoa(*stackDump, byteString, 2, false);
|
|
||||||
drawString(byteString, false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char path[36] = "dumps/",
|
char folderPath[36],
|
||||||
fileName[] = "crash_dump_00000000.dmp";
|
path[36],
|
||||||
|
fileName[] = "crash_dump_00010000.dmp";
|
||||||
|
|
||||||
concatenateStrings(path, dumpHeader->processor == 9 ? "arm9" : "arm11");
|
sprintf(folderPath, "dumps/arm%u", dumpHeader->processor);
|
||||||
findDumpFile(path, fileName);
|
findDumpFile(folderPath, fileName);
|
||||||
concatenateStrings(path, "/");
|
sprintf(path, "%s/%s", folderPath, fileName);
|
||||||
concatenateStrings(path, fileName);
|
|
||||||
|
|
||||||
if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize))
|
if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize))
|
||||||
{
|
{
|
||||||
posY = drawString("You can find a dump in the following file:", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "You can find a dump in the following file:");
|
||||||
posY = drawString(path, true, 10, posY + SPACING_Y, COLOR_WHITE) + SPACING_Y;
|
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, path) + SPACING_Y;
|
||||||
}
|
}
|
||||||
else posY = drawString("Error writing the dump file", true, 10, posY + SPACING_Y, COLOR_RED);
|
else posY = drawString(true, 10, posY + SPACING_Y, COLOR_RED, "Error writing the dump file");
|
||||||
|
|
||||||
drawString("Press any button to shutdown", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Press any button to shutdown");
|
||||||
|
|
||||||
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
#include "fmt.h"
|
||||||
#include "../build/bundled.h"
|
#include "../build/bundled.h"
|
||||||
|
|
||||||
static Firm *firm = (Firm *)0x24000000;
|
static Firm *firm = (Firm *)0x24000000;
|
||||||
@ -325,11 +326,10 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
|
|||||||
|
|
||||||
if(loadFromStorage)
|
if(loadFromStorage)
|
||||||
{
|
{
|
||||||
char fileName[24] = "sysmodules/";
|
char fileName[64];
|
||||||
|
|
||||||
//Read modules from files if they exist
|
//Read modules from files if they exist
|
||||||
concatenateStrings(fileName, moduleName);
|
sprintf(fileName, "%.8s.cxi", moduleName);
|
||||||
concatenateStrings(fileName, ".cxi");
|
|
||||||
|
|
||||||
dstModuleSize = getFileSize(fileName);
|
dstModuleSize = getFileSize(fileName);
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
|
|||||||
|
|
||||||
const u8 *module;
|
const u8 *module;
|
||||||
|
|
||||||
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
|
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6 + 1) == 0)
|
||||||
{
|
{
|
||||||
module = injector_bin;
|
module = injector_bin;
|
||||||
dstModuleSize = injector_bin_size;
|
dstModuleSize = injector_bin_size;
|
||||||
|
411
source/fmt.c
Normal file
411
source/fmt.c
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
// TuxSH's changes: add support for 64-bit numbers, remove floating-point code
|
||||||
|
// TODO! fix left-padding handling with > 10 characters.
|
||||||
|
|
||||||
|
#include "fmt.h"
|
||||||
|
#include "strings.h"
|
||||||
|
|
||||||
|
/* File : barebones/ee_printf.c
|
||||||
|
This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code.
|
||||||
|
|
||||||
|
This code is based on a file that contains the following:
|
||||||
|
Copyright (C) 2002 Michael Ringgaard. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. Neither the name of the project nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#include <coremark.h>
|
||||||
|
//#include <stdarg.h>
|
||||||
|
|
||||||
|
#define ZEROPAD (1<<0) /* Pad with zero */
|
||||||
|
#define SIGN (1<<1) /* Unsigned/signed long */
|
||||||
|
#define PLUS (1<<2) /* Show plus */
|
||||||
|
#define SPACE (1<<3) /* Spacer */
|
||||||
|
#define LEFT (1<<4) /* Left justified */
|
||||||
|
#define HEX_PREP (1<<5) /* 0x */
|
||||||
|
#define UPPERCASE (1<<6) /* 'ABCDEF' */
|
||||||
|
|
||||||
|
#define is_digit(c) ((c) >= '0' && (c) <= '9')
|
||||||
|
|
||||||
|
static char *lower_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
|
static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
/*
|
||||||
|
static size_t strnlen(const char *s, size_t count);
|
||||||
|
|
||||||
|
static size_t strnlen(const char *s, size_t count)
|
||||||
|
{
|
||||||
|
const char *sc;
|
||||||
|
for (sc = s; *sc != '\0' && count--; ++sc);
|
||||||
|
return sc - s;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int ee_skip_atoi(const char **s)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (is_digit(**s)) i = i*10 + *((*s)++) - '0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *ee_number(char *str, long long num, int base, int size, int precision, int type)
|
||||||
|
{
|
||||||
|
char c, sign, tmp[66];
|
||||||
|
char *dig = lower_digits;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (type & UPPERCASE) dig = upper_digits;
|
||||||
|
if (type & LEFT) type &= ~ZEROPAD;
|
||||||
|
if (base < 2 || base > 36) return 0;
|
||||||
|
|
||||||
|
c = (type & ZEROPAD) ? '0' : ' ';
|
||||||
|
sign = 0;
|
||||||
|
if (type & SIGN)
|
||||||
|
{
|
||||||
|
if (num < 0)
|
||||||
|
{
|
||||||
|
sign = '-';
|
||||||
|
num = -num;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
else if (type & PLUS)
|
||||||
|
{
|
||||||
|
sign = '+';
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
else if (type & SPACE)
|
||||||
|
{
|
||||||
|
sign = ' ';
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & HEX_PREP)
|
||||||
|
{
|
||||||
|
if (base == 16)
|
||||||
|
size -= 2;
|
||||||
|
else if (base == 8)
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
if (num == 0)
|
||||||
|
tmp[i++] = '0';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (num != 0)
|
||||||
|
{
|
||||||
|
tmp[i++] = dig[(unsigned long long)num % (unsigned long long)base];
|
||||||
|
num = (long long)((unsigned long long)num / (unsigned long long) base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > precision) precision = i;
|
||||||
|
size -= precision;
|
||||||
|
if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
|
||||||
|
if (sign) *str++ = sign;
|
||||||
|
|
||||||
|
if (type & HEX_PREP)
|
||||||
|
{
|
||||||
|
if (base == 8)
|
||||||
|
*str++ = '0';
|
||||||
|
else if (base == 16)
|
||||||
|
{
|
||||||
|
*str++ = '0';
|
||||||
|
*str++ = lower_digits[33];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(type & LEFT)) while (size-- > 0) *str++ = c;
|
||||||
|
while (i < precision--) *str++ = '0';
|
||||||
|
while (i-- > 0) *str++ = tmp[i];
|
||||||
|
while (size-- > 0) *str++ = ' ';
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *eaddr(char *str, unsigned char *addr, int size, int precision __attribute__((unused)), int type)
|
||||||
|
{
|
||||||
|
char tmp[24];
|
||||||
|
char *dig = lower_digits;
|
||||||
|
int i, len;
|
||||||
|
|
||||||
|
if (type & UPPERCASE) dig = upper_digits;
|
||||||
|
len = 0;
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
if (i != 0) tmp[len++] = ':';
|
||||||
|
tmp[len++] = dig[addr[i] >> 4];
|
||||||
|
tmp[len++] = dig[addr[i] & 0x0F];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(type & LEFT)) while (len < size--) *str++ = ' ';
|
||||||
|
for (i = 0; i < len; ++i) *str++ = tmp[i];
|
||||||
|
while (len < size--) *str++ = ' ';
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *iaddr(char *str, unsigned char *addr, int size, int precision __attribute__((unused)), int type)
|
||||||
|
{
|
||||||
|
char tmp[24];
|
||||||
|
int i, n, len;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (i != 0) tmp[len++] = '.';
|
||||||
|
n = addr[i];
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
tmp[len++] = lower_digits[0];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (n >= 100)
|
||||||
|
{
|
||||||
|
tmp[len++] = lower_digits[n / 100];
|
||||||
|
n = n % 100;
|
||||||
|
tmp[len++] = lower_digits[n / 10];
|
||||||
|
n = n % 10;
|
||||||
|
}
|
||||||
|
else if (n >= 10)
|
||||||
|
{
|
||||||
|
tmp[len++] = lower_digits[n / 10];
|
||||||
|
n = n % 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp[len++] = lower_digits[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(type & LEFT)) while (len < size--) *str++ = ' ';
|
||||||
|
for (i = 0; i < len; ++i) *str++ = tmp[i];
|
||||||
|
while (len < size--) *str++ = ' ';
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ee_vsprintf(char *buf, const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
long long num;
|
||||||
|
int i, base;
|
||||||
|
char *str;
|
||||||
|
char *s;
|
||||||
|
int flags; // Flags to number()
|
||||||
|
|
||||||
|
int field_width; // Width of output field
|
||||||
|
int precision; // Min. # of digits for integers; max number of chars for from string
|
||||||
|
int qualifier; // 'h', 'l', or 'L' for integer fields
|
||||||
|
int qualifier2;
|
||||||
|
|
||||||
|
for (str = buf; *fmt; fmt++)
|
||||||
|
{
|
||||||
|
if (*fmt != '%')
|
||||||
|
{
|
||||||
|
*str++ = *fmt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process flags
|
||||||
|
flags = 0;
|
||||||
|
repeat:
|
||||||
|
fmt++; // This also skips first '%'
|
||||||
|
switch (*fmt)
|
||||||
|
{
|
||||||
|
case '-': flags |= LEFT; goto repeat;
|
||||||
|
case '+': flags |= PLUS; goto repeat;
|
||||||
|
case ' ': flags |= SPACE; goto repeat;
|
||||||
|
case '#': flags |= HEX_PREP; goto repeat;
|
||||||
|
case '0': flags |= ZEROPAD; goto repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get field width
|
||||||
|
field_width = -1;
|
||||||
|
if (is_digit(*fmt))
|
||||||
|
field_width = ee_skip_atoi(&fmt);
|
||||||
|
else if (*fmt == '*')
|
||||||
|
{
|
||||||
|
fmt++;
|
||||||
|
field_width = va_arg(args, int);
|
||||||
|
if (field_width < 0)
|
||||||
|
{
|
||||||
|
field_width = -field_width;
|
||||||
|
flags |= LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the precision
|
||||||
|
precision = -1;
|
||||||
|
if (*fmt == '.')
|
||||||
|
{
|
||||||
|
++fmt;
|
||||||
|
if (is_digit(*fmt))
|
||||||
|
precision = ee_skip_atoi(&fmt);
|
||||||
|
else if (*fmt == '*')
|
||||||
|
{
|
||||||
|
++fmt;
|
||||||
|
precision = va_arg(args, int);
|
||||||
|
}
|
||||||
|
if (precision < 0) precision = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the conversion qualifier
|
||||||
|
qualifier = qualifier2 = -1;
|
||||||
|
if(*fmt == 'L')
|
||||||
|
qualifier = *fmt++;
|
||||||
|
else if (*fmt == 'l')
|
||||||
|
{
|
||||||
|
qualifier = *fmt++;
|
||||||
|
if(*fmt == 'l') qualifier2 = *fmt++;
|
||||||
|
}
|
||||||
|
else if (*fmt == 'h')
|
||||||
|
{
|
||||||
|
qualifier = *fmt++;
|
||||||
|
if(*fmt == 'h') qualifier2 = *fmt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default base
|
||||||
|
base = 10;
|
||||||
|
|
||||||
|
switch (*fmt)
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' ';
|
||||||
|
*str++ = (unsigned char) va_arg(args, int);
|
||||||
|
while (--field_width > 0) *str++ = ' ';
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
s = va_arg(args, char *);
|
||||||
|
if (!s) s = "<NULL>";
|
||||||
|
if(precision != -1)
|
||||||
|
len = strnlen(s, precision);
|
||||||
|
else
|
||||||
|
len = strlen(s);
|
||||||
|
if (!(flags & LEFT)) while (len < field_width--) *str++ = ' ';
|
||||||
|
for (i = 0; i < len; ++i) *str++ = *s++;
|
||||||
|
while (len < field_width--) *str++ = ' ';
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (field_width == -1)
|
||||||
|
{
|
||||||
|
field_width = 2 * sizeof(void *);
|
||||||
|
flags |= ZEROPAD;
|
||||||
|
}
|
||||||
|
str = ee_number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 'A':
|
||||||
|
flags |= UPPERCASE;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
if (qualifier == 'l')
|
||||||
|
str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
|
||||||
|
else
|
||||||
|
str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Integer number formats - set up the flags and "break"
|
||||||
|
case 'o':
|
||||||
|
base = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
flags |= UPPERCASE;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
base = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
flags |= SIGN;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (*fmt != '%') *str++ = '%';
|
||||||
|
if (*fmt)
|
||||||
|
*str++ = *fmt;
|
||||||
|
else
|
||||||
|
--fmt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bugfixes here:
|
||||||
|
|
||||||
|
if(flags & SIGN)
|
||||||
|
{
|
||||||
|
if (qualifier == 'l' && qualifier2 == 'l')
|
||||||
|
num = va_arg(args, long long int);
|
||||||
|
else if(qualifier == 'l')
|
||||||
|
num = va_arg(args, long int);
|
||||||
|
/* else if(qualifier == 'h' && qualifier == 'h')
|
||||||
|
num = va_arg(args, signed char);
|
||||||
|
else if(qualifier == 'h')
|
||||||
|
num = va_arg(args, short);*/
|
||||||
|
else
|
||||||
|
num = va_arg(args, int);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (qualifier == 'l' && qualifier2 == 'l')
|
||||||
|
num = va_arg(args, unsigned long long int);
|
||||||
|
else if(qualifier == 'l')
|
||||||
|
num = va_arg(args, unsigned long int);
|
||||||
|
/* else if(qualifier == 'h' && qualifier == 'h')
|
||||||
|
num = va_arg(args, unsigned char);
|
||||||
|
else if(qualifier == 'h')
|
||||||
|
num = va_arg(args, unsigned short);*/
|
||||||
|
else
|
||||||
|
num = va_arg(args, unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = ee_number(str, num, base, field_width, precision, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
*str = '\0';
|
||||||
|
return str - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vsprintf(char *buf, const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
return ee_vsprintf(buf, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sprintf(char *buf, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
n = ee_vsprintf(buf, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return n;
|
||||||
|
}
|
6
source/fmt.h
Normal file
6
source/fmt.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "memory.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int vsprintf(char *buf, const char *fmt, va_list args);
|
||||||
|
int sprintf(char *buf, const char *fmt, ...);
|
45
source/fs.c
45
source/fs.c
@ -23,6 +23,7 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
|
#include "fmt.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
@ -141,9 +142,9 @@ void loadPayload(u32 pressed, const char *payloadPath)
|
|||||||
DIR dir;
|
DIR dir;
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
FRESULT result;
|
FRESULT result;
|
||||||
char path[22] = "payloads";
|
char path[128];
|
||||||
|
|
||||||
result = f_findfirst(&dir, &info, path, pattern);
|
result = f_findfirst(&dir, &info, "payloads", pattern);
|
||||||
|
|
||||||
if(result != FR_OK) return;
|
if(result != FR_OK) return;
|
||||||
|
|
||||||
@ -151,8 +152,7 @@ void loadPayload(u32 pressed, const char *payloadPath)
|
|||||||
|
|
||||||
if(!info.fname[0]) return;
|
if(!info.fname[0]) return;
|
||||||
|
|
||||||
concatenateStrings(path, "/");
|
sprintf(path, "payloads/%s", 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);
|
||||||
@ -207,12 +207,12 @@ void payloadMenu(void)
|
|||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("Luma3DS chainloader", true, 10, 10, COLOR_TITLE);
|
drawString(true, 10, 10, COLOR_TITLE, "Luma3DS chainloader");
|
||||||
drawString("Press A to select, START to quit", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press A to select, START to quit");
|
||||||
|
|
||||||
for(u32 i = 0, posY = 10 + 3 * SPACING_Y, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y)
|
for(u32 i = 0, posY = 10 + 3 * SPACING_Y, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y)
|
||||||
{
|
{
|
||||||
drawString(payloadList[i], true, 10, posY, color);
|
drawString(true, 10, posY, color, payloadList[i]);
|
||||||
if(color == COLOR_RED) color = COLOR_WHITE;
|
if(color == COLOR_RED) color = COLOR_WHITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,15 +249,13 @@ void payloadMenu(void)
|
|||||||
|
|
||||||
if(oldSelectedPayload == selectedPayload) continue;
|
if(oldSelectedPayload == selectedPayload) continue;
|
||||||
|
|
||||||
drawString(payloadList[oldSelectedPayload], true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE);
|
drawString(true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE, payloadList[oldSelectedPayload]);
|
||||||
drawString(payloadList[selectedPayload], true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED);
|
drawString(true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED, payloadList[selectedPayload]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pressed == BUTTON_A)
|
if(pressed == BUTTON_A)
|
||||||
{
|
{
|
||||||
concatenateStrings(path, "/");
|
sprintf(path, "payloads/%s.bin", payloadList[selectedPayload]);
|
||||||
concatenateStrings(path, payloadList[selectedPayload]);
|
|
||||||
concatenateStrings(path, ".bin");
|
|
||||||
loadPayload(0, path);
|
loadPayload(0, path);
|
||||||
error("The payload is too large or corrupted.");
|
error("The payload is too large or corrupted.");
|
||||||
}
|
}
|
||||||
@ -274,14 +272,14 @@ u32 firmRead(void *dest, u32 firmType)
|
|||||||
{"00000003", "20000003"},
|
{"00000003", "20000003"},
|
||||||
{"00000001", "20000001"}};
|
{"00000001", "20000001"}};
|
||||||
|
|
||||||
char path[48] = "1:/title/00040138/";
|
char folderPath[48];
|
||||||
concatenateStrings(path, firmFolders[firmType][ISN3DS ? 1 : 0]);
|
char path[48];
|
||||||
concatenateStrings(path, "/content");
|
sprintf(folderPath, "1:/title/00040138/%s/content", firmFolders[firmType][ISN3DS ? 1 : 0]);
|
||||||
|
|
||||||
DIR dir;
|
DIR dir;
|
||||||
u32 firmVersion = 0xFFFFFFFF;
|
u32 firmVersion = 0xFFFFFFFF;
|
||||||
|
|
||||||
if(f_opendir(&dir, path) != FR_OK) goto exit;
|
if(f_opendir(&dir, folderPath) != FR_OK) goto exit;
|
||||||
|
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
|
|
||||||
@ -302,10 +300,7 @@ u32 firmRead(void *dest, u32 firmType)
|
|||||||
if(firmVersion == 0xFFFFFFFF) goto exit;
|
if(firmVersion == 0xFFFFFFFF) goto exit;
|
||||||
|
|
||||||
//Complete the string with the .app name
|
//Complete the string with the .app name
|
||||||
concatenateStrings(path, "/00000000.app");
|
sprintf(path, "%s/%08x.app", folderPath, firmVersion);
|
||||||
|
|
||||||
//Convert back the .app name from integer to array
|
|
||||||
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;
|
||||||
|
|
||||||
@ -313,21 +308,19 @@ exit:
|
|||||||
return firmVersion;
|
return firmVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
void findDumpFile(const char *path, char *fileName)
|
void findDumpFile(const char *folderPath, char *fileName)
|
||||||
{
|
{
|
||||||
DIR dir;
|
DIR dir;
|
||||||
FRESULT result;
|
FRESULT result;
|
||||||
u32 n = 0;
|
|
||||||
|
|
||||||
while(n <= 99999999)
|
for(u32 n = 0; n <= 99999999; n++)
|
||||||
{
|
{
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
|
|
||||||
result = f_findfirst(&dir, &info, path, fileName);
|
sprintf(fileName, "crash_dump_%08u.dmp", n);
|
||||||
|
result = f_findfirst(&dir, &info, folderPath, fileName);
|
||||||
|
|
||||||
if(result != FR_OK || !info.fname[0]) break;
|
if(result != FR_OK || !info.fname[0]) break;
|
||||||
|
|
||||||
decItoa(++n, fileName + 11, 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result == FR_OK) f_closedir(&dir);
|
if(result == FR_OK) f_closedir(&dir);
|
||||||
|
@ -34,4 +34,4 @@ void fileDelete(const char *path);
|
|||||||
void loadPayload(u32 pressed, const char *payloadPath);
|
void loadPayload(u32 pressed, const char *payloadPath);
|
||||||
void payloadMenu(void);
|
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 *folderPath, char *fileName);
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
#include "pin.h"
|
#include "pin.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
#include "fmt.h"
|
||||||
|
|
||||||
extern CfgData configData;
|
extern CfgData configData;
|
||||||
extern ConfigurationStatus needConfig;
|
extern ConfigurationStatus needConfig;
|
||||||
@ -263,8 +264,8 @@ boot:
|
|||||||
|
|
||||||
if(res != 0)
|
if(res != 0)
|
||||||
{
|
{
|
||||||
char patchesError[] = "Failed to apply FIRM patch(es).";
|
char patchesError[64];
|
||||||
decItoa(res, patchesError + 16, 2);
|
sprintf(patchesError, "Failed to apply %u FIRM patch(es).", res);
|
||||||
error(patchesError);
|
error(patchesError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
source/pin.c
26
source/pin.c
@ -50,11 +50,10 @@ void newPin(bool allowSkipping, u32 pinMode)
|
|||||||
|
|
||||||
u8 length = 4 + 2 * (pinMode - 1);
|
u8 length = 4 + 2 * (pinMode - 1);
|
||||||
|
|
||||||
drawString("Enter a new PIN using ABXY and the DPad", true, 10, 10, COLOR_TITLE);
|
drawString(true, 10, 10, COLOR_TITLE, "Enter a new PIN using ABXY and the DPad");
|
||||||
drawString(allowSkipping ? "Press START to skip, SELECT to reset" : "Press SELECT to reset", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, allowSkipping ? "Press START to skip, SELECT to reset" : "Press SELECT to reset");
|
||||||
|
|
||||||
drawString("PIN ( digits): ", true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
drawFormattedString(true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE, "PIN (%u digits): ", length);
|
||||||
drawCharacter('0' + length, true, 10 + 5 * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
|
||||||
|
|
||||||
//Pad to AES block length with zeroes
|
//Pad to AES block length with zeroes
|
||||||
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
|
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
|
||||||
@ -67,7 +66,7 @@ void newPin(bool allowSkipping, u32 pinMode)
|
|||||||
if(reset)
|
if(reset)
|
||||||
{
|
{
|
||||||
for(u32 i = 0; i < cnt; i++)
|
for(u32 i = 0; i < cnt; i++)
|
||||||
drawCharacter((char)enteredPassword[i], true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK);
|
drawCharacter(true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK, (char)enteredPassword[i]);
|
||||||
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
reset = false;
|
reset = false;
|
||||||
@ -97,7 +96,7 @@ void newPin(bool allowSkipping, u32 pinMode)
|
|||||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||||
|
|
||||||
//Visualize character on screen
|
//Visualize character on screen
|
||||||
drawCharacter(enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
drawCharacter(true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE, enteredPassword[cnt]);
|
||||||
|
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
@ -143,11 +142,10 @@ bool verifyPin(u32 pinMode)
|
|||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("Enter the PIN using ABXY and the DPad to proceed", true, 10, 10, COLOR_TITLE);
|
drawString(true, 10, 10, COLOR_TITLE, "Enter the PIN using ABXY and the DPad to proceed");
|
||||||
drawString("Press START to shutdown, SELECT to clear", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press START to shutdown, SELECT to clear");
|
||||||
|
|
||||||
drawString("PIN ( digits): ", true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
drawFormattedString(true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE, "PIN (%u digits): ", lengthBlock[0]);
|
||||||
drawCharacter('0' + lengthBlock[0], true, 10 + 5 * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
|
||||||
|
|
||||||
const char *messageFile = "pinmessage.txt";
|
const char *messageFile = "pinmessage.txt";
|
||||||
char message[801];
|
char message[801];
|
||||||
@ -157,7 +155,7 @@ bool verifyPin(u32 pinMode)
|
|||||||
if(messageSize != 0)
|
if(messageSize != 0)
|
||||||
{
|
{
|
||||||
message[messageSize] = 0;
|
message[messageSize] = 0;
|
||||||
drawString(message, false, 10, 10, COLOR_WHITE);
|
drawString(false, 10, 10, COLOR_WHITE, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Pad to AES block length with zeroes
|
//Pad to AES block length with zeroes
|
||||||
@ -172,7 +170,7 @@ bool verifyPin(u32 pinMode)
|
|||||||
if(reset)
|
if(reset)
|
||||||
{
|
{
|
||||||
for(u32 i = 0; i < cnt; i++)
|
for(u32 i = 0; i < cnt; i++)
|
||||||
drawCharacter('*', true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK);
|
drawCharacter(true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK, '*');
|
||||||
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
reset = false;
|
reset = false;
|
||||||
@ -201,7 +199,7 @@ bool verifyPin(u32 pinMode)
|
|||||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||||
|
|
||||||
//Visualize character on screen
|
//Visualize character on screen
|
||||||
drawCharacter('*', true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
drawCharacter(true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE, '*');
|
||||||
|
|
||||||
if(++cnt < lengthBlock[0]) continue;
|
if(++cnt < lengthBlock[0]) continue;
|
||||||
|
|
||||||
@ -212,7 +210,7 @@ bool verifyPin(u32 pinMode)
|
|||||||
{
|
{
|
||||||
reset = true;
|
reset = true;
|
||||||
|
|
||||||
drawString("Wrong PIN, try again", true, 10, 10 + 5 * SPACING_Y, COLOR_RED);
|
drawString(true, 10, 10 + 5 * SPACING_Y, COLOR_RED, "Wrong PIN, try again");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,35 +32,12 @@ u32 strlen(const char *string)
|
|||||||
return stringEnd - string;
|
return stringEnd - string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void concatenateStrings(char *destination, const char *source)
|
u32 strnlen(const char *string, u32 maxlen)
|
||||||
{
|
{
|
||||||
u32 i = strlen(source),
|
u32 size;
|
||||||
j = strlen(destination);
|
for(size = 0; size < maxlen && *string; string++, size++);
|
||||||
|
|
||||||
memcpy(&destination[j], source, i + 1);
|
return size;
|
||||||
}
|
|
||||||
|
|
||||||
void hexItoa(u32 number, char *out, u32 digits, bool fillString)
|
|
||||||
{
|
|
||||||
const char hexDigits[] = "0123456789ABCDEF";
|
|
||||||
u32 i;
|
|
||||||
|
|
||||||
for(i = 0; number > 0; i++)
|
|
||||||
{
|
|
||||||
out[digits - 1 - i] = hexDigits[number & 0xF];
|
|
||||||
number >>= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fillString) while(i < digits) out[digits - 1 - i++] = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void decItoa(u32 number, char *out, u32 digits)
|
|
||||||
{
|
|
||||||
for(u32 i = 0; number > 0; i++)
|
|
||||||
{
|
|
||||||
out[digits - 1 - i] = '0' + number % 10;
|
|
||||||
number /= 10;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 hexAtoi(const char *in, u32 digits)
|
u32 hexAtoi(const char *in, u32 digits)
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
u32 strlen(const char *string);
|
u32 strlen(const char *string);
|
||||||
void concatenateStrings(char *destination, const char *source);
|
u32 strnlen(const char *string, u32 maxlen);
|
||||||
void hexItoa(u32 number, char *out, u32 digits, bool fillString);
|
|
||||||
void decItoa(u32 number, char *out, u32 digits);
|
|
||||||
u32 hexAtoi(const char *in, u32 digits);
|
u32 hexAtoi(const char *in, u32 digits);
|
||||||
u32 decAtoi(const char *in, u32 digits);
|
u32 decAtoi(const char *in, u32 digits);
|
@ -110,9 +110,9 @@ void error(const char *message)
|
|||||||
{
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("An error has occurred:", true, 10, 10, COLOR_RED);
|
drawString(true, 10, 10, COLOR_RED, "An error has occurred:");
|
||||||
u32 posY = drawString(message, true, 10, 30, COLOR_WHITE);
|
u32 posY = drawString(true, 10, 30, COLOR_WHITE, message);
|
||||||
drawString("Press any button to shutdown", true, 10, posY + 2 * SPACING_Y, COLOR_WHITE);
|
drawString(true, 10, posY + 2 * SPACING_Y, COLOR_WHITE, "Press any button to shutdown");
|
||||||
|
|
||||||
waitInput(false);
|
waitInput(false);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user