WIP: Fix NAND cart dumping

This commit is contained in:
Pk11 2021-09-27 00:41:06 -05:00
parent 531e58531b
commit d75ab87bfb
3 changed files with 143 additions and 39 deletions

View File

@ -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

View File

@ -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.

View File

@ -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));