From db69aca1b49733da51f64ee857ac9b861b1c468c Mon Sep 17 00:00:00 2001 From: Pk11 Date: Mon, 21 Feb 2022 23:43:50 -0600 Subject: [PATCH] Fix save file FAT header generation --- arm9/src/sav.c | 154 ++++++++++++++++++++----------------------------- 1 file changed, 62 insertions(+), 92 deletions(-) diff --git a/arm9/src/sav.c b/arm9/src/sav.c index 9eaba01..ed27cd2 100644 --- a/arm9/src/sav.c +++ b/arm9/src/sav.c @@ -2,51 +2,7 @@ #include #include -static u32 _getClusterSize(u32 sizebytes) -{ - if (sizebytes < 573440) - return 512; - - else if (sizebytes < 5472256) - return 2048; - - else if (sizebytes < 17301504) - return 4096; - - else - return 2048; -} - -static u16 _getMaxFiles(u32 sizebytes) -{ - if (sizebytes < 573440) - return 16; - - else - return 256; -} - -//wip -static u16 _getFatz(u32 sizebytes) -{ - if (sizebytes <= 0x4000) //16 kb - return 1; - - else if (sizebytes <= 0x200000) //2 mb - return 3; - - else - return 6; -} - -//wip -static u16 _getTotSec16(u32 sizebytes, u16 bytesPerSec) -{ - if (sizebytes == 0x4000) //16 kb - return 27; - - return sizebytes / bytesPerSec; -} +#define align(v, a) (((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v)) bool initFatHeader(FILE* f) { @@ -57,61 +13,75 @@ bool initFatHeader(FILE* f) fseek(f, 0, SEEK_END); u32 size = ftell(f); + //based on GodMode9 + //https://github.com/d0k3/GodMode9/blob/d8d43c14f3317423c677b1c7e0987bcb9bbd7299/arm9/source/game/nds.c#L47-L105 + const u16 sectorSize = 0x200; + + //fit maximum sectors for the size + const u16 maxSectors = size / sectorSize; + u16 sectorCount = 1; + u16 secPerTrk = 1; + u16 numHeads = 1; + u16 sectorCountNext = 0; + while (sectorCountNext <= maxSectors) + { + sectorCountNext = secPerTrk * (numHeads + 1) * (numHeads + 1); + if (sectorCountNext <= maxSectors) + { + numHeads++; + sectorCount = sectorCountNext; + + secPerTrk++; + sectorCountNext = secPerTrk * numHeads * numHeads; + if (sectorCountNext <= maxSectors) + { + sectorCount = sectorCountNext; + } + } + } + sectorCountNext = (secPerTrk + 1) * numHeads * numHeads; + if (sectorCountNext <= maxSectors) + { + secPerTrk++; + sectorCount = sectorCountNext; + } + + u8 secPerCluster = (sectorCount > (8 << 10)) ? 8 : (sectorCount > (1 << 10) ? 4 : 1); + + u16 rootEntryCount = size < 0x8C000 ? 0x20 : 0x200; + + u16 totalClusters = align(sectorCount, secPerCluster) / secPerCluster; + u32 fatBytes = (align(totalClusters, 2) / 2) * 3; // 2 sectors -> 3 byte + u16 fatSize = align(fatBytes, sectorSize) / sectorSize; + + FATHeader* h = (FATHeader*)malloc(sizeof(FATHeader)); h->BS_JmpBoot[0] = 0xE9; h->BS_JmpBoot[1] = 0; h->BS_JmpBoot[2] = 0; - h->BS_OEMName[0] = 'M'; - h->BS_OEMName[1] = 'S'; - h->BS_OEMName[2] = 'W'; - h->BS_OEMName[3] = 'I'; - h->BS_OEMName[4] = 'N'; - h->BS_OEMName[5] = '4'; - h->BS_OEMName[6] = '.'; - h->BS_OEMName[7] = '1'; + memcpy(h->BS_OEMName, "MSWIN4.1", 8); - h->BPB_BytesPerSec = 512; - h->BPB_SecPerClus = _getClusterSize(size) / h->BPB_BytesPerSec; - h->BPB_RsvdSecCnt = 1; - h->BPB_NumFATs = 2; - h->BPB_RootEntCnt = _getMaxFiles(size) * 2; - h->BPB_TotSec16 = _getTotSec16(size, h->BPB_BytesPerSec); // - h->BPB_Media = 0xF8; - h->BPB_FATSz16 = _getFatz(size); // - h->BPB_SecPerTrk = 0; - h->BPB_NumHeads = 0; - h->BPB_HiddSec = 0; - h->BPB_TotSec32 = 0; - h->BS_DrvNum = 0x07; - h->BS_Reserved1 = 0; + h->BPB_BytesPerSec = sectorSize; + h->BPB_SecPerClus = secPerCluster; + h->BPB_RsvdSecCnt = 0x0001; + h->BPB_NumFATs = 0x02; + h->BPB_RootEntCnt = rootEntryCount; + h->BPB_TotSec16 = sectorCount; + h->BPB_Media = 0xF8; // "hard drive" + h->BPB_FATSz16 = fatSize; + h->BPB_SecPerTrk = secPerTrk; + h->BPB_NumHeads = numHeads; + h->BPB_HiddSec = 0x00000000; + h->BPB_TotSec32 = 0x00000000; + h->BS_DrvNum = 0x05; + h->BS_Reserved1 = 0x00; h->BS_BootSig = 0x29; - h->BS_VolID = 305419896; - - h->BS_VolLab[0] = 'V'; - h->BS_VolLab[1] = 'O'; - h->BS_VolLab[2] = 'L'; - h->BS_VolLab[3] = 'U'; - h->BS_VolLab[4] = 'M'; - h->BS_VolLab[5] = 'E'; - h->BS_VolLab[6] = 'L'; - h->BS_VolLab[7] = 'A'; - h->BS_VolLab[8] = 'B'; - h->BS_VolLab[9] = 'E'; - h->BS_VolLab[10] = 'L'; - - h->BS_FilSysType[0] = 'F'; - h->BS_FilSysType[1] = 'A'; - h->BS_FilSysType[2] = 'T'; - h->BS_FilSysType[3] = '1'; - h->BS_FilSysType[4] = '2'; - h->BS_FilSysType[5] = ' '; - h->BS_FilSysType[6] = ' '; - h->BS_FilSysType[7] = ' '; - - memset(h->BS_BootCode, 0, 448); - + h->BS_VolID = 0x12345678; + memcpy(h->BS_VolLab, "VOLUMELABEL", 11); + memcpy(h->BS_FilSysType,"FAT12 ", 8); + memset(h->BS_BootCode, 0, sizeof(h->BS_BootCode)); h->BS_BootSign = 0xAA55; fseek(f, 0, SEEK_SET);