From d75ab87bfb20ab61e006cbd5555fd8bd2f49c763 Mon Sep 17 00:00:00 2001 From: Pk11 Date: Mon, 27 Sep 2021 00:41:06 -0500 Subject: [PATCH 01/10] WIP: Fix NAND cart dumping --- arm9/source/dumpOperations.cpp | 143 ++++++++++++++++++++++++--------- arm9/source/ndsheaderbanner.h | 5 +- arm9/source/read_card.c | 34 +++++++- 3 files changed, 143 insertions(+), 39 deletions(-) diff --git a/arm9/source/dumpOperations.cpp b/arm9/source/dumpOperations.cpp index 1cdafc5..97b711c 100644 --- a/arm9/source/dumpOperations.cpp +++ b/arm9/source/dumpOperations.cpp @@ -20,6 +20,16 @@ extern bool expansionPakFound; static sNDSHeaderExt ndsCardHeader; +void dumpFailMsg(bool save) { + font->clear(false); + font->printf(0, 0, false, Alignment::left, Palette::white, "Failed to dump the %s.", save ? "save" : "ROM"); + font->update(false); + + for (int i = 0; i < 60*2; i++) { + swiWaitForVBlank(); + } +} + //--------------------------------------------------------------------------------- // https://github.com/devkitPro/libnds/blob/master/source/common/cardEeprom.c#L74 // with Pokémon Mystery Dungeon - Explorers of Sky (128 KiB EEPROM) fixed @@ -157,6 +167,28 @@ void cardEepromChipEraseFixed(void) { } } +u32 cardNandGetSaveSize(void) { + u32 id = cardReadID(CARD_CLK_SLOW); + + u16 flags = id >> 16; + + if ((id & 0xFF) == 0xEC) { // Samsung + switch(flags) { + case 0x8801: + return 8 << 20; // 8MByte - Jam with the Band + break; + case 0x8800: + return 16 << 20; // 16MByte - WarioWare D.I.Y. + break; + case 0xE800: + return 82 << 20; // 82MByte - Face Training + break; + } + } + + return 0; +} + void ndsCardSaveDump(const char* filename) { FILE *out = fopen(filename, "wb"); if(out) { @@ -165,29 +197,76 @@ void ndsCardSaveDump(const char* filename) { font->print(0, 1, false, "Do not remove the NDS card."); font->update(false); - unsigned char *buffer; - auxspi_extra card_type = auxspi_has_extra(); - if(card_type == AUXSPI_INFRARED) { - int size = auxspi_save_size_log_2(card_type); - int size_blocks; - int type = auxspi_save_type(card_type); - if(size < 16) - size_blocks = 1; - else - size_blocks = 1 << (size - 16); - u32 LEN = std::min(1 << size, 1 << 16); - buffer = new unsigned char[LEN*size_blocks]; - auxspi_read_data(0, buffer, LEN*size_blocks, type, card_type); - fwrite(buffer, 1, LEN*size_blocks, out); - } else { - int type = cardEepromGetTypeFixed(); - int size = cardEepromGetSizeFixed(); - buffer = new unsigned char[size]; - cardReadEeprom(0, buffer, size, type); - fwrite(buffer, 1, size, out); + int type = cardEepromGetTypeFixed(); + + if(type == -1) { // NAND + u32 saveSize = cardNandGetSaveSize(); + + if(saveSize == 0) { + dumpFailMsg(true); + return; + } + + // testing print + font->clear(false); + font->printf(0, 0, false, Alignment::left, Palette::white, "Found NAND save: Size: %d MiB", saveSize >> 20); + font->update(false); + for(int i = 0; i < 120; i++) + swiWaitForVBlank(); + + u32 currentSize = saveSize; + FILE* destinationFile = fopen(filename, "wb"); + if (destinationFile) { + + font->print(0, 4, false, "Progress:"); + font->print(0, 5, false, "["); + font->print(-1, 5, false, "]"); + for (u32 src = 0; src < saveSize; src += 0x8000) { + // Print time + font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen); + font->update(true); + + font->print((src / (saveSize / (SCREEN_COLS - 2))) + 1, 5, false, "="); + font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", src, saveSize); + font->update(false); + + for (u32 i = 0; i < 0x8000; i += 0x200) { + cardRead(src+i, copyBuf+i); + } + if (fwrite(copyBuf, 1, (currentSize >= 0x8000 ? 0x8000 : currentSize), destinationFile) < 1) { + dumpFailMsg(true); + break; + } + currentSize -= 0x8000; + } + fclose(destinationFile); + } else { + dumpFailMsg(true); + } + } else { // SPI + unsigned char *buffer; + auxspi_extra card_type = auxspi_has_extra(); + if(card_type == AUXSPI_INFRARED) { + int size = auxspi_save_size_log_2(card_type); + int size_blocks; + int type = auxspi_save_type(card_type); + if(size < 16) + size_blocks = 1; + else + size_blocks = 1 << (size - 16); + u32 LEN = std::min(1 << size, 1 << 16); + buffer = new unsigned char[LEN*size_blocks]; + auxspi_read_data(0, buffer, LEN*size_blocks, type, card_type); + fwrite(buffer, 1, LEN*size_blocks, out); + } else { + int size = cardEepromGetSizeFixed(); + buffer = new unsigned char[size]; + cardReadEeprom(0, buffer, size, type); + fwrite(buffer, 1, size, out); + } + delete[] buffer; + fclose(out); } - delete[] buffer; - fclose(out); } } @@ -312,16 +391,6 @@ void ndsCardSaveRestore(const char *filename) { } } -void dumpFailMsg(void) { - font->clear(false); - font->print(0, 0, false, "Failed to dump the ROM."); - font->update(false); - - for (int i = 0; i < 60*2; i++) { - swiWaitForVBlank(); - } -} - void ndsCardDump(void) { int pressed = 0; //bool showGameCardMsgAgain = false; @@ -619,14 +688,14 @@ void ndsCardDump(void) { cardRead (src+i, copyBuf+i); } if (fwrite(copyBuf, 1, (currentSize>=0x8000 ? 0x8000 : currentSize), destinationFile) < 1) { - dumpFailMsg(); + dumpFailMsg(false); break; } currentSize -= 0x8000; } fclose(destinationFile); } else { - dumpFailMsg(); + dumpFailMsg(false); } ndsCardSaveDump(destSavPath); //} @@ -752,7 +821,7 @@ void gbaCartDump(void) { FILE* destinationFile = fopen(destPath, "wb"); if (destinationFile) { if (fwrite(GBAROM, 1, romSize, destinationFile) < 1) { - dumpFailMsg(); + dumpFailMsg(false); } else // Check for 64MB GBA Video ROM if (strncmp((char*)0x080000AC, "MSAE", 4)==0 // Shark Tale @@ -774,14 +843,14 @@ void gbaCartDump(void) { writeChange(cmd); readChange(); if (fwrite(GBAROM + (0x1000 >> 1), 0x1000, 1, destinationFile) < 1) { - dumpFailMsg(); + dumpFailMsg(false); break; } } } fclose(destinationFile); } else { - dumpFailMsg(); + dumpFailMsg(false); } // Save file diff --git a/arm9/source/ndsheaderbanner.h b/arm9/source/ndsheaderbanner.h index 7d0c42f..133b2e3 100644 --- a/arm9/source/ndsheaderbanner.h +++ b/arm9/source/ndsheaderbanner.h @@ -85,7 +85,10 @@ typedef struct { u32 romSize; //!< total size of the ROM. u32 headerSize; //!< ROM header size. - u32 zeros88[14]; + u32 zeros88[3]; + u16 nandRomEnd; //!< ROM region end for NAND games. + u16 nandRwStart; //!< RW region start for NAND games. + u32 zeros98[10]; u8 gbaLogo[156]; //!< Nintendo logo needed for booting the game. u16 logoCRC16; //!< Nintendo Logo Checksum, CRC-16. u16 headerCRC16; //!< header checksum, CRC-16. diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index 41f45c1..dcfa798 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -42,6 +42,18 @@ enum { ERR_HEAD_CRC = 0x16, } ERROR_CODES; +// NAND Card commands +// https://problemkaputt.de/gbatek-ds-cartridge-nand.htm +#define CARD_CMD_NAND_WRITE_BUFFER 0x81 +#define CARD_CMD_NAND_FLUSH_BUFFER 0x82 +#define CARD_CMD_NAND_DISCARD_BUFFER 0x84 +#define CARD_CMD_NAND_WRITE_ENABLE 0x85 +#define CARD_CMD_NAND_ROM_MODE 0x8B +#define CARD_CMD_NAND_RW_MODE 0xB2 +#define CARD_CMD_NAND_READ_STATUS 0xD6 +#define CARD_CMD_NAND_UNKNOWN 0xBB +#define CARD_CMD_NAND_READ_ID 0x94 + typedef union { char title[4]; @@ -51,6 +63,8 @@ typedef union static bool twlBlowfish = false; static bool normalChip = false; // As defined by GBAtek, normal chip secure area is accessed in blocks of 0x200, other chip in blocks of 0x1000 +static bool nandChip = false; +static bool nandRomMode = true; static u32 portFlags = 0; static u32 headerData[0x1000/sizeof(u32)] = {0}; static u32 secureArea[CARD_SECURE_AREA_SIZE/sizeof(u32)] = {0}; @@ -277,6 +291,7 @@ int cardInit (sNDSHeaderExt* ndsHeader) { u32 portFlagsKey1, portFlagsSecRead; normalChip = false; // As defined by GBAtek, normal chip secure area is accessed in blocks of 0x200, other chip in blocks of 0x1000 + nandRomMode = true; int secureBlockNumber; int i; u8 cmdData[8] __attribute__ ((aligned)); @@ -310,10 +325,17 @@ int cardInit (sNDSHeaderExt* ndsHeader) toncset(headerData, 0, 0x1000); - u32 iCardId=cardReadID(CARD_CLK_SLOW); + u32 iCardId=cardReadID(CARD_CLK_SLOW); while(REG_ROMCTRL & CARD_BUSY); //u32 iCheapCard=iCardId&0x80000000; + // Check if NAND + nandChip = (iCardId >> 24) & BIT(3); + if (nandChip) { + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0); + nandRomMode = true; + } + // Read the header cardParamCommand (CARD_CMD_HEADER_READ, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(1) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), @@ -464,6 +486,16 @@ void cardRead (u32 src, void* dest) return; } + if (nandChip) { + if (src < ndsHeader->nandRomEnd * 0x20000 /*dsi: 80000h?*/ && !nandRomMode) { + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0); + nandRomMode = true; + } else if (src > ndsHeader->nandRwStart * 0x20000 /*dsi: 80000h?*/ && nandRomMode) { + cardParamCommand(CARD_CMD_NAND_RW_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0); + nandRomMode = false; + } + } + cardParamCommand (CARD_CMD_DATA_READ, src, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), dest, 0x200/sizeof(u32)); From 7b105c09a15888d24799d1cdb374ef6209f51ddb Mon Sep 17 00:00:00 2001 From: Pk11 Date: Mon, 4 Oct 2021 18:08:12 -0500 Subject: [PATCH 02/10] Fix NAND card header reading It now tries to dump, but the rest of the dump is garbage. It tries the save too, but I think that's also garbage. This breaks some things that worked before, marked with TODOs. I'll fix them once NAND works. --- arm9/source/dumpOperations.cpp | 40 ++++++++++++------------------ arm9/source/read_card.c | 45 +++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/arm9/source/dumpOperations.cpp b/arm9/source/dumpOperations.cpp index 97b711c..0bf4057 100644 --- a/arm9/source/dumpOperations.cpp +++ b/arm9/source/dumpOperations.cpp @@ -168,22 +168,13 @@ void cardEepromChipEraseFixed(void) { } u32 cardNandGetSaveSize(void) { - u32 id = cardReadID(CARD_CLK_SLOW); - - u16 flags = id >> 16; - - if ((id & 0xFF) == 0xEC) { // Samsung - switch(flags) { - case 0x8801: - return 8 << 20; // 8MByte - Jam with the Band - break; - case 0x8800: - return 16 << 20; // 16MByte - WarioWare D.I.Y. - break; - case 0xE800: - return 82 << 20; // 82MByte - Face Training - break; - } + switch(*(u32*)ndsCardHeader.gameCode & 0x00FFFFFF) { + case 0x00425855: // 'UXB' + return 8 << 20; // 8MByte - Jam with the Band + case 0x00524F55: // 'UOR' + return 16 << 20; // 16MByte - WarioWare D.I.Y. + case 0x004B5355: // 'USK' + return 82 << 20; // 82MByte - Face Training } return 0; @@ -207,13 +198,6 @@ void ndsCardSaveDump(const char* filename) { return; } - // testing print - font->clear(false); - font->printf(0, 0, false, Alignment::left, Palette::white, "Found NAND save: Size: %d MiB", saveSize >> 20); - font->update(false); - for(int i = 0; i < 120; i++) - swiWaitForVBlank(); - u32 currentSize = saveSize; FILE* destinationFile = fopen(filename, "wb"); if (destinationFile) { @@ -231,7 +215,7 @@ void ndsCardSaveDump(const char* filename) { font->update(false); for (u32 i = 0; i < 0x8000; i += 0x200) { - cardRead(src+i, copyBuf+i); + cardRead(ndsCardHeader.nandRwStart + src + i, copyBuf + i); } if (fwrite(copyBuf, 1, (currentSize >= 0x8000 ? 0x8000 : currentSize), destinationFile) < 1) { dumpFailMsg(true); @@ -680,6 +664,11 @@ void ndsCardDump(void) { font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen); font->update(true); + // TODO: Remove, just for testing + scanKeys(); + if(keysDown() & KEY_B) + break; + font->print((src / (romSize / (SCREEN_COLS - 2))) + 1, 5, false, "="); font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", src, romSize); font->update(false); @@ -697,7 +686,8 @@ void ndsCardDump(void) { } else { dumpFailMsg(false); } - ndsCardSaveDump(destSavPath); + // TODO: Uncomment, just commented for testing + // ndsCardSaveDump(destSavPath); //} } } diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index dcfa798..4d5a275 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -300,7 +300,7 @@ int cardInit (sNDSHeaderExt* ndsHeader) twlBlowfish = false; sysSetCardOwner (BUS_OWNER_ARM9); // Allow arm9 to access NDS cart - if (isDSiMode()) { + if (isDSiMode()) { // Reset card slot disableSlot1(); for(i = 0; i < 25; i++) { swiWaitForVBlank(); } @@ -311,18 +311,21 @@ int cardInit (sNDSHeaderExt* ndsHeader) cardParamCommand (CARD_CMD_DUMMY, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(1) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); - } else { - REG_ROMCTRL=0; - REG_AUXSPICNT=0; - //ioDelay2(167550); - for(i = 0; i < 25; i++) { swiWaitForVBlank(); } - REG_AUXSPICNT=CARD_CR1_ENABLE|CARD_CR1_IRQ; - REG_ROMCTRL=CARD_nRESET|CARD_SEC_SEED; - while(REG_ROMCTRL&CARD_BUSY) ; - cardReset(); - while(REG_ROMCTRL&CARD_BUSY) ; } + // TODO: This was only done in DS mode, but fixes NAND in DSi mode + // see if only part of this is needed or if it causes problems to do + // all of it in DSi mode. + REG_ROMCTRL=0; + REG_AUXSPICNT=0; + //ioDelay2(167550); + for(i = 0; i < 25; i++) { swiWaitForVBlank(); } + REG_AUXSPICNT=CARD_CR1_ENABLE|CARD_CR1_IRQ; + REG_ROMCTRL=CARD_nRESET|CARD_SEC_SEED; + while(REG_ROMCTRL&CARD_BUSY) ; + cardReset(); + while(REG_ROMCTRL&CARD_BUSY) ; + toncset(headerData, 0, 0x1000); u32 iCardId=cardReadID(CARD_CLK_SLOW); @@ -332,7 +335,7 @@ int cardInit (sNDSHeaderExt* ndsHeader) // Check if NAND nandChip = (iCardId >> 24) & BIT(3); if (nandChip) { - cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0); + // cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); nandRomMode = true; } @@ -346,9 +349,17 @@ int cardInit (sNDSHeaderExt* ndsHeader) if ((ndsHeader->unitCode != 0) || (ndsHeader->dsi_flags != 0)) { // Extended header found - cardParamCommand (CARD_CMD_HEADER_READ, 0, - CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(4) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), - (void*)headerData, 0x1000/sizeof(u32)); + if(true) { // TODO: some need single 1000h? + for(int i = 0; i < 8; i++) { + cardParamCommand (CARD_CMD_HEADER_READ, i * 0x200, + CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(1) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), + headerData + i * 0x200 / sizeof(u32), 0x200/sizeof(u32)); + } + } else { + cardParamCommand (CARD_CMD_HEADER_READ, 0, + CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(4) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), + (void*)headerData, 0x1000/sizeof(u32)); + } if (ndsHeader->dsi1[0]==0xFFFFFFFF && ndsHeader->dsi1[1]==0xFFFFFFFF && ndsHeader->dsi1[2]==0xFFFFFFFF && ndsHeader->dsi1[3]==0xFFFFFFFF) { @@ -488,10 +499,10 @@ void cardRead (u32 src, void* dest) if (nandChip) { if (src < ndsHeader->nandRomEnd * 0x20000 /*dsi: 80000h?*/ && !nandRomMode) { - cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0); + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); nandRomMode = true; } else if (src > ndsHeader->nandRwStart * 0x20000 /*dsi: 80000h?*/ && nandRomMode) { - cardParamCommand(CARD_CMD_NAND_RW_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0); + cardParamCommand(CARD_CMD_NAND_RW_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); nandRomMode = false; } } From 0dedcfb9ddb7886ac6f17549c3e792074701165f Mon Sep 17 00:00:00 2001 From: Pk11 Date: Mon, 4 Oct 2021 20:27:20 -0500 Subject: [PATCH 03/10] Improve extended header reading --- arm9/source/read_card.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index 4d5a275..c6dc0a3 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -64,7 +64,7 @@ static bool twlBlowfish = false; static bool normalChip = false; // As defined by GBAtek, normal chip secure area is accessed in blocks of 0x200, other chip in blocks of 0x1000 static bool nandChip = false; -static bool nandRomMode = true; +static int nandRomMode = -1; static u32 portFlags = 0; static u32 headerData[0x1000/sizeof(u32)] = {0}; static u32 secureArea[CARD_SECURE_AREA_SIZE/sizeof(u32)] = {0}; @@ -290,8 +290,9 @@ static void switchToTwlBlowfish(sNDSHeaderExt* ndsHeader) { int cardInit (sNDSHeaderExt* ndsHeader) { u32 portFlagsKey1, portFlagsSecRead; - normalChip = false; // As defined by GBAtek, normal chip secure area is accessed in blocks of 0x200, other chip in blocks of 0x1000 - nandRomMode = true; + normalChip = false; // As defined by GBAtek, normal chip secure area and header are accessed in blocks of 0x200, other chip in blocks of 0x1000 + nandChip = false; + nandRomMode = -1; int secureBlockNumber; int i; u8 cmdData[8] __attribute__ ((aligned)); @@ -330,14 +331,9 @@ int cardInit (sNDSHeaderExt* ndsHeader) u32 iCardId=cardReadID(CARD_CLK_SLOW); while(REG_ROMCTRL & CARD_BUSY); - //u32 iCheapCard=iCardId&0x80000000; - // Check if NAND - nandChip = (iCardId >> 24) & BIT(3); - if (nandChip) { - // cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); - nandRomMode = true; - } + normalChip = (iCardId & BIT(31)) != 0; // ROM chip ID MSB + nandChip = (iCardId & BIT(27)) != 0; // Card has a NAND chip // Read the header cardParamCommand (CARD_CMD_HEADER_READ, 0, @@ -349,7 +345,7 @@ int cardInit (sNDSHeaderExt* ndsHeader) if ((ndsHeader->unitCode != 0) || (ndsHeader->dsi_flags != 0)) { // Extended header found - if(true) { // TODO: some need single 1000h? + if(normalChip) { for(int i = 0; i < 8; i++) { cardParamCommand (CARD_CMD_HEADER_READ, i * 0x200, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(1) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), @@ -391,7 +387,6 @@ int cardInit (sNDSHeaderExt* ndsHeader) ((ndsHeader->cardControlBF & (CARD_CLK_SLOW|CARD_DELAY1(0x1FFF))) + ((ndsHeader->cardControlBF & CARD_DELAY2(0x3F)) >> 16)); // Adjust card transfer method depending on the most significant bit of the chip ID - normalChip = (iCardId & 0x80000000) != 0; // ROM chip ID MSB if (!normalChip) { portFlagsKey1 |= CARD_SEC_LARGE; } @@ -497,15 +492,15 @@ void cardRead (u32 src, void* dest) return; } - if (nandChip) { - if (src < ndsHeader->nandRomEnd * 0x20000 /*dsi: 80000h?*/ && !nandRomMode) { - cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); - nandRomMode = true; - } else if (src > ndsHeader->nandRwStart * 0x20000 /*dsi: 80000h?*/ && nandRomMode) { - cardParamCommand(CARD_CMD_NAND_RW_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); - nandRomMode = false; - } - } + // if (nandChip) { + // if (src < ndsHeader->nandRomEnd * 0x20000 /*dsi: 80000h?*/ && nandRomMode != CARD_CMD_NAND_ROM_MODE) { + // cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); + // nandRomMode = CARD_CMD_NAND_ROM_MODE; + // } else if (src > ndsHeader->nandRwStart * 0x20000 /*dsi: 80000h?*/ && nandRomMode != CARD_CMD_NAND_RW_MODE) { + // cardParamCommand(CARD_CMD_NAND_RW_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); + // nandRomMode = CARD_CMD_NAND_RW_MODE; + // } + // } cardParamCommand (CARD_CMD_DATA_READ, src, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), From 0bc622b3d5b2df9dcbf209321482c358defe628a Mon Sep 17 00:00:00 2001 From: Pk11 Date: Tue, 5 Oct 2021 00:30:37 -0500 Subject: [PATCH 04/10] Fix NAND ROM dumping yes. it was literally the 'random' number. --- arm9/source/read_card.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index c6dc0a3..0689d8a 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -72,8 +72,7 @@ static u32 secureArea[CARD_SECURE_AREA_SIZE/sizeof(u32)] = {0}; static const u8 cardSeedBytes[] = {0xE8, 0x4D, 0x5A, 0xB1, 0x17, 0x8F, 0x99, 0xD5}; static u32 getRandomNumber(void) { - return 4; // chosen by fair dice roll. - // guaranteed to be random. + return rand(); } static void decryptSecureArea (u32 gameCode, u32* secureArea, int iCardDevice) From 294c4bee1ca936d796211ffa7f085f81bc815c5c Mon Sep 17 00:00:00 2001 From: Pk11 Date: Wed, 6 Oct 2021 00:51:38 -0500 Subject: [PATCH 05/10] Fix NAND save writing and restoring --- arm9/source/dumpOperations.cpp | 238 ++++++++++++++++++++------------- arm9/source/read_card.c | 105 ++++++++++++--- arm9/source/read_card.h | 7 +- 3 files changed, 240 insertions(+), 110 deletions(-) diff --git a/arm9/source/dumpOperations.cpp b/arm9/source/dumpOperations.cpp index 0bf4057..9eb0dd9 100644 --- a/arm9/source/dumpOperations.cpp +++ b/arm9/source/dumpOperations.cpp @@ -30,6 +30,26 @@ void dumpFailMsg(bool save) { } } +void saveWriteFailMsg(void) { + const std::string_view sizeError = "The size of this save doesn't match the size of the inserted game card.\n\nWrite cancelled!"; + + font->clear(false); + font->print(0, 0, false, sizeError, Alignment::left, Palette::red); + font->print(0, font->calcHeight(sizeError) + 1, false, "( OK)"); + font->update(false); + + u16 pressed; + do { + // Print time + font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen); + font->update(true); + + scanKeys(); + pressed = keysDownRepeat(); + swiWaitForVBlank(); + } while (!(pressed & KEY_A)); +} + //--------------------------------------------------------------------------------- // https://github.com/devkitPro/libnds/blob/master/source/common/cardEeprom.c#L74 // with Pokémon Mystery Dungeon - Explorers of Sky (128 KiB EEPROM) fixed @@ -215,7 +235,7 @@ void ndsCardSaveDump(const char* filename) { font->update(false); for (u32 i = 0; i < 0x8000; i += 0x200) { - cardRead(ndsCardHeader.nandRwStart + src + i, copyBuf + i); + cardRead(cardNandRwStart + src + i, copyBuf + i, true); } if (fwrite(copyBuf, 1, (currentSize >= 0x8000 ? 0x8000 : currentSize), destinationFile) < 1) { dumpFailMsg(true); @@ -273,104 +293,144 @@ void ndsCardSaveRestore(const char *filename) { } while (!(pressed & (KEY_A | KEY_B))); if(pressed & KEY_A) { - auxspi_extra card_type = auxspi_has_extra(); - bool auxspi = card_type == AUXSPI_INFRARED; - FILE *in = fopen(filename, "rb"); - if(in) { - unsigned char *buffer; - int size; - int type; - int length; - unsigned int num_blocks = 0, shift = 0, LEN = 0; - if(auxspi) { - size = auxspi_save_size_log_2(card_type); - type = auxspi_save_type(card_type); - switch(type) { - case 1: - shift = 4; // 16 bytes - break; - case 2: - shift = 5; // 32 bytes - break; - case 3: - shift = 8; // 256 bytes - break; - default: - return; + int type = cardEepromGetTypeFixed(); + + if(type == -1) { // NAND + if (cardInit(&ndsCardHeader) != 0) { + font->clear(false); + font->print(0, 0, false, "Unable to restore the save."); + font->update(false); + for (int i = 0; i < 60 * 2; i++) { + swiWaitForVBlank(); } - LEN = 1 << shift; - num_blocks = 1 << (size - shift); - } else { - type = cardEepromGetTypeFixed(); - size = cardEepromGetSizeFixed(); + return; } + + u32 saveSize = cardNandGetSaveSize(); + + if(saveSize == 0) { + dumpFailMsg(true); + return; + } + + FILE* in = fopen(filename, "rb"); + fseek(in, 0, SEEK_END); - length = ftell(in); + size_t length = ftell(in); fseek(in, 0, SEEK_SET); - if(length != (auxspi ? (int)(LEN * num_blocks) : size)) { + if(length != saveSize) { fclose(in); - const std::string_view sizeError = "The size of this save doesn't match the size of the inserted game card.\n\nWrite cancelled!"; + saveWriteFailMsg(); + return; + } - font->clear(false); - font->print(0, 0, false, sizeError, Alignment::left, Palette::red); - font->print(0, font->calcHeight(sizeError) + 1, false, "( OK)"); - font->update(false); + u32 currentSize = saveSize; + if (in) { - do { + font->print(0, 4, false, "Progress:"); + font->print(0, 5, false, "["); + font->print(-1, 5, false, "]"); + for (u32 src = 0; src < saveSize; src += 0x8000) { // Print time font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen); font->update(true); - scanKeys(); - pressed = keysDownRepeat(); - swiWaitForVBlank(); - } while (!(pressed & KEY_A)); - return; - } - - font->clear(false); - font->print(0, 0, false, "Restoring save..."); - font->print(0, 1, false, "Do not remove the NDS card."); - font->print(0, 4, false, "Progress:"); - font->update(false); - - if(type == 3) { - if(auxspi) - auxspi_erase(card_type); - else - cardEepromChipEraseFixed(); - } - if(auxspi){ - buffer = new unsigned char[LEN]; - font->print(0, 5, false, "["); - font->print(-1, 5, false, "]"); - for(unsigned int i = 0; i < num_blocks; i++) { - font->print((i * (SCREEN_COLS - 2) / num_blocks) + 1, 5, false, "="); - font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", i * LEN, length); + font->print((src / (saveSize / (SCREEN_COLS - 2))) + 1, 5, false, "="); + font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", src, saveSize); font->update(false); - fread(buffer, 1, LEN, in); - auxspi_write_data(i << shift, buffer, LEN, type, card_type); - } - } else { - int blocks = size / 32; - int written = 0; - buffer = new unsigned char[blocks]; - font->print(0, 5, false, "["); - font->print(-1, 5, false, "]"); - for(unsigned int i = 0; i < 32; i++) { - font->print((i * (SCREEN_COLS - 2) / 32) + 1, 5, false, "="); - font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", written, size); - font->update(false); - - fread(buffer, 1, blocks, in); - cardWriteEeprom(written, buffer, blocks, type); - written += blocks; + fread(copyBuf, 1, 0x8000, in); + for (u32 i = 0; i < 0x8000; i += 0x800) { + cardWriteNand(copyBuf + i, cardNandRwStart + src + i); + } + currentSize -= 0x8000; } + fclose(in); + } + } else { // SPI + auxspi_extra card_type = auxspi_has_extra(); + bool auxspi = card_type == AUXSPI_INFRARED; + FILE *in = fopen(filename, "rb"); + if(in) { + unsigned char *buffer; + int size; + int length; + unsigned int num_blocks = 0, shift = 0, LEN = 0; + if(auxspi) { + size = auxspi_save_size_log_2(card_type); + type = auxspi_save_type(card_type); + switch(type) { + case 1: + shift = 4; // 16 bytes + break; + case 2: + shift = 5; // 32 bytes + break; + case 3: + shift = 8; // 256 bytes + break; + default: + return; + } + LEN = 1 << shift; + num_blocks = 1 << (size - shift); + } else { + size = cardEepromGetSizeFixed(); + } + fseek(in, 0, SEEK_END); + length = ftell(in); + fseek(in, 0, SEEK_SET); + if(length != (auxspi ? (int)(LEN * num_blocks) : size)) { + fclose(in); + + saveWriteFailMsg(); + return; + } + + font->clear(false); + font->print(0, 0, false, "Restoring save..."); + font->print(0, 1, false, "Do not remove the NDS card."); + font->print(0, 4, false, "Progress:"); + font->update(false); + + if(type == 3) { + if(auxspi) + auxspi_erase(card_type); + else + cardEepromChipEraseFixed(); + } + if(auxspi){ + buffer = new unsigned char[LEN]; + font->print(0, 5, false, "["); + font->print(-1, 5, false, "]"); + for(unsigned int i = 0; i < num_blocks; i++) { + font->print((i * (SCREEN_COLS - 2) / num_blocks) + 1, 5, false, "="); + font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", i * LEN, length); + font->update(false); + + fread(buffer, 1, LEN, in); + auxspi_write_data(i << shift, buffer, LEN, type, card_type); + } + } else { + int blocks = size / 32; + int written = 0; + buffer = new unsigned char[blocks]; + font->print(0, 5, false, "["); + font->print(-1, 5, false, "]"); + for(unsigned int i = 0; i < 32; i++) { + font->print((i * (SCREEN_COLS - 2) / 32) + 1, 5, false, "="); + font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", written, size); + font->update(false); + + fread(buffer, 1, blocks, in); + cardWriteEeprom(written, buffer, blocks, type); + written += blocks; + } + } + delete[] buffer; + fclose(in); } - delete[] buffer; - fclose(in); } } } @@ -604,7 +664,7 @@ void ndsCardDump(void) { iprintf ("\x1b[8;0H"); iprintf ("Read:\n"); iprintf ("%i/%i Bytes ", (int)src, (int)romSize); - cardRead (src, (void*)0x09000000+(src % 0x800000)); + cardRead (src, (void*)0x09000000+(src % 0x800000), false); } iprintf("\x1b[15;0H"); iprintf("Please switch to the\nflashcard, then press A.\n"); @@ -664,17 +724,12 @@ void ndsCardDump(void) { font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen); font->update(true); - // TODO: Remove, just for testing - scanKeys(); - if(keysDown() & KEY_B) - break; - font->print((src / (romSize / (SCREEN_COLS - 2))) + 1, 5, false, "="); font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", src, romSize); font->update(false); for (u32 i = 0; i < 0x8000; i += 0x200) { - cardRead (src+i, copyBuf+i); + cardRead (src+i, copyBuf+i, false); } if (fwrite(copyBuf, 1, (currentSize>=0x8000 ? 0x8000 : currentSize), destinationFile) < 1) { dumpFailMsg(false); @@ -686,8 +741,7 @@ void ndsCardDump(void) { } else { dumpFailMsg(false); } - // TODO: Uncomment, just commented for testing - // ndsCardSaveDump(destSavPath); + ndsCardSaveDump(destSavPath); //} } } diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index 0689d8a..818c8a4 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -45,7 +45,7 @@ enum { // NAND Card commands // https://problemkaputt.de/gbatek-ds-cartridge-nand.htm #define CARD_CMD_NAND_WRITE_BUFFER 0x81 -#define CARD_CMD_NAND_FLUSH_BUFFER 0x82 +#define CARD_CMD_NAND_COMMIT_BUFFER 0x82 #define CARD_CMD_NAND_DISCARD_BUFFER 0x84 #define CARD_CMD_NAND_WRITE_ENABLE 0x85 #define CARD_CMD_NAND_ROM_MODE 0x8B @@ -63,18 +63,48 @@ typedef union static bool twlBlowfish = false; static bool normalChip = false; // As defined by GBAtek, normal chip secure area is accessed in blocks of 0x200, other chip in blocks of 0x1000 -static bool nandChip = false; -static int nandRomMode = -1; static u32 portFlags = 0; static u32 headerData[0x1000/sizeof(u32)] = {0}; static u32 secureArea[CARD_SECURE_AREA_SIZE/sizeof(u32)] = {0}; +static bool nandChip = false; +static int nandSection = -1; // -1 = ROM, above that is the current 128 KiB section in RW +u32 cardNandRomEnd = 0; +u32 cardNandRwStart = 0; + static const u8 cardSeedBytes[] = {0xE8, 0x4D, 0x5A, 0xB1, 0x17, 0x8F, 0x99, 0xD5}; static u32 getRandomNumber(void) { return rand(); } +//--------------------------------------------------------------------------------- +// https://github.com/devkitPro/libnds/blob/105d4943dbac8f2bd99a47b22cd3ed48f96af083/source/common/card.c#L47-L62 +// but modified to write if CARD_WR is set. +static void cardPolledTransferWrite(u32 flags, u32 *buffer, u32 length, const u8 *command) { +//--------------------------------------------------------------------------------- + cardWriteCommand(command); + REG_ROMCTRL = flags | CARD_BUSY; + u32 * target = buffer + length; + do { + // Read/write data if available + if (REG_ROMCTRL & CARD_DATA_READY) { + if (flags & CARD_WR) { // Write + if (NULL != buffer && buffer < target) + REG_CARD_DATA_RD = *buffer++; + else + REG_CARD_DATA_RD = 0; + } else { // Read + u32 data = REG_CARD_DATA_RD; + if (NULL != buffer && buffer < target) + *buffer++ = REG_CARD_DATA_RD; + else + (void)data; + } + } + } while (REG_ROMCTRL & CARD_BUSY); +} + static void decryptSecureArea (u32 gameCode, u32* secureArea, int iCardDevice) { init_keycode (gameCode, 2, 8, iCardDevice); @@ -291,7 +321,7 @@ int cardInit (sNDSHeaderExt* ndsHeader) u32 portFlagsKey1, portFlagsSecRead; normalChip = false; // As defined by GBAtek, normal chip secure area and header are accessed in blocks of 0x200, other chip in blocks of 0x1000 nandChip = false; - nandRomMode = -1; + nandSection = -1; int secureBlockNumber; int i; u8 cmdData[8] __attribute__ ((aligned)); @@ -313,9 +343,6 @@ int cardInit (sNDSHeaderExt* ndsHeader) NULL, 0); } - // TODO: This was only done in DS mode, but fixes NAND in DSi mode - // see if only part of this is needed or if it causes problems to do - // all of it in DSi mode. REG_ROMCTRL=0; REG_AUXSPICNT=0; //ioDelay2(167550); @@ -467,10 +494,23 @@ int cardInit (sNDSHeaderExt* ndsHeader) //return normalChip ? ERR_SEC_NORM : ERR_SEC_OTHR; } + // Set NAND card section location variables + if (nandChip) { + if(ndsHeader->nandRomEnd != 0) { + // TWL cards (Face Training) multiply by 0x80000 instead of 0x20000 + cardNandRomEnd = ndsHeader->nandRomEnd * (ndsHeader->unitCode == 0 ? 0x20000 : 0x80000); + cardNandRwStart = ndsHeader->nandRwStart * (ndsHeader->unitCode == 0 ? 0x20000 : 0x80000); + } else { + // Jam with the Band (J) (大合奏!バンドブラザーズ) doesn't have the RW section in the header + cardNandRomEnd = 0x7200000; + cardNandRwStart = 0x7200000; + } + } + return ERR_NONE; } -void cardRead (u32 src, void* dest) +void cardRead (u32 src, void* dest, bool nandSave) { sNDSHeaderExt* ndsHeader = (sNDSHeaderExt*)headerData; @@ -491,15 +531,17 @@ void cardRead (u32 src, void* dest) return; } - // if (nandChip) { - // if (src < ndsHeader->nandRomEnd * 0x20000 /*dsi: 80000h?*/ && nandRomMode != CARD_CMD_NAND_ROM_MODE) { - // cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); - // nandRomMode = CARD_CMD_NAND_ROM_MODE; - // } else if (src > ndsHeader->nandRwStart * 0x20000 /*dsi: 80000h?*/ && nandRomMode != CARD_CMD_NAND_RW_MODE) { - // cardParamCommand(CARD_CMD_NAND_RW_MODE, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), NULL, 0); - // nandRomMode = CARD_CMD_NAND_RW_MODE; - // } - // } + if (nandChip) { + if ((src < cardNandRomEnd || !nandSave) && nandSection != -1) { + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + nandSection = -1; + } else if (src >= cardNandRwStart && nandSection != (src - cardNandRwStart) / (128 << 10)) { + if(nandSection != -1) // Need to switch back to ROM mode before switching to another RW section + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_RW_MODE, src, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + nandSection = (src - cardNandRwStart) / (128 << 10); + } + } cardParamCommand (CARD_CMD_DATA_READ, src, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), @@ -510,3 +552,32 @@ void cardRead (u32 src, void* dest) } } +// src must be a 0x800 byte array +void cardWriteNand (void* src, u32 dest) +{ + if (dest < cardNandRwStart || !nandChip) + return; + + if (nandSection != (dest - cardNandRwStart) / (128 << 10)) { + if(nandSection != -1) // Need to switch back to ROM mode before switching to another RW section + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_RW_MODE, dest, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + nandSection = (dest - cardNandRwStart) / (128 << 10); + } + + cardParamCommand(CARD_CMD_NAND_WRITE_ENABLE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + + const u8 cmdData[8] = {0, 0, 0, dest, dest >> 8, dest >> 16, dest >> 24, CARD_CMD_NAND_WRITE_BUFFER}; + for (int i = 0; i < 4; i++) { + cardPolledTransferWrite(portFlags | CARD_ACTIVATE | CARD_WR | CARD_nRESET | CARD_BLK_SIZE(1), src + (i * 0x200), 0x200 / sizeof(u32), cmdData); + } + + cardParamCommand(CARD_CMD_NAND_COMMIT_BUFFER, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + + u32 status; + do { + cardParamCommand(CARD_CMD_NAND_READ_STATUS, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7), &status, 1); + } while((status & BIT(5)) == 0); + + cardParamCommand(CARD_CMD_NAND_DISCARD_BUFFER, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); +} diff --git a/arm9/source/read_card.h b/arm9/source/read_card.h index e54d37a..56f94a8 100644 --- a/arm9/source/read_card.h +++ b/arm9/source/read_card.h @@ -36,9 +36,14 @@ extern "C" { #endif +extern u32 cardNandRomEnd; +extern u32 cardNandRwStart; + int cardInit (sNDSHeaderExt* ndsHeader); -void cardRead (u32 src, void* dest); +void cardRead (u32 src, void* dest, bool nandSave); + +void cardWriteNand (void* src, u32 dest); #ifdef __cplusplus } From bc4b0baf1f9f38e2486f5f453c0b07aa53584226 Mon Sep 17 00:00:00 2001 From: Pk11 Date: Wed, 6 Oct 2021 01:00:24 -0500 Subject: [PATCH 06/10] Fix dumping the save in the ROM Technically this is actually more accurate, however it makes the dump not match a 'clean' dump (and there couldn't be a 'clean' dump like this as the save will always vary) --- arm9/source/read_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index 818c8a4..f26c78e 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -535,7 +535,7 @@ void cardRead (u32 src, void* dest, bool nandSave) if ((src < cardNandRomEnd || !nandSave) && nandSection != -1) { cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); nandSection = -1; - } else if (src >= cardNandRwStart && nandSection != (src - cardNandRwStart) / (128 << 10)) { + } else if (src >= cardNandRwStart && nandSection != (src - cardNandRwStart) / (128 << 10) && nandSave) { if(nandSection != -1) // Need to switch back to ROM mode before switching to another RW section cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); cardParamCommand(CARD_CMD_NAND_RW_MODE, src, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); From 8e48ab82f6412c32b251ab4b841ba5328b83eefe Mon Sep 17 00:00:00 2001 From: Pk11 Date: Wed, 6 Oct 2021 14:10:16 -0500 Subject: [PATCH 07/10] Don't switch to TWL Blowfish for NAND saves This doesn't seem to fully fix Face Training, but it might help? Force push because I decided to undo disabling face training saves so it can still be tested --- arm9/source/read_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index f26c78e..551e83d 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -547,7 +547,7 @@ void cardRead (u32 src, void* dest, bool nandSave) portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), dest, 0x200/sizeof(u32)); - if (src > ndsHeader->romSize) { + if (src > ndsHeader->romSize && !(nandSave && src >= cardNandRwStart)) { switchToTwlBlowfish(ndsHeader); } } From 960c1ea7ad49657b3ffd12517b3c16ac946403ed Mon Sep 17 00:00:00 2001 From: Pk11 Date: Wed, 6 Oct 2021 14:11:48 -0500 Subject: [PATCH 08/10] Only dump 64 MiB for Face Training GBATEK says 82 MB RW section but now how much is save, nocash said 66 MB is save(?) on nesdev, but then melonDS makes a 64 MB save, since melonDS seems to work I'm just going to lower this to 64 MB incase going further can cause trouble. --- arm9/source/dumpOperations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arm9/source/dumpOperations.cpp b/arm9/source/dumpOperations.cpp index 9eb0dd9..550ed82 100644 --- a/arm9/source/dumpOperations.cpp +++ b/arm9/source/dumpOperations.cpp @@ -194,7 +194,7 @@ u32 cardNandGetSaveSize(void) { case 0x00524F55: // 'UOR' return 16 << 20; // 16MByte - WarioWare D.I.Y. case 0x004B5355: // 'USK' - return 82 << 20; // 82MByte - Face Training + return 64 << 20; // 64MByte - Face Training } return 0; From 132f787623cfc621129c53d585559863c4f4f041 Mon Sep 17 00:00:00 2001 From: Pk11 Date: Sun, 10 Oct 2021 17:44:14 -0500 Subject: [PATCH 09/10] Remove `CARD_CLK_SLOW` from NAND commands Seems fine without it, maybe better? --- arm9/source/read_card.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arm9/source/read_card.c b/arm9/source/read_card.c index 551e83d..c247511 100644 --- a/arm9/source/read_card.c +++ b/arm9/source/read_card.c @@ -533,12 +533,12 @@ void cardRead (u32 src, void* dest, bool nandSave) if (nandChip) { if ((src < cardNandRomEnd || !nandSave) && nandSection != -1) { - cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); nandSection = -1; } else if (src >= cardNandRwStart && nandSection != (src - cardNandRwStart) / (128 << 10) && nandSave) { if(nandSection != -1) // Need to switch back to ROM mode before switching to another RW section - cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); - cardParamCommand(CARD_CMD_NAND_RW_MODE, src, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); + cardParamCommand(CARD_CMD_NAND_RW_MODE, src, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); nandSection = (src - cardNandRwStart) / (128 << 10); } } @@ -560,24 +560,24 @@ void cardWriteNand (void* src, u32 dest) if (nandSection != (dest - cardNandRwStart) / (128 << 10)) { if(nandSection != -1) // Need to switch back to ROM mode before switching to another RW section - cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); - cardParamCommand(CARD_CMD_NAND_RW_MODE, dest, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); + cardParamCommand(CARD_CMD_NAND_RW_MODE, dest, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); nandSection = (dest - cardNandRwStart) / (128 << 10); } - cardParamCommand(CARD_CMD_NAND_WRITE_ENABLE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_WRITE_ENABLE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); const u8 cmdData[8] = {0, 0, 0, dest, dest >> 8, dest >> 16, dest >> 24, CARD_CMD_NAND_WRITE_BUFFER}; for (int i = 0; i < 4; i++) { cardPolledTransferWrite(portFlags | CARD_ACTIVATE | CARD_WR | CARD_nRESET | CARD_BLK_SIZE(1), src + (i * 0x200), 0x200 / sizeof(u32), cmdData); } - cardParamCommand(CARD_CMD_NAND_COMMIT_BUFFER, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_COMMIT_BUFFER, 0, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); u32 status; do { - cardParamCommand(CARD_CMD_NAND_READ_STATUS, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(7), &status, 1); + cardParamCommand(CARD_CMD_NAND_READ_STATUS, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(7), &status, 1); } while((status & BIT(5)) == 0); - cardParamCommand(CARD_CMD_NAND_DISCARD_BUFFER, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW, NULL, 0); + cardParamCommand(CARD_CMD_NAND_DISCARD_BUFFER, 0, portFlags | CARD_ACTIVATE | CARD_nRESET, NULL, 0); } From d608197df85a242d159d0bf10fb033d56d8b5694 Mon Sep 17 00:00:00 2001 From: Pk11 Date: Sun, 10 Oct 2021 17:48:32 -0500 Subject: [PATCH 10/10] Fix NAND restore error message & variable name --- arm9/source/dumpOperations.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arm9/source/dumpOperations.cpp b/arm9/source/dumpOperations.cpp index 550ed82..2d4355a 100644 --- a/arm9/source/dumpOperations.cpp +++ b/arm9/source/dumpOperations.cpp @@ -309,7 +309,11 @@ void ndsCardSaveRestore(const char *filename) { u32 saveSize = cardNandGetSaveSize(); if(saveSize == 0) { - dumpFailMsg(true); + font->print(0, 0, false, "Unable to restore the save."); + font->update(false); + for (int i = 0; i < 60 * 2; i++) { + swiWaitForVBlank(); + } return; } @@ -327,22 +331,21 @@ void ndsCardSaveRestore(const char *filename) { u32 currentSize = saveSize; if (in) { - font->print(0, 4, false, "Progress:"); font->print(0, 5, false, "["); font->print(-1, 5, false, "]"); - for (u32 src = 0; src < saveSize; src += 0x8000) { + for (u32 dest = 0; dest < saveSize; dest += 0x8000) { // Print time font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen); font->update(true); - font->print((src / (saveSize / (SCREEN_COLS - 2))) + 1, 5, false, "="); - font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", src, saveSize); + font->print((dest / (saveSize / (SCREEN_COLS - 2))) + 1, 5, false, "="); + font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", dest, saveSize); font->update(false); fread(copyBuf, 1, 0x8000, in); for (u32 i = 0; i < 0x8000; i += 0x800) { - cardWriteNand(copyBuf + i, cardNandRwStart + src + i); + cardWriteNand(copyBuf + i, cardNandRwStart + dest + i); } currentSize -= 0x8000; }