diff --git a/source/arm9/firmwriter.c b/source/arm9/firmwriter.c index d34f053..dcb4be8 100644 --- a/source/arm9/firmwriter.c +++ b/source/arm9/firmwriter.c @@ -11,17 +11,94 @@ #include "arm9/menu.h" #include "arm9/timer.h" -void firmwriterInit() -{ +static size_t totalToWrite; +static size_t totalWritten; +static size_t curSector; +static bool protectSig; +static bool failure; +void firmwriterInit(size_t sector, size_t sectorCount, bool preserveSignature) +{ + if(sectorCount < 2) + panic(); + + totalToWrite = sectorCount; + totalWritten = 0; + // +1 because we'll write the firm header afterwards + curSector = sector + 1; + protectSig = preserveSignature; + failure = false; } bool firmwriterWriteBlock() { + void *sourceBuf = (void *) FIRM_LOAD_ADDR + (totalWritten + 1) * 0x200; + u32 blockData[0x80]; + if(totalWritten >= totalToWrite - 1) + return false; + + if(!dev_rawnand->write_sector(curSector, 0x200, sourceBuf)) + { + failure = true; + return false; + } + + /* read back data and compare */ + if(!dev_rawnand->read_sector(sector, sizeof blockData, blockData) || + memcmp(sourceBuf, blockData, sizeof blockData) != 0) + { + failure = true; + return false; + } + + curSector++; + totalWritten++; + + return true; +} + +bool firmwriterIsDone() +{ + if(failure) + return false; + + return totalWritten == totalToWrite - 1; } bool firmwriterFinish() { + u32 blockData[0x80]; + firm_header header; + void *firmBuf = (void *) FIRM_LOAD_ADDR; + size_t sector = curSector - totalWritten - 1; + /* read signature from NAND if we want to keep sighax */ + if(protectSig) + { + if(!dev_rawnand->read_sector(sector, sizeof header, &header)) + { + failure = true; + return false; + } + + memcpy(header, firmBuf, 0x100); + firmBuf = (void *) header; + } + + if(!dev_rawnand->write_sector(sector, 0x200, firmBuf); + { + failure = true; + return false; + } + + /* read back data and compare */ + if(!dev_rawnand->read_sector(sector, sizeof blockData, blockData) || + memcmp(firmBuf, blockData, sizeof blockData) != 0) + { + failure = true; + return false; + } + + return true; } diff --git a/source/arm9/menu_update.c b/source/arm9/menu_update.c index 88a4c70..cc5848d 100644 --- a/source/arm9/menu_update.c +++ b/source/arm9/menu_update.c @@ -13,12 +13,17 @@ #include "arm9/menu.h" #include "arm9/timer.h" +#define MIN_UPDATE_SIZE 0x1000 + static const char *updateFilePath = "sdmc:\\fastboot3ds.bin"; +static const char *installPath = "firm0" bool menuUpdateLoader() { u8 *updateBuffer = (u8 *) FIRM_LOAD_ADDR; FILINFO fileStat; + size_t fwSize; + size_t sector; uiClearConsoles(); consoleSelect(&con_top); @@ -39,6 +44,15 @@ uiPrintError("Invalid update file!\n"); goto fail; } + + // XXX + fwSize = calcFirmwareSize(); + + if(fwSize < MIN_UPDATE_SIZE || fwSize % 0x200) // this would be really odd. + { + uiPrintError("Invalid update file!\n"); + goto fail; + } // verify fastboot magic if(memcmp(updateBuffer+0x208, "FASTBOOT 3DS ", 0x10) != 0) @@ -67,8 +81,52 @@ goto fail; } + /* NOTE: We assume sighax is installed on firm0 */ + + sector = partitionGetSector(installPath); + uiPrintTextAt(0, 4, "Updating...\n"); + firmwriterInit(sector, fwSize / 0x200, true); + + for(size_t i=0; i