Support dumping all possible eMMC partitions (with file splitting when necessary)

This commit is contained in:
Rajko Stojadinovic 2018-05-01 13:17:13 +02:00 committed by nwert
parent 8365426fc3
commit 04de3d184a

View file

@ -15,6 +15,8 @@
*/ */
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <alloca.h>
#include "clock.h" #include "clock.h"
#include "uart.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) 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; 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; 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; 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)) 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); tui_pbar(&gfx_con, 0, gfx_con.y, pct);
lba_curr += num; lba_curr += num;
total -= num; totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE;
} }
tui_pbar(&gfx_con, 0, gfx_con.y, 100); tui_pbar(&gfx_con, 0, gfx_con.y, 100);
@ -413,7 +466,14 @@ out:;
return 1; 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_clear(&gfx_ctxt, 0xFF000000);
gfx_con_setpos(&gfx_con, 0, 0); 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); gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
goto out; goto out;
} }
sdmmc_storage_set_mmc_partition(&storage, 0);
LIST_INIT(gpt); if (dumpType & DUMP_BOOT)
nx_emmc_gpt_parse(&gpt, &storage); {
int i = 0; static u32 BOOT_PART_SIZE = 0x400000;
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);
//XXX: skip these for now. emmc_part_t bootPart;
if (//!strcmp(part->name, "SYSTEM") || memset(&bootPart, 0, sizeof(bootPart));
!strcmp(part->name, "USER")) 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"); memcpy(bootPart.name, "BOOT", 4);
continue; bootPart.name[4] = (u8)('0' + i);
} bootPart.name[5] = 0;
dump_emmc_part(part->name, &storage, part); gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i,
gfx_putc(&gfx_con, '\n'); 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); sdmmc_storage_end(&storage);
gfx_puts(&gfx_con, "Done.\n");
out:; out:;
sleep(100000); sleep(100000);
btn_wait(); 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() void launch_firmware()
{ {
ini_sec_t *cfg_sec = NULL; ini_sec_t *cfg_sec = NULL;
@ -571,7 +661,9 @@ menu_t menu_cinfo = {
ment_t ment_tools[] = { ment_t ment_tools[] = {
MDEF_BACK(), 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() MDEF_END()
}; };
menu_t menu_tools = { menu_t menu_tools = {