diff --git a/ipl/main.c b/ipl/main.c index abace60..dae10bd 100755 --- a/ipl/main.c +++ b/ipl/main.c @@ -15,6 +15,8 @@ */ #include +#include +#include #include "clock.h" #include "uart.h" @@ -380,17 +382,67 @@ void *sd_file_read(char *path) int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part) { + static u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF; + static u32 MULTIPART_SPLIT_SIZE = (1u << 31); + + u32 totalSectors = part->lba_end - part->lba_start + 1; + char* outFilename = sd_path; + u32 sdPathLen = strlen(sd_path); + u32 numSplitParts = 0; + if (totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE)) + { + const u32 MULTIPART_SPLIT_SECTORS = MULTIPART_SPLIT_SIZE/NX_EMMC_BLOCKSIZE; + numSplitParts = (totalSectors+MULTIPART_SPLIT_SECTORS-1)/MULTIPART_SPLIT_SECTORS; + + outFilename = alloca(sdPathLen+4); + memcpy(outFilename, sd_path, sdPathLen); + outFilename[sdPathLen++] = '.'; + + outFilename[sdPathLen] = '0'; + if (numSplitParts >= 10) + { + outFilename[sdPathLen+1] = '0'; + outFilename[sdPathLen+2] = 0; + } + else + outFilename[sdPathLen+1] = 0; + } + FIL fp; - if (f_open(&fp, sd_path, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) + if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) return 0; - u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * 512); + static u32 NUM_SECTORS_PER_ITER = 512; + u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * NUM_SECTORS_PER_ITER); - u32 total = part->lba_end - part->lba_start + 1; u32 lba_curr = part->lba_start; - while(total > 0) + u32 bytesWritten = 0; + u32 currPartIdx = 0; + while(totalSectors > 0) { - u32 num = MIN(total, 512); + if (numSplitParts != 0 && bytesWritten >= MULTIPART_SPLIT_SIZE) + { + f_close(&fp); + memset(&fp, 0, sizeof(fp)); + currPartIdx++; + + if (numSplitParts >= 10 && currPartIdx < 10) + { + outFilename[sdPathLen] = '0'; + itoa(currPartIdx, &outFilename[sdPathLen+1], 10); + } + else + itoa(currPartIdx, &outFilename[sdPathLen], 10); + + if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) + { + free(buf); + return 0; + } + bytesWritten = 0; + } + + u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER); if(!sdmmc_storage_read(storage, lba_curr, num, buf)) { @@ -403,7 +455,8 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part) tui_pbar(&gfx_con, 0, gfx_con.y, pct); lba_curr += num; - total -= num; + totalSectors -= num; + bytesWritten += num * NX_EMMC_BLOCKSIZE; } tui_pbar(&gfx_con, 0, gfx_con.y, 100); @@ -413,7 +466,14 @@ out:; return 1; } -void dump_emmc() +typedef enum +{ + DUMP_BOOT = 1, + DUMP_SYSTEM = 2, + DUMP_USER = 4 +} dumpType_t; + +static void dump_emmc_selected(dumpType_t dumpType) { gfx_clear(&gfx_ctxt, 0xFF000000); gfx_con_setpos(&gfx_con, 0, 0); @@ -431,35 +491,65 @@ void dump_emmc() gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF); goto out; } - sdmmc_storage_set_mmc_partition(&storage, 0); - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); - int i = 0; - LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) - { - gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i++, - part->name, part->lba_start, part->lba_end); + if (dumpType & DUMP_BOOT) + { + static u32 BOOT_PART_SIZE = 0x400000; - //XXX: skip these for now. - if (//!strcmp(part->name, "SYSTEM") || - !strcmp(part->name, "USER")) + emmc_part_t bootPart; + memset(&bootPart, 0, sizeof(bootPart)); + bootPart.lba_start = 0; + bootPart.lba_end = (BOOT_PART_SIZE/NX_EMMC_BLOCKSIZE)-1; + for (u32 i=0; i<2; i++) { - gfx_puts(&gfx_con, "Skipped.\n"); - continue; - } + memcpy(bootPart.name, "BOOT", 4); + bootPart.name[4] = (u8)('0' + i); + bootPart.name[5] = 0; - dump_emmc_part(part->name, &storage, part); - gfx_putc(&gfx_con, '\n'); + gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i, + bootPart.name, bootPart.lba_start, bootPart.lba_end); + + sdmmc_storage_set_mmc_partition(&storage, i+1); + dump_emmc_part(bootPart.name, &storage, &bootPart); + gfx_putc(&gfx_con, '\n'); + } + + } + + if ((dumpType & DUMP_SYSTEM) || (dumpType & DUMP_USER)) + { + sdmmc_storage_set_mmc_partition(&storage, 0); + + LIST_INIT(gpt); + nx_emmc_gpt_parse(&gpt, &storage); + int i = 0; + LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link) + { + if ((dumpType & DUMP_USER) == 0 && !strcmp(part->name, "USER")) + continue; + if ((dumpType & DUMP_SYSTEM) == 0 && strcmp(part->name, "USER")) + continue; + + gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i++, + part->name, part->lba_start, part->lba_end); + + dump_emmc_part(part->name, &storage, part); + gfx_putc(&gfx_con, '\n'); + } } sdmmc_storage_end(&storage); + gfx_puts(&gfx_con, "Done.\n"); out:; sleep(100000); btn_wait(); } +void dump_emmc_system() { dump_emmc_selected(DUMP_SYSTEM); } +void dump_emmc_user() { dump_emmc_selected(DUMP_USER); } +void dump_emmc_boot() { dump_emmc_selected(DUMP_BOOT); } + void launch_firmware() { ini_sec_t *cfg_sec = NULL; @@ -571,7 +661,9 @@ menu_t menu_cinfo = { ment_t ment_tools[] = { MDEF_BACK(), - MDEF_HANDLER("Dump eMMC", dump_emmc), + MDEF_HANDLER("Dump eMMC", dump_emmc_system), + MDEF_HANDLER("Dump eMMC USER", dump_emmc_user), + MDEF_HANDLER("Dump eMMC BOOT", dump_emmc_boot), MDEF_END() }; menu_t menu_tools = {