Compare commits
7 Commits
2e6cd115c1
...
v1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40938fdb58 | ||
|
|
73e3cc7be6 | ||
|
|
90f893f573 | ||
|
|
3f44441df4 | ||
|
|
44c3ae5ef1 | ||
|
|
5a775ebb72 | ||
|
|
884ad1f6e6 |
@@ -15,7 +15,7 @@
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define FF_FS_MINIMIZE 3
|
||||
#define FF_FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: Basic functions are fully enabled.
|
||||
@@ -200,7 +200,7 @@
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define FF_FS_NOFSINFO 0
|
||||
#define FF_FS_NOFSINFO 1
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
|
||||
183
ipl/main.c
183
ipl/main.c
@@ -388,12 +388,65 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
{
|
||||
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
|
||||
static const u32 MULTIPART_SPLIT_SIZE = (1u << 31);
|
||||
static const u32 SECTORS_TO_MB_COEFF = 0x800;
|
||||
|
||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||
u32 currPartIdx = 0;
|
||||
u32 numSplitParts = 0;
|
||||
u32 maxSplitParts = 0;
|
||||
int isSmallSdCard = 0;
|
||||
int partialDumpInProgress = 0;
|
||||
int res = 0;
|
||||
int ignoreWriteErrors = 0;
|
||||
char* outFilename = sd_path;
|
||||
u32 sdPathLen = strlen(sd_path);
|
||||
u32 numSplitParts = 0;
|
||||
if ((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE))
|
||||
|
||||
FIL partialIdxFp;
|
||||
char partialIdxFilename[12];
|
||||
memcpy(partialIdxFilename, "partial.idx", 11);
|
||||
partialIdxFilename[11] = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "SD Card free space: %dMB, Total dump size %dMB\n",
|
||||
sd_fs.free_clst * sd_fs.csize / SECTORS_TO_MB_COEFF,
|
||||
totalSectors / SECTORS_TO_MB_COEFF);
|
||||
|
||||
// Check if the USER partition or the RAW eMMC fits the sd card free space
|
||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||
{
|
||||
isSmallSdCard = 1;
|
||||
|
||||
gfx_printf(&gfx_con, "%kSD card free space is smaller than dump total size.%k\n", 0xFF00BAFF, 0xFFFFFFFF);
|
||||
|
||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (MULTIPART_SPLIT_SIZE / 512);
|
||||
|
||||
if (!maxSplitParts)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kNot enough free space for partial dumping.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Check if we continueing a previous raw eMMC dump in progress.
|
||||
if (isSmallSdCard)
|
||||
{
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFound partial dump in progress. Continuing...%k\n", 0xFF14FDAE, 0xFFFFFFFF);
|
||||
|
||||
partialDumpInProgress = 1;
|
||||
|
||||
f_read(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
|
||||
// Increase maxSplitParts to accommodate previously dumped parts
|
||||
maxSplitParts += currPartIdx;
|
||||
}
|
||||
else
|
||||
gfx_printf(&gfx_con, "%kContinuing with partial dumping...%k\n", 0xFF00BAFF, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
// Check if filesystem is FAT32 or the free space is smaller and dump in parts
|
||||
if (((sd_fs.fs_type != FS_EXFAT) || isSmallSdCard) && totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE))
|
||||
{
|
||||
static const u32 MULTIPART_SPLIT_SECTORS = MULTIPART_SPLIT_SIZE/NX_EMMC_BLOCKSIZE;
|
||||
numSplitParts = (totalSectors+MULTIPART_SPLIT_SECTORS-1)/MULTIPART_SPLIT_SECTORS;
|
||||
@@ -402,14 +455,28 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
memcpy(outFilename, sd_path, sdPathLen);
|
||||
outFilename[sdPathLen++] = '.';
|
||||
|
||||
outFilename[sdPathLen] = '0';
|
||||
if (numSplitParts >= 10)
|
||||
if (!partialDumpInProgress)
|
||||
{
|
||||
outFilename[sdPathLen+1] = '0';
|
||||
outFilename[sdPathLen+2] = 0;
|
||||
outFilename[sdPathLen] = '0';
|
||||
if (numSplitParts >= 10)
|
||||
{
|
||||
outFilename[sdPathLen+1] = '0';
|
||||
outFilename[sdPathLen+2] = 0;
|
||||
}
|
||||
else
|
||||
outFilename[sdPathLen+1] = 0;
|
||||
}
|
||||
// Continue from where we left, if partial dump in proggress.
|
||||
else
|
||||
outFilename[sdPathLen+1] = 0;
|
||||
{
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
itoa(currPartIdx, &outFilename[sdPathLen+1], 10);
|
||||
}
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
}
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
@@ -421,8 +488,16 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
u32 currPartIdx = 0;
|
||||
u32 prevPct=200;
|
||||
u32 prevPct = 200;
|
||||
int retryCount = 0;
|
||||
|
||||
// Continue from where we left, if partial dump in proggress.
|
||||
if (partialDumpInProgress)
|
||||
{
|
||||
lba_curr += currPartIdx * (MULTIPART_SPLIT_SIZE / NX_EMMC_BLOCKSIZE);
|
||||
totalSectors -= currPartIdx * (MULTIPART_SPLIT_SIZE / NX_EMMC_BLOCKSIZE);
|
||||
}
|
||||
|
||||
while(totalSectors > 0)
|
||||
{
|
||||
if (numSplitParts != 0 && bytesWritten >= MULTIPART_SPLIT_SIZE)
|
||||
@@ -439,6 +514,40 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
|
||||
// More parts to dump that do not currently fit the sd card free space
|
||||
if ((isSmallSdCard && currPartIdx >= maxSplitParts) || (res && !ignoreWriteErrors))
|
||||
{
|
||||
// Create partial dump index file
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
|
||||
{
|
||||
f_write(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k\nError creating partial.idx file.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
if (res && !ignoreWriteErrors)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k\nPress any key and try again.%k\n",
|
||||
0xFF0000FF, 0xFFFFFFFF);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
gfx_puts(&gfx_con, "\n1. Press any key and Power off Switch from the main menu.\n\
|
||||
2. Move the files from SD card to free space.\n \
|
||||
Don\'t move the partial.idx file!\n\
|
||||
3. Unplug and re-plug USB while pressing Vol+.\n\
|
||||
4. Run hekate - ipl again and press Dump RAW eMMC or eMMC USER to continue");
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
@@ -447,18 +556,35 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
bytesWritten = 0;
|
||||
}
|
||||
|
||||
int retryCount=0;
|
||||
retryCount = 0;
|
||||
u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
while(!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kError reading %d blocks @ LBA %08X (try %d) %k\n",
|
||||
gfx_printf(&gfx_con, "%kError reading %d blocks @ LBA %08X from eMMC (try %d)%k\n",
|
||||
0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
|
||||
|
||||
sleep(500000);
|
||||
if (retryCount >= 3)
|
||||
if (retryCount >= 10)
|
||||
goto out;
|
||||
}
|
||||
f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res && !ignoreWriteErrors)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFatal error %d when writing to SD Card%k\n\
|
||||
Press VOL to abort and try again\nPress POWER to ignore errors (will produce a corrupt dump)",
|
||||
0xFF0000FF, res, 0xFFFFFFFF);
|
||||
u32 btn = btn_wait();
|
||||
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
bytesWritten = MULTIPART_SPLIT_SIZE - num * NX_EMMC_BLOCKSIZE;
|
||||
currPartIdx--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ignoreWriteErrors = 1;
|
||||
}
|
||||
}
|
||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
@@ -482,6 +608,13 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
out:;
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
// Partial dump done. Remove partial dump index file.
|
||||
if(partialDumpInProgress)
|
||||
{
|
||||
f_unlink(partialIdxFilename);
|
||||
gfx_printf(&gfx_con, "\n\nYou can now join the files and get the complete raw eMMC dump.\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -503,6 +636,12 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_puts(&gfx_con, "Checking for available free space...\n");
|
||||
// Get SD Card free space for partial dumping
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
}
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
@@ -527,8 +666,8 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
bootPart.name[4] = (u8)('0' + i);
|
||||
bootPart.name[5] = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end);
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%08X-%08X)%k\n", 0xFFFFDD00, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFFFFFFF);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i+1);
|
||||
dump_emmc_part(bootPart.name, &storage, &bootPart);
|
||||
@@ -551,8 +690,8 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
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);
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%08X-%08X)%k\n", 0xFFFFDD00, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFFFFFFF);
|
||||
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
@@ -567,10 +706,10 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
memset(&rawPart, 0, sizeof(rawPart));
|
||||
rawPart.lba_start = 0;
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS-1;
|
||||
strcpy(rawPart.name, "RawNand.bin");
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end);
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%08X-%08X)%k\n", 0xFFFFDD00, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFFFFFFF);
|
||||
|
||||
dump_emmc_part(rawPart.name, &storage, &rawPart);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
@@ -579,7 +718,7 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
}
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
gfx_puts(&gfx_con, "Done.\n");
|
||||
gfx_puts(&gfx_con, "Done. Press any key.\n");
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
@@ -702,7 +841,7 @@ menu_t menu_cinfo = {
|
||||
|
||||
ment_t ment_tools[] = {
|
||||
MDEF_BACK(),
|
||||
MDEF_HANDLER("Dump eMMC RawNand", dump_emmc_rawnand),
|
||||
MDEF_HANDLER("Dump RAW eMMC", dump_emmc_rawnand),
|
||||
MDEF_HANDLER("Dump eMMC SYS", dump_emmc_system),
|
||||
MDEF_HANDLER("Dump eMMC USER", dump_emmc_user),
|
||||
MDEF_HANDLER("Dump eMMC BOOT", dump_emmc_boot),
|
||||
|
||||
15
ipl/sdmmc.c
15
ipl/sdmmc.c
@@ -492,7 +492,7 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage)
|
||||
if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5))
|
||||
return 0;
|
||||
|
||||
return (resp & 0xFFF) == 0x1AA ? 1 : 0;
|
||||
return (resp & 0xFF) == 0xAA ? 1 : 0;
|
||||
}
|
||||
|
||||
static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int supports_low_voltage)
|
||||
@@ -518,7 +518,8 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
||||
{
|
||||
if (cond & 0x40000000)
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
// TODO: Some SD Card incorrectly report low voltage support
|
||||
// Disable it for now
|
||||
if (cond & 0x1000000 && supports_low_voltage)
|
||||
{
|
||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||
@@ -537,7 +538,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
||||
}
|
||||
if (get_tmr() > timeout)
|
||||
break;
|
||||
sleep(1000);
|
||||
sleep(10000); // Needs to be at least 10ms for some SD Cards
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -758,6 +759,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
case 1:
|
||||
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
|
||||
break;
|
||||
case 2:
|
||||
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("[sd] Unknown CSD structure %d\n", csd_struct);
|
||||
//TODO: I've encountered this with one of my SD cards, but
|
||||
@@ -793,7 +797,8 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
memcpy(storage->scr, buf, 8);
|
||||
DPRINTF("[sd] got scr\n");
|
||||
|
||||
if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4)
|
||||
// Check if card supports a wider bus and if it's not SD Version 1.0
|
||||
if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4 && (storage->scr[0] & 0xF))
|
||||
{
|
||||
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN))
|
||||
{
|
||||
@@ -815,7 +820,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
}
|
||||
DPRINTF("[sd] enabled highspeed (low voltage)\n");
|
||||
}
|
||||
else if (type != 6 && storage->scr[0] & 0xF != 0)
|
||||
else if (type != 6 && (storage->scr[0] & 0xF) != 0)
|
||||
{
|
||||
if (!_sd_storage_enable_highspeed_high_volt(storage, buf))
|
||||
{
|
||||
|
||||
@@ -54,24 +54,30 @@ int sdmmc_get_voltage(sdmmc_t *sdmmc)
|
||||
|
||||
static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
u8 pwr = 0;
|
||||
|
||||
switch (power)
|
||||
{
|
||||
case SDMMC_POWER_OFF:
|
||||
sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
break;
|
||||
case SDMMC_POWER_1_8:
|
||||
sdmmc->regs->pwrcon =
|
||||
(sdmmc->regs->pwrcon & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK) |
|
||||
TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
break;
|
||||
case SDMMC_POWER_3_3:
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->pwrcon |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
if (power != SDMMC_POWER_OFF)
|
||||
{
|
||||
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
sdmmc->regs->pwrcon = pwr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user