diff --git a/arm9/source/fs.c b/arm9/source/fs.c index 17a6b1b..300a59f 100644 --- a/arm9/source/fs.c +++ b/arm9/source/fs.c @@ -37,6 +37,8 @@ #include "firm.h" #include "crypto.h" #include "strings.h" +#include "alignedseqmemcpy.h" +#include "i2c.h" static FATFS sdFs, nandFs; @@ -121,6 +123,79 @@ bool fileDelete(const char *path) return f_unlink(path) == FR_OK; } +bool fileCopy(const char *pathSrc, const char *pathDst, bool replace, void *tmpBuffer, size_t bufferSize) +{ + FIL fileSrc, fileDst; + FRESULT res; + + res = f_open(&fileSrc, pathSrc, FA_READ); + if (res != FR_OK) + return true; // Succeed if the source file doesn't exist + + size_t szSrc = f_size(&fileSrc), rem = szSrc; + + res = f_open(&fileDst, pathDst, FA_WRITE | (replace ? FA_CREATE_ALWAYS : FA_CREATE_NEW)); + + if (res == FR_EXIST) + { + // We did not fail + f_close(&fileSrc); + return true; + } + else if (res == FR_NO_PATH) + { + const char *c; + for (c = pathDst + strlen(pathDst); *c != '/' && c >= pathDst; --c); + if (c >= pathDst && c - pathDst <= FF_MAX_LFN && *c != '\0') + { + char path[FF_MAX_LFN + 1]; + strncpy(path, pathDst, c - pathDst); + path[FF_MAX_LFN] = '\0'; + res = f_mkdir(path); + } + + if (res == FR_OK) + res = f_open(&fileDst, pathDst, FA_WRITE | (replace ? FA_CREATE_ALWAYS : FA_CREATE_NEW)); + } + + if (res != FR_OK) + { + f_close(&fileSrc); + return false; + } + + while (rem > 0) + { + size_t sz = rem >= bufferSize ? bufferSize : rem; + UINT n = 0; + + res = f_read(&fileSrc, tmpBuffer, sz, &n); + if (n != sz) + res = FR_INT_ERR; // should not happen + + if (res == FR_OK) + { + res = f_write(&fileDst, tmpBuffer, sz, &n); + if (n != sz) + res = FR_DENIED; // disk full + } + + if (res != FR_OK) + { + f_close(&fileSrc); + f_close(&fileDst); + f_unlink(pathDst); // oops, failed + return false; + } + rem -= sz; + } + + f_close(&fileSrc); + f_close(&fileDst); + + return true; +} + bool findPayload(char *path, u32 pressed) { const char *pattern; @@ -309,3 +384,39 @@ void findDumpFile(const char *folderPath, char *fileName) if(result == FR_OK) f_closedir(&dir); } + +static u8 fileCopyBuffer[0x1000]; +bool backupEssentialFiles(void) +{ + size_t sz = sizeof(fileCopyBuffer); + + bool ok = !(isSdMode && !mountFs(false, false)); + + ok = ok && fileCopy("1:/ro/sys/HWCAL0.dat", "backups/HWCAL0.dat", false, fileCopyBuffer, sz); + ok = ok && fileCopy("1:/ro/sys/HWCAL1.dat", "backups/HWCAL1.dat", false, fileCopyBuffer, sz); + + ok = ok && fileCopy("1:/rw/sys/LocalFriendCodeSeed_A", "backups/LocalFriendCodeSeed_A", false, fileCopyBuffer, sz); // often doesn't exist + ok = ok && fileCopy("1:/rw/sys/LocalFriendCodeSeed_B", "backups/LocalFriendCodeSeed_B", false, fileCopyBuffer, sz); + + ok = ok && fileCopy("1:/rw/sys/SecureInfo_A", "backups/SecureInfo_A", false, fileCopyBuffer, sz); + ok = ok && fileCopy("1:/rw/sys/SecureInfo_B", "backups/SecureInfo_B", false, fileCopyBuffer, sz); // often doesn't exist + + if (!ok) return false; + + alignedseqmemcpy(fileCopyBuffer, (const void *)0x10012000, 0x100); + if (getFileSize("backups/otp.bin") != 0x100) + ok = ok && fileWrite(fileCopyBuffer, "backups/otp.bin", 0x100); + + if (!ok) return false; + + // On dev boards, but not O3DS IS_DEBUGGER, hwcal is on an EEPROM chip accessed via I2C + u8 c = mcuConsoleInfo[0]; + if (c == 2 || c == 4 || (ISN3DS && c == 5) || c == 6) + { + I2C_readRegBuf(I2C_DEV_EEPROM, 0, fileCopyBuffer, 0x1000); // Up to two instances of hwcal, with the second one @0x800 + if (getFileSize("backups/HWCAL_01_EEPROM.dat") != 0x1000) + ok = ok && fileWrite(fileCopyBuffer, "backups/HWCAL_01_EEPROM.dat", 0x1000); + } + + return ok; +} diff --git a/arm9/source/fs.h b/arm9/source/fs.h index db83b2a..99c5a9c 100644 --- a/arm9/source/fs.h +++ b/arm9/source/fs.h @@ -35,7 +35,10 @@ u32 fileRead(void *dest, const char *path, u32 maxSize); u32 getFileSize(const char *path); bool fileWrite(const void *buffer, const char *path, u32 size); bool fileDelete(const char *path); +bool fileCopy(const char *pathSrc, const char *pathDst, bool replace, void *tmpBuffer, size_t bufferSize); bool findPayload(char *path, u32 pressed); bool payloadMenu(char *path, bool *hasDisplayedMenu); u32 firmRead(void *dest, u32 firmType); void findDumpFile(const char *folderPath, char *fileName); + +bool backupEssentialFiles(void); diff --git a/arm9/source/main.c b/arm9/source/main.c index 50b6666..927cacb 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -49,6 +49,9 @@ bool isSdMode; u16 launchedPath[80+1]; BootType bootType; +u16 mcuFwVersion; +u8 mcuConsoleInfo[9]; + void main(int argc, char **argv, u32 magicWord) { bool isFirmProtEnabled, @@ -117,6 +120,11 @@ void main(int argc, char **argv, u32 magicWord) memcpy(__itcm_start__, __itcm_lma__, __itcm_bss_start__ - __itcm_start__); memset(__itcm_bss_start__, 0, __itcm_end__ - __itcm_bss_start__); I2C_init(); + + I2C_readRegBuf(I2C_DEV_MCU, 0x00, (u8 *)&mcuFwVersion, 2); + if ((mcuFwVersion & 0xFFF) < 0x0100) error("Unsupported MCU FW version."); + I2C_readRegBuf(I2C_DEV_MCU, 0x7F, mcuConsoleInfo, 9); + if(isInvalidLoader) error("Launched using an unsupported loader."); installArm9Handlers(); diff --git a/arm9/source/types.h b/arm9/source/types.h index e4646bb..871bb45 100644 --- a/arm9/source/types.h +++ b/arm9/source/types.h @@ -130,3 +130,6 @@ extern BootType bootType; extern u16 launchedFirmTidLow[8]; extern u16 launchedPath[80+1]; + +extern u16 mcuFwVersion; +extern u8 mcuConsoleInfo[9];