mirror of
https://github.com/CTCaer/hekate.git
synced 2024-12-27 18:36:01 +00:00
[Backup & Restore] Performance changes
- Use always aligned buffers to up the speed for DMA usage. For verification, backup and restore. - Rework verification a little bit and make default Sparse mode. Sparse mode protects from fake sd cards, bad sectors and frequent I/O corruption. Aka, ~100% of cases.
This commit is contained in:
parent
b1110caed1
commit
bafc6f4a1d
4 changed files with 75 additions and 149 deletions
|
@ -36,7 +36,7 @@ void set_default_configuration()
|
|||
h_cfg.autoboot = 0;
|
||||
h_cfg.autoboot_list = 0;
|
||||
h_cfg.bootwait = 3;
|
||||
h_cfg.verification = 2;
|
||||
h_cfg.verification = 1;
|
||||
h_cfg.se_keygen_done = 0;
|
||||
h_cfg.sbar_time_keeping = 0;
|
||||
h_cfg.backlight = 100;
|
||||
|
@ -453,9 +453,9 @@ void config_verification()
|
|||
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
|
||||
memcpy(vr_text, " Disable (Fastest)", 19);
|
||||
memcpy(vr_text + 64, " Sparse (Fast)", 16);
|
||||
memcpy(vr_text + 128, " Full (Slow)", 16);
|
||||
memcpy(vr_text, " Disable (Fastest - Unsafe)", 28);
|
||||
memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23);
|
||||
memcpy(vr_text + 128, " Full (Slow - Safe)", 23);
|
||||
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,10 @@
|
|||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define EMMC_BUF_ALIGNED 0x85000000
|
||||
#define SDXC_BUF_ALIGNED 0x86000000
|
||||
#define MIXD_BUF_ALIGNED 0x87000000
|
||||
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
extern FATFS sd_fs;
|
||||
|
@ -43,6 +47,7 @@ extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_st
|
|||
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
|
||||
{
|
||||
FIL fp;
|
||||
u8 sparseShouldVerify = 0;
|
||||
u32 btn = 0;
|
||||
u32 prevPct = 200;
|
||||
int res = 0;
|
||||
|
@ -54,14 +59,10 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
|
|||
{
|
||||
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
|
||||
|
||||
u32 numSectorsPerIter = 0;
|
||||
if (totalSectorsVer > 0x200000)
|
||||
numSectorsPerIter = 8192; //4MB Cache
|
||||
else
|
||||
numSectorsPerIter = 512; //256KB Cache
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
|
||||
|
||||
u8 *bufEm = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
||||
u8 *bufSd = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
||||
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
|
||||
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
|
||||
|
||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
|
||||
|
@ -69,53 +70,47 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
|
|||
u32 num = 0;
|
||||
while (totalSectorsVer > 0)
|
||||
{
|
||||
num = MIN(totalSectorsVer, numSectorsPerIter);
|
||||
|
||||
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
|
||||
num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);
|
||||
|
||||
// Check every time or every 4.
|
||||
// Every 4 protects from fake sd, sector corruption and frequent I/O corruption.
|
||||
// Full provides all that, plus protection from extremely rare I/O corruption.
|
||||
if ((h_cfg.verification & 2) || !(sparseShouldVerify % 4))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
|
||||
num, lba_curr);
|
||||
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
|
||||
num, lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
if (f_read(&fp, bufSd, num << 9, NULL))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(bufEm);
|
||||
free(bufSd);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
if (f_read(&fp, bufSd, num << 9, NULL))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
|
||||
|
||||
free(bufEm);
|
||||
free(bufSd);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (h_cfg.verification)
|
||||
{
|
||||
case 1:
|
||||
res = memcmp32sparse((u32 *)bufEm, (u32 *)bufSd, num << 9);
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
se_calc_sha256(&hashEm, bufEm, num << 9);
|
||||
se_calc_sha256(&hashSd, bufSd, num << 9);
|
||||
se_calc_sha256(hashEm, bufEm, num << 9);
|
||||
se_calc_sha256(hashSd, bufSd, num << 9);
|
||||
res = memcmp(hashEm, hashSd, 0x10);
|
||||
break;
|
||||
}
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nSD card and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
|
||||
|
||||
free(bufEm);
|
||||
free(bufSd);
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
if (res)
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("\nSD and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sparseShouldVerify++;
|
||||
|
||||
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
|
@ -130,19 +125,15 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
|
|||
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
|
||||
{
|
||||
gfx_con.fntsz = 16;
|
||||
WPRINTF("\n\nThe verification was cancelled!");
|
||||
WPRINTF("\n\nVerification was cancelled!");
|
||||
EPRINTF("\nPress any key...\n");
|
||||
msleep(1500);
|
||||
msleep(1000);
|
||||
|
||||
free(bufEm);
|
||||
free(bufSd);
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
free(bufEm);
|
||||
free(bufSd);
|
||||
f_close(&fp);
|
||||
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
|
||||
|
@ -157,6 +148,17 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
|
|||
}
|
||||
}
|
||||
|
||||
void _update_filename(char *outFilename, u32 sdPathLen, u32 numSplitParts, u32 currPartIdx)
|
||||
{
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
|
||||
}
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
}
|
||||
|
||||
static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
{
|
||||
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
|
||||
|
@ -187,7 +189,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
||||
multipartSplitSize = (1u << 30);
|
||||
// Maximum parts fitting the free space available.
|
||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / 512);
|
||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
||||
|
||||
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||
|
@ -238,28 +240,8 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
|
||||
outFilename[sdPathLen++] = '.';
|
||||
|
||||
if (!partialDumpInProgress)
|
||||
{
|
||||
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 Backup in progress.
|
||||
else
|
||||
{
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
|
||||
}
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
}
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, partialDumpInProgress ? currPartIdx : 0);
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
|
@ -268,7 +250,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
{
|
||||
f_close(&fp);
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
|
||||
WPRINTF("An existing backup has been detected!");
|
||||
WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n");
|
||||
msleep(500);
|
||||
|
@ -289,12 +271,9 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32 numSectorsPerIter = 0;
|
||||
if (totalSectors > 0x200000)
|
||||
numSectorsPerIter = 8192;
|
||||
else
|
||||
numSectorsPerIter = 512;
|
||||
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192;
|
||||
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 lbaStartPart = part->lba_start;
|
||||
|
@ -333,18 +312,11 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
{
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
|
||||
}
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
|
||||
|
||||
// Always create partial.idx before next part, in case a fatal error occurs.
|
||||
if (isSmallSdCard)
|
||||
|
@ -360,7 +332,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
gfx_con.fntsz = 16;
|
||||
EPRINTF("\nError creating partial.idx file.\n");
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -374,7 +345,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
4. Select the SAME option again to continue.\n");
|
||||
gfx_con.fntsz = 16;
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -389,7 +359,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
gfx_con.fntsz = 16;
|
||||
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
bytesWritten = 0;
|
||||
|
@ -400,7 +369,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
}
|
||||
|
||||
retryCount = 0;
|
||||
num = MIN(totalSectors, numSectorsPerIter);
|
||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||
{
|
||||
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
|
||||
|
@ -414,7 +383,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
num, lba_curr);
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
|
@ -428,7 +396,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
|
||||
EPRINTF("\nPress any key and try again...\n");
|
||||
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
|
@ -460,7 +427,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
EPRINTF("\nPress any key...\n");
|
||||
msleep(1500);
|
||||
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
f_unlink(outFilename);
|
||||
|
||||
|
@ -470,7 +436,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
|||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Backup operation ended successfully.
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
|
||||
if (h_cfg.verification)
|
||||
|
@ -664,13 +629,9 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||
else
|
||||
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n", ((u32)((u64)f_size(&fp) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
|
||||
|
||||
u32 numSectorsPerIter = 0;
|
||||
if (totalSectors > 0x200000)
|
||||
numSectorsPerIter = 8192; //4MB Cache
|
||||
else
|
||||
numSectorsPerIter = 512; //256KB Cache
|
||||
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
|
||||
|
||||
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
|
||||
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
|
@ -682,7 +643,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||
while (totalSectors > 0)
|
||||
{
|
||||
retryCount = 0;
|
||||
num = MIN(totalSectors, numSectorsPerIter);
|
||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
|
||||
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res)
|
||||
|
@ -691,7 +652,6 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||
EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res);
|
||||
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
|
||||
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
@ -708,7 +668,6 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||
num, lba_curr);
|
||||
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
|
||||
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
@ -727,7 +686,6 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
|||
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||
|
||||
// Restore operation ended successfully.
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
|
||||
if (h_cfg.verification)
|
||||
|
@ -769,13 +727,13 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
|||
}
|
||||
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
|
||||
|
||||
u8 value = 10;
|
||||
while (value > 0)
|
||||
u8 failsafe_wait = 10;
|
||||
while (failsafe_wait > 0)
|
||||
{
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
|
||||
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
|
||||
msleep(1000);
|
||||
value--;
|
||||
failsafe_wait--;
|
||||
}
|
||||
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
|
||||
|
||||
|
|
|
@ -120,31 +120,3 @@ u32 crc32c(const void *buf, u32 len)
|
|||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len)
|
||||
{
|
||||
u32 len32 = len / 4;
|
||||
|
||||
if (!(len32 % 32))
|
||||
{
|
||||
while (len32)
|
||||
{
|
||||
len32 -= 32;
|
||||
if(buf1[len32] != buf2[len32])
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (len32)
|
||||
{
|
||||
len32 -= 32;
|
||||
if(buf1[len32] != buf2[len32])
|
||||
return 1;
|
||||
if (len32 < 32)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,4 @@ void power_off();
|
|||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
||||
u32 crc32c(const void *buf, u32 len);
|
||||
|
||||
/* This is a faster implementation of memcmp that checks two u32 values */
|
||||
/* every 128 Bytes block. Intented only for Backup and Restore */
|
||||
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue