diff --git a/source/gamecart/protocol.c b/source/gamecart/protocol.c index f750bc8..46ed72f 100644 --- a/source/gamecart/protocol.c +++ b/source/gamecart/protocol.c @@ -184,9 +184,8 @@ void Cart_Secure_Init(u32 *buf, u32 *out) const u32 C5_cmd[4] = { 0xC5000000, 0x00000000, rand1, rand2 }; CTR_SendCommand(C5_cmd, 0, 1, 0x100822C, NULL); - CTR_SendCommand(A2_cmd, 4, 1, 0x100822C, &test); - CTR_SendCommand(A2_cmd, 4, 1, 0x100822C, &test); - CTR_SendCommand(A2_cmd, 4, 1, 0x100822C, &test); - CTR_SendCommand(A2_cmd, 4, 1, 0x100822C, &test); - CTR_SendCommand(A2_cmd, 4, 1, 0x100822C, &test); + for (int i = 0; i < 5; ++i) { + CTR_SendCommand(A2_cmd, 4, 1, 0x100822C, &test); + ioDelay(0xF0000); + } } diff --git a/source/main.c b/source/main.c index 109ef15..8869cc3 100644 --- a/source/main.c +++ b/source/main.c @@ -22,29 +22,24 @@ static void ClearTop(void) { } static void wait_key(void) { - Debug(""); - Debug("Press key to continue"); + Debug("Press key to continue..."); InputWait(); } int main() { +restart_program: // Setup boring stuff - clear the screen, initialize SD output, etc... ClearTop(); - Debug(""); - Debug("Hello world from ARM9!"); - Debug("ROM dump tool v0.2", 1, 1, 0xFF); + Debug("ROM dump tool v0.2"); + Debug("Insert your game cart and SD card now."); wait_key(); - char filename_buf[21]; - unsigned int bytes_written = 0; - // Arbitrary target buffer // TODO: This should be done in a nicer way ;) u8* target = (u8*)0x22000000; u8* header = (u8*)0x23000000; - Debug("ROM dump tool v0.2", 1, 1, 0xFF); memset(target, 0x00, 0x100000); // Clear our 1 MB buffer // clear_screens(0x00); @@ -56,18 +51,11 @@ int main() { wait_key(); return 0; } - Debug("Successfully f_mounted"); - Debug("cleared stuff! Initializing game card...", 1, 1, 0xFF); // ROM DUMPING CODE STARTS HERE Cart_Init(); - - Debug("Done! Cart id is %08x, press A...", (u32)Cart_GetID()); - - InputWait(); - Debug("Done waiting :)...", 1, 1, 0xFF); - + Debug("Cart id is %08x, press A...", Cart_GetID()); CTR_CmdReadHeader(header); Debug("Done reading header: %08X :)...", *(u32*)&header[0x100]); @@ -75,7 +63,7 @@ int main() { u32 sec_keys[4]; Cart_Secure_Init((u32*)header,sec_keys); - u32 mediaUnit = 0x200; + u32 mediaUnit = 0x200; // TODO: Read from cart u32 ramCache = 0xC000; //24MB/s - 0x1000000 u32 dumpSize = 0x100000; //1MB @@ -84,64 +72,74 @@ int main() { // Read out the header 0x0000-0x1000 CTR_CmdReadData(0, mediaUnit, 8, target); - // Create output file - TODO: Put actual information in the file name (game id/name/..?), to have a standardized naming scheme - snprintf(filename_buf, sizeof(filename_buf), "%s", "/dump.3ds"); + u32 NCSD_magic = *(u32*)(&target[0x100]); + u32 cartSize = *(u32*)(&target[0x104]); + Debug("Cart size: %llu MB", (u64)cartSize * (u64)mediaUnit / 1024ull / 1024ull); + if (NCSD_magic != 0x4453434E) { + Debug("NCSD magic not found in header!!!"); + Debug("Press A to continue anyway."); + if (!(InputWait() & 1)) + goto cleanup_mount; + } - wait_key(); - Debug("File name: \"%s\"", filename_buf); + // Create output file + char filename_buf[32]; + snprintf(filename_buf, sizeof(filename_buf), "/%.16s.3ds", &header[0x150]); + Debug("Outputting to file: \"%s\"", filename_buf); unsigned flags = FA_READ | FA_WRITE | FA_CREATE_ALWAYS; if (f_open(&file, filename_buf, flags) != FR_OK) { Debug("Failed to create file..."); wait_key(); - return 0; + goto cleanup_mount; } f_lseek(&file, 0); f_sync(&file); - Debug("Successfully created file"); - wait_key(); // Write header to file unsigned int written = 0; f_write(&file, target, 0x4000, &written); f_sync(&file); - Debug("Wrote header"); - wait_key(); - u32 cartSize = *(u32*)(&target[0x104]); - Debug("Cart size: %llu MB", (u64)cartSize * 0x200ull / 1024ull / 1024ull); - wait_key(); + Debug("Ready to dump. (SELECT to skip)"); + if (InputWait() & 4) // Select + goto skip_dumping; // Dump remaining data - for(u32 adr=0x20; adr ramCache) dumped = ramCache; + if (dumped > ramCache) dumped = ramCache; - for(u32 adr2=0; (adr2 < dumped); adr2+=blocks) { - u32 currentSector = (adr+adr2); - u32 percent = ((currentSector*100)/cartSize); + for (u32 adr2 = 0; adr2 < dumped; adr2 += blocks) { + u32 currentSector = adr + adr2; + u32 percent = (currentSector * 100) / cartSize; if ((adr2 % (blocks*3)) == blocks*2) Debug("Dumping %08X / %08X - %03d%%",currentSector,cartSize,percent); CTR_CmdReadData(currentSector, mediaUnit, blocks, (void*)(target + (adr2 * mediaUnit))); } - f_write(&file, target, dumped * mediaUnit, &bytes_written); - f_sync(&file); - } + unsigned int bytes_written = 0; + f_write(&file, target, dumped * mediaUnit, &bytes_written); + Debug("Wrote 0x%x bytes, e.g. %08x", bytes_written, *(u32*)target); + } + Debug("Done!"); + +skip_dumping: // Write header - TODO: Not sure why this is done at the very end.. f_lseek(&file, 0x1000); f_write(&file, header, 0x200, &written); f_sync(&file); - Debug("Wrote 0x%X header bytes", written); - wait_key(); // Done, clean up... f_close(&file); +cleanup_mount: f_mount(NULL, "0:", 0); + Debug("Press B to exit, any other key to restart."); + if (!(InputWait() & 2)) + goto restart_program; + return 0; }