diff --git a/include/arm9/debug.h b/include/arm9/debug.h index fbff661..9719422 100644 --- a/include/arm9/debug.h +++ b/include/arm9/debug.h @@ -4,4 +4,5 @@ void hashCodeRoData(); noreturn void panic(); +noreturn void panicMsg(const char *msg); void dumpMem(u8 *mem, u32 size, char *filepath); diff --git a/include/util.h b/include/util.h index e2c178b..ddefc0f 100644 --- a/include/util.h +++ b/include/util.h @@ -17,6 +17,8 @@ // custom safe strncpy, string is always 0-terminated for buflen > 0 void strncpy_s(char *dest, const char *src, u32 nchars, const u32 buflen); +void memcpy_s(void *dstBuf, size_t dstBufSize, size_t dstBufOffset, + void *srcBuf, size_t srcBufSize, size_t srcBufOffset); u32 getleu32(const void* ptr); diff --git a/source/arm9/config.c b/source/arm9/config.c index 5f6226e..198dfa8 100644 --- a/source/arm9/config.c +++ b/source/arm9/config.c @@ -35,7 +35,8 @@ bool (*write)(AttributeEntryType *attr, void *newData, int key); } FunctionsEntryType; - +bool createConfigFile(); +bool writeConfigFile(); static bool parseConfigFile(); static bool parseBootOption(AttributeEntryType *attr); static bool writeBootOption(AttributeEntryType *attr, void *newData, int key); @@ -81,15 +82,28 @@ u32 fileSize; unsigned bytesRead; + // does the config file exist? if(f_stat(filepath, &fileStat) != FR_OK) { - printf("Failed to get config-file status!\n"); - goto fail; + // try to create a file + if(!createConfigFile()) + return false; + // does it work now? + if(f_stat(filepath, &fileStat) != FR_OK) + return false; + } + else // file exists + { + if(filebuf) // but we are reloading the settings, so free the old buffer + { + free(filebuf); + filebuf = NULL; + } } fileSize = fileStat.fsize; - if(fileSize > MAX_FILE_SIZE || fileSize == 0) + if(fileSize > MAX_FILE_SIZE) { printf("Invalid config-file size!\n"); goto fail; @@ -128,23 +142,26 @@ return false; } -static bool writeConfigFile() +bool writeConfigFile() { const u32 fileSize = strlen(filebuf); unsigned int bytesWritten; if(fileSize > MAX_FILE_SIZE) - panic(); + panicMsg("fileSize too large!"); if(f_open(&file, filepath, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) { goto fail; } - if((f_write(&file, filebuf, fileSize, &bytesWritten) != FR_OK) || (bytesWritten != fileSize)) + if(fileSize) { - f_close(&file); - goto fail; + if((f_write(&file, filebuf, fileSize, &bytesWritten) != FR_OK) || (bytesWritten != fileSize)) + { + f_close(&file); + goto fail; + } } f_close(&file); @@ -158,14 +175,13 @@ bool createConfigFile() { - filebuf = (char *) malloc(MAX_FILE_SIZE + 1); + if(!filebuf) + filebuf = (char *) malloc(MAX_FILE_SIZE + 1); if(!filebuf) return false; - filebuf[0] = 0x0d; - filebuf[1] = 0x0a; - filebuf[2] = 0x00; + filebuf[0] = '\0'; return writeConfigFile(); } @@ -297,13 +313,23 @@ if(diff) { - if(curTextLen < newLen) - memcpy(textData + diff, textData + curTextLen, - curLen - (filebuf - textData + diff) + 1); + if(newLen > curTextLen) + { + size_t backupLen = curLen - (textData - filebuf) - curTextLen + 1; + char *tempBuf = (char *) malloc(backupLen); + if(!tempBuf) + return 0; + memcpy(tempBuf, textData + curTextLen, backupLen); + + memcpy_s(filebuf, MAX_FILE_SIZE + 1, textData - filebuf + newLen, + tempBuf, backupLen, 0); + } else - memcpy(textData + newLen, textData + curTextLen, - curLen - (filebuf - textData + curTextLen) + 1); - + { + memcpy_s(filebuf, MAX_FILE_SIZE + 1, textData - filebuf + newLen, + filebuf, MAX_FILE_SIZE + 1, textData - filebuf + curTextLen); + } + for(u32 key=0; key textData) @@ -564,7 +590,7 @@ attr = &attributes[key]; if(!keyFunctions[key].write) - panic(); + panicMsg("Unimplemented key function!"); return keyFunctions[key].write(attr, data, key); } diff --git a/source/arm9/debug.c b/source/arm9/debug.c index ecbebcb..8c51a31 100644 --- a/source/arm9/debug.c +++ b/source/arm9/debug.c @@ -41,11 +41,29 @@ for(;;) waitForIrq(); } +noreturn void panicMsg(const char *msg) +{ + register u32 lr __asm__("lr"); + + consoleInit(0, NULL); + + printf("\x1b[41m\x1b[0J\x1b[9C****PANIC!!!****\n\nlr = 0x%08" PRIX32 "\n", lr); + printf("\nERROR MESSAGE:\n%s\n", msg); + + unmount_fs(); + devs_close(); + + PXI_sendWord(PXI_CMD_ALLOW_POWER_OFF); + + for(;;) waitForIrq(); +} + // Expects the registers in the exception stack to be in the following order: // cpsr, pc (unmodified), r0-r14 noreturn void guruMeditation(u8 type, u32 *excStack) { const char *typeStr[3] = {"Undefined instruction", "Prefetch abort", "Data abort"}; + const size_t maxStackWords = 15 * 2; u32 realPc, instSize = 4; bool codeChanged = false; @@ -83,10 +101,11 @@ excStack[9], realPc); // make sure we can actually dump the stack without triggering another fault. - if((excStack[15] >= (u32)A9_STACK_START) && (excStack[15] < (u32)A9_STACK_END)) + if((excStack[15] >= (u32)A9_STACK_START) && (excStack[15] < (u32)A9_STACK_END) && + (excStack[15] + maxStackWords * 4 < (u32)A9_STACK_END)) { puts("Stack dump:"); - for(u32 i = 0; i < 15; i++) + for(u32 i = 0; i < maxStackWords / 2; i++) { printf("0x%08" PRIX32 ": %08" PRIX32 " %08" PRIX32 "\n", excStack[15], ((u32*)excStack[15])[0], ((u32*)excStack[15])[1]); diff --git a/source/arm9/menu.c b/source/arm9/menu.c index 936e41b..b466952 100644 --- a/source/arm9/menu.c +++ b/source/arm9/menu.c @@ -386,8 +386,11 @@ menu_state = menu_next_state; break; case MENU_EVENT_SD_CARD_INSERTED: - dev_sdcard->init(); // try to initialize sd card + // try to initialize sd card + dev_sdcard->init(); f_mount(&sd_fs, "sdmc:", 1); + // also try to load saved settings + loadConfigFile(); break; case MENU_EVENT_SD_CARD_REMOVED: // what else to do here? diff --git a/source/arm9/menu_options.c b/source/arm9/menu_options.c index edba406..23b59ab 100644 --- a/source/arm9/menu_options.c +++ b/source/arm9/menu_options.c @@ -175,6 +175,8 @@ } done: + + writeConfigFile(); menuActState(); menuSetReturnToState(STATE_PREVIOUS); diff --git a/source/util.c b/source/util.c index 0e38e0f..e45192e 100644 --- a/source/util.c +++ b/source/util.c @@ -1,4 +1,5 @@ #include "util.h" +#include void wait(u32 cycles) { @@ -57,6 +58,25 @@ *dest = '\0'; } +// custom safe memcpy +void memcpy_s(void *dstBuf, size_t dstBufSize, size_t dstBufOffset, + void *srcBuf, size_t srcBufSize, size_t srcBufOffset) +{ + size_t dstRemaining, srcRemaining, actualSize; + + if(dstBufOffset >= dstBufSize) + return; + if(srcBufOffset >= srcBufSize) + return; + + dstRemaining = dstBufSize - dstBufOffset; + srcRemaining = srcBufSize - srcBufOffset; + + actualSize = min(dstRemaining, srcRemaining); + + memcpy(dstBuf+dstBufOffset, srcBuf+srcBufOffset, actualSize); +} + u32 getleu32(const void* ptr) { const u8* p = (const u8*)ptr;