[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 = 0;
h_cfg.autoboot_list = 0; h_cfg.autoboot_list = 0;
h_cfg.bootwait = 3; h_cfg.bootwait = 3;
h_cfg.verification = 2; h_cfg.verification = 1;
h_cfg.se_keygen_done = 0; h_cfg.se_keygen_done = 0;
h_cfg.sbar_time_keeping = 0; h_cfg.sbar_time_keeping = 0;
h_cfg.backlight = 100; h_cfg.backlight = 100;
@ -453,9 +453,9 @@ void config_verification()
ments[1].type = MENT_CHGLINE; ments[1].type = MENT_CHGLINE;
memcpy(vr_text, " Disable (Fastest)", 19); memcpy(vr_text, " Disable (Fastest - Unsafe)", 28);
memcpy(vr_text + 64, " Sparse (Fast)", 16); memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23);
memcpy(vr_text + 128, " Full (Slow)", 16); memcpy(vr_text + 128, " Full (Slow - Safe)", 23);
for (u32 i = 0; i < 3; i++) for (u32 i = 0; i < 3; i++)
{ {

View file

@ -31,6 +31,10 @@
#include "../utils/btn.h" #include "../utils/btn.h"
#include "../utils/util.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_t sd_sdmmc;
extern sdmmc_storage_t sd_storage; extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs; 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) static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
{ {
FIL fp; FIL fp;
u8 sparseShouldVerify = 0;
u32 btn = 0; u32 btn = 0;
u32 prevPct = 200; u32 prevPct = 200;
int res = 0; 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 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
u32 numSectorsPerIter = 0; const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
if (totalSectorsVer > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
u8 *bufEm = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE); u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
u8 *bufSd = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE); u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); 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); 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; u32 num = 0;
while (totalSectorsVer > 0) while (totalSectorsVer > 0)
{ {
num = MIN(totalSectorsVer, numSectorsPerIter); num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm)) // 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; if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n", {
num, lba_curr); 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); se_calc_sha256(hashEm, bufEm, num << 9);
free(bufSd); se_calc_sha256(hashSd, bufSd, num << 9);
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);
res = memcmp(hashEm, hashSd, 0x10); 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); if (res)
free(bufSd); {
f_close(&fp); gfx_con.fntsz = 16;
return 1; 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); pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct) 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)) if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
{ {
gfx_con.fntsz = 16; gfx_con.fntsz = 16;
WPRINTF("\n\nThe verification was cancelled!"); WPRINTF("\n\nVerification was cancelled!");
EPRINTF("\nPress any key...\n"); EPRINTF("\nPress any key...\n");
msleep(1500); msleep(1000);
free(bufEm);
free(bufSd);
f_close(&fp); f_close(&fp);
return 0; return 0;
} }
} }
free(bufEm);
free(bufSd);
f_close(&fp); f_close(&fp);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555); 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 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 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) if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
multipartSplitSize = (1u << 30); multipartSplitSize = (1u << 30);
// Maximum parts fitting the free space available. // 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. // Check if the USER partition or the RAW eMMC fits the sd card free space.
if (totalSectors > (sd_fs.free_clst * sd_fs.csize)) 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++] = '.'; 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. // Continue from where we left, if Partial Backup in progress.
else _update_filename(outFilename, sdPathLen, numSplitParts, partialDumpInProgress ? currPartIdx : 0);
{
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
} }
FIL fp; FIL fp;
@ -268,7 +250,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
{ {
f_close(&fp); f_close(&fp);
gfx_con.fntsz = 16; gfx_con.fntsz = 16;
WPRINTF("An existing backup has been detected!"); WPRINTF("An existing backup has been detected!");
WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n"); WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n");
msleep(500); msleep(500);
@ -289,12 +271,9 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
return 0; return 0;
} }
u32 numSectorsPerIter = 0; const u32 NUM_SECTORS_PER_ITER = 8192;
if (totalSectors > 0x200000)
numSectorsPerIter = 8192; u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
else
numSectorsPerIter = 512;
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u32 lba_curr = part->lba_start; u32 lba_curr = part->lba_start;
u32 lbaStartPart = 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"); EPRINTF("\nPress any key and try again...\n");
free(buf);
return 0; return 0;
} }
} }
if (numSplitParts >= 10 && currPartIdx < 10) _update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
// Always create partial.idx before next part, in case a fatal error occurs. // Always create partial.idx before next part, in case a fatal error occurs.
if (isSmallSdCard) 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; gfx_con.fntsz = 16;
EPRINTF("\nError creating partial.idx file.\n"); EPRINTF("\nError creating partial.idx file.\n");
free(buf);
return 0; 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"); 4. Select the SAME option again to continue.\n");
gfx_con.fntsz = 16; gfx_con.fntsz = 16;
free(buf);
return 1; 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; gfx_con.fntsz = 16;
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename); EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
free(buf);
return 0; return 0;
} }
bytesWritten = 0; bytesWritten = 0;
@ -400,7 +369,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
} }
retryCount = 0; retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter); num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
while (!sdmmc_storage_read(storage, lba_curr, num, buf)) while (!sdmmc_storage_read(storage, lba_curr, num, buf))
{ {
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...", 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); num, lba_curr);
EPRINTF("\nPress any key and try again...\n"); EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp); f_close(&fp);
f_unlink(outFilename); 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); EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
EPRINTF("\nPress any key and try again...\n"); EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp); f_close(&fp);
f_unlink(outFilename); 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"); EPRINTF("\nPress any key...\n");
msleep(1500); msleep(1500);
free(buf);
f_close(&fp); f_close(&fp);
f_unlink(outFilename); 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); tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Backup operation ended successfully. // Backup operation ended successfully.
free(buf);
f_close(&fp); f_close(&fp);
if (h_cfg.verification) if (h_cfg.verification)
@ -664,13 +629,9 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
else else
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n", ((u32)((u64)f_size(&fp) >> (u64)9)) >> SECTORS_TO_MIB_COEFF); 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; const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
if (totalSectors > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE); u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
u32 lba_curr = part->lba_start; u32 lba_curr = part->lba_start;
u32 bytesWritten = 0; u32 bytesWritten = 0;
@ -682,7 +643,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
while (totalSectors > 0) while (totalSectors > 0)
{ {
retryCount = 0; retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter); num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL); res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
if (res) 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); 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"); EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
free(buf);
f_close(&fp); f_close(&fp);
return 0; return 0;
} }
@ -708,7 +668,6 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
num, lba_curr); num, lba_curr);
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n"); EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
free(buf);
f_close(&fp); f_close(&fp);
return 0; 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); tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Restore operation ended successfully. // Restore operation ended successfully.
free(buf);
f_close(&fp); f_close(&fp);
if (h_cfg.verification) 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); gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u8 value = 10; u8 failsafe_wait = 10;
while (value > 0) while (failsafe_wait > 0)
{ {
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy); 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); msleep(1000);
value--; failsafe_wait--;
} }
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy); 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; 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); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
u32 crc32c(const void *buf, u32 len); 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 #endif