[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:
Kostas Missos 2019-03-08 00:30:56 +02:00
parent b1110caed1
commit bafc6f4a1d
4 changed files with 75 additions and 149 deletions

View file

@ -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++)
{

View file

@ -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);

View file

@ -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;
}

View file

@ -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