FatFS and general file operations fixes

* Make FatFS thread safe via malloc and remove alloca.
* Fix memory leak from emmc gpt parsing
* Always unmount SD card in menu and when launching
* Use folders for Backup/Dump/Restore operations
* Add error report for some important f_opens
* Don't let partial dumping if backup chosen is not GPP or USER.
This commit is contained in:
Kostas Missos 2018-06-23 07:04:41 +03:00
parent e8ee994ad0
commit f3149e0be3
3 changed files with 77 additions and 37 deletions

View file

@ -97,7 +97,7 @@
*/ */
#define FF_USE_LFN 1 #define FF_USE_LFN 3
#define FF_MAX_LFN 255 #define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name). /* The FF_USE_LFN switches the support for LFN (long file name).
/ /

View file

@ -39,6 +39,7 @@
#include "gfx.h" #include "gfx.h"
extern gfx_ctxt_t gfx_ctxt; extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con; extern gfx_con_t gfx_con;
extern void sd_unmount();
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__) //#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...) #define DPRINTF(...)
@ -480,7 +481,7 @@ int hos_launch(ini_sec_t *cfg)
gfx_printf(&gfx_con, "Rebuilt and loaded package2\n"); gfx_printf(&gfx_con, "Rebuilt and loaded package2\n");
//Unmount SD card. //Unmount SD card.
f_mount(NULL, "", 1); sd_unmount();
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC); gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);

View file

@ -20,7 +20,6 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <alloca.h>
#include "clock.h" #include "clock.h"
#include "uart.h" #include "uart.h"
@ -52,6 +51,7 @@
#include "hos.h" #include "hos.h"
#include "pkg1.h" #include "pkg1.h"
#include "mmc.h" #include "mmc.h"
#include "lz.h"
//TODO: ugly. //TODO: ugly.
gfx_ctxt_t gfx_ctxt; gfx_ctxt_t gfx_ctxt;
@ -139,7 +139,10 @@ void *sd_file_read(char *path)
int sd_save_to_file(void * buf, u32 size, const char * filename) int sd_save_to_file(void * buf, u32 size, const char * filename)
{ {
FIL fp; FIL fp;
if (f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) { u32 res = 0;
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK;
if (res) {
EPRINTFARGS("Error (%d) creating file %s.\n", res, filename);
return 1; return 1;
} }
@ -357,14 +360,15 @@ void print_fuseinfo()
{ {
if (sd_mount()) if (sd_mount())
{ {
char fuseFilename[9]; char fuseFilename[23];
memcpy(fuseFilename, "fuse.bin", 8); f_mkdir("Backup/Dumps");
fuseFilename[8] = 0; memcpy(fuseFilename, "Backup/Dumps/fuses.bin\0", 23);
if (sd_save_to_file((u8 *)0x7000F900, 0x2FC, fuseFilename)) if (sd_save_to_file((u8 *)0x7000F900, 0x2FC, fuseFilename))
EPRINTF("\nError creating fuse.bin file."); EPRINTF("\nError creating fuse.bin file.");
else else
gfx_puts(&gfx_con, "\nDone!\n"); gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
} }
btn_wait(); btn_wait();
@ -390,14 +394,15 @@ void print_kfuseinfo()
{ {
if (sd_mount()) if (sd_mount())
{ {
char kfuseFilename[10]; char kfuseFilename[24];
memcpy(kfuseFilename, "kfuse.bin", 9); f_mkdir("Backup/Dumps");
kfuseFilename[9] = 0; memcpy(kfuseFilename, "Backup/Dumps/kfuses.bin\0", 24);
if (sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, kfuseFilename)) if (sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, kfuseFilename))
EPRINTF("\nError creating kfuse.bin file."); EPRINTF("\nError creating kfuse.bin file.");
else else
gfx_puts(&gfx_con, "\nDone!\n"); gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
} }
btn_wait(); btn_wait();
@ -538,6 +543,7 @@ void print_mmc_info()
gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF, gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end); part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
} }
nx_emmc_gpt_free(&gpt);
} }
} }
@ -593,6 +599,7 @@ void print_sdcard_info()
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n", gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC, 0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC,
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512); sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
sd_unmount();
} }
btn_wait(); btn_wait();
@ -753,7 +760,7 @@ int dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char* outFilename,
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 const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF; static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
static const u32 SECTORS_TO_MIB_COEFF = 11; static const u32 SECTORS_TO_MIB_COEFF = 11;
u32 multipartSplitSize = (1u << 31); u32 multipartSplitSize = (1u << 31);
u32 totalSectors = part->lba_end - part->lba_start + 1; u32 totalSectors = part->lba_end - part->lba_start + 1;
@ -763,13 +770,12 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
int isSmallSdCard = 0; int isSmallSdCard = 0;
int partialDumpInProgress = 0; int partialDumpInProgress = 0;
int res = 0; int res = 0;
char* outFilename = sd_path; char *outFilename = sd_path;
u32 sdPathLen = strlen(sd_path); u32 sdPathLen = strlen(sd_path);
FIL partialIdxFp; FIL partialIdxFp;
char partialIdxFilename[12]; char partialIdxFilename[12];
memcpy(partialIdxFilename, "partial.idx", 11); memcpy(partialIdxFilename, "partial.idx\0", 12);
partialIdxFilename[11] = 0;
gfx_printf(&gfx_con, "\nSD Card free space: %d MiB, Total backup size %d MiB\n\n", gfx_printf(&gfx_con, "\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
@ -795,8 +801,8 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
return 0; return 0;
} }
} }
// Check if we continuing a previous raw eMMC backup in progress. // Check if we are continuing a previous raw eMMC or USER partition backup in progress.
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK) if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
{ {
gfx_printf(&gfx_con, "%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC); gfx_printf(&gfx_con, "%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
@ -826,8 +832,6 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE; u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors; numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
outFilename = alloca(sdPathLen+4);
memcpy(outFilename, sd_path, sdPathLen);
outFilename[sdPathLen++] = '.'; outFilename[sdPathLen++] = '.';
if (!partialDumpInProgress) if (!partialDumpInProgress)
@ -855,15 +859,22 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
} }
FIL fp; FIL fp;
if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK;
if (res)
{ {
EPRINTFARGS("Error creating file %s.\n", outFilename); EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
return 0; return 0;
} }
static const u32 NUM_SECTORS_PER_ITER = 512; u32 numSectorsPerIter = 0;
u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * NUM_SECTORS_PER_ITER); if (totalSectors > 0x200000)
numSectorsPerIter = 8192;
else
numSectorsPerIter = 512;
u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * numSectorsPerIter);
u32 lba_curr = part->lba_start; u32 lba_curr = part->lba_start;
u32 bytesWritten = 0; u32 bytesWritten = 0;
@ -877,6 +888,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE); totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
} }
u32 num = 0;
while(totalSectors > 0) while(totalSectors > 0)
{ {
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize) if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
@ -886,7 +898,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
currPartIdx++; currPartIdx++;
// Verify part. // Verify part.
if (dump_emmc_verify(storage, lba_curr, outFilename, NUM_SECTORS_PER_ITER, part)) if (dump_emmc_verify(storage, lba_curr, outFilename, numSectorsPerIter, part))
{ {
EPRINTF("\nPress any key and try again...\n"); EPRINTF("\nPress any key and try again...\n");
@ -934,9 +946,12 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
} }
// Create next part. // Create next part.
if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK;
if (res)
{ {
EPRINTFARGS("Error creating file %s.\n", outFilename); EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
free(buf); free(buf);
return 0; return 0;
@ -945,7 +960,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
} }
retryCount = 0; retryCount = 0;
u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER); num = MIN(totalSectors, numSectorsPerIter);
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 from eMMC (try %d), retrying...", EPRINTFARGS("Error reading %d blocks @ LBA %08X from eMMC (try %d), retrying...",
@ -998,7 +1013,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
f_close(&fp); f_close(&fp);
// Verify last part or single file backup. // Verify last part or single file backup.
if (dump_emmc_verify(storage, lba_curr, outFilename, NUM_SECTORS_PER_ITER, part)) if (dump_emmc_verify(storage, lba_curr, outFilename, numSectorsPerIter, part))
{ {
EPRINTF("\nPress any key and try again...\n"); EPRINTF("\nPress any key and try again...\n");
@ -1050,7 +1065,15 @@ static void dump_emmc_selected(dumpType_t dumpType)
} }
int i = 0; int i = 0;
char sdPath[64];
memcpy(sdPath, "Backup/", 7);
timer = get_tmr(); timer = get_tmr();
// Create Backup/Restore folders, if they do not exist.
f_mkdir("Backup");
f_mkdir("Backup/Partitions");
f_mkdir("Backup/Restore");
if (dumpType & DUMP_BOOT) if (dumpType & DUMP_BOOT)
{ {
static const u32 BOOT_PART_SIZE = 0x400000; static const u32 BOOT_PART_SIZE = 0x400000;
@ -1069,7 +1092,9 @@ static void dump_emmc_selected(dumpType_t dumpType)
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC); bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, i+1); sdmmc_storage_set_mmc_partition(&storage, i+1);
res = dump_emmc_part(bootPart.name, &storage, &bootPart);
strcpy(sdPath + 7, bootPart.name);
res = dump_emmc_part(sdPath, &storage, &bootPart);
} }
} }
@ -1091,13 +1116,20 @@ static void dump_emmc_selected(dumpType_t dumpType)
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++, gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC); part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
res = dump_emmc_part(part->name, &storage, part); memcpy(sdPath, "Backup/Partitions/", 18);
strcpy(sdPath + 18, part->name);
res = dump_emmc_part(sdPath, &storage, part);
// If a part failed, don't continue.
if (!res)
break;
} }
nx_emmc_gpt_free(&gpt);
} }
if (dumpType & DUMP_RAW) if (dumpType & DUMP_RAW)
{ {
static const u32 RAW_AREA_NUM_SECTORS = 0x3A3E000; // Get GP partition size dynamically.
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
emmc_part_t rawPart; emmc_part_t rawPart;
memset(&rawPart, 0, sizeof(rawPart)); memset(&rawPart, 0, sizeof(rawPart));
@ -1108,7 +1140,8 @@ static void dump_emmc_selected(dumpType_t dumpType)
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++, gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC); rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
res = dump_emmc_part(rawPart.name, &storage, &rawPart); strcpy(sdPath + 7, rawPart.name);
res = dump_emmc_part(sdPath, &storage, &rawPart);
} }
} }
} }
@ -1120,6 +1153,7 @@ static void dump_emmc_selected(dumpType_t dumpType)
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n",0xFF96FF00, 0xFFCCCCCC); gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n",0xFF96FF00, 0xFFCCCCCC);
out:; out:;
sd_unmount();
btn_wait(); btn_wait();
} }
@ -1183,28 +1217,29 @@ void dump_package1()
gfx_printf(&gfx_con, "%kWarmboot ofst: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_off); gfx_printf(&gfx_con, "%kWarmboot ofst: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_off);
// Dump package1. // Dump package1.
if (sd_save_to_file(pkg1, 0x40000, "pkg1_decr.bin")) { f_mkdir("Backup/pkg1");
if (sd_save_to_file(pkg1, 0x40000, "Backup/pkg1/pkg1_decr.bin")) {
EPRINTF("\nFailed to create pkg1_decr.bin"); EPRINTF("\nFailed to create pkg1_decr.bin");
goto out; goto out;
} }
gfx_puts(&gfx_con, "\npackage1 dumped to pkg1_decr.bin\n"); gfx_puts(&gfx_con, "\nFull package1 dumped to pkg1_decr.bin\n");
// Dump nxbootloader. // Dump nxbootloader.
if (sd_save_to_file(loader, hdr->ldr_size, "nxloader.bin")) { if (sd_save_to_file(loader, hdr->ldr_size, "Backup/pkg1/nxloader.bin")) {
EPRINTF("\nFailed to create nxloader.bin"); EPRINTF("\nFailed to create nxloader.bin");
goto out; goto out;
} }
gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n"); gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
// Dump secmon. // Dump secmon.
if (sd_save_to_file(secmon, hdr->sm_size, "secmon.bin")) { if (sd_save_to_file(secmon, hdr->sm_size, "Backup/pkg1/secmon.bin")) {
EPRINTF("\nFailed to create secmon.bin"); EPRINTF("\nFailed to create secmon.bin");
goto out; goto out;
} }
gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n"); gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
// Dump warmboot. // Dump warmboot.
if (sd_save_to_file(warmboot, hdr->wb_size, "warmboot.bin")) { if (sd_save_to_file(warmboot, hdr->wb_size, "Backup/pkg1/warmboot.bin")) {
EPRINTF("\nFailed to create warmboot.bin"); EPRINTF("\nFailed to create warmboot.bin");
goto out; goto out;
} }
@ -1212,6 +1247,7 @@ void dump_package1()
sdmmc_storage_end(&storage); sdmmc_storage_end(&storage);
sd_unmount();
gfx_puts(&gfx_con, "\nDone. Press any key...\n"); gfx_puts(&gfx_con, "\nDone. Press any key...\n");
out:; out:;
@ -1403,6 +1439,7 @@ void fix_sd_attr(){
buff[1] = 0; buff[1] = 0;
fix_attributes(buff, &total); fix_attributes(buff, &total);
gfx_printf(&gfx_con, "\n%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC); gfx_printf(&gfx_con, "\n%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
sd_unmount();
} }
btn_wait(); btn_wait();
} }
@ -1548,10 +1585,12 @@ void ipl_main()
u32 *fb = display_init_framebuffer(); u32 *fb = display_init_framebuffer();
gfx_init_ctxt(&gfx_ctxt, fb, 720, 1280, 768); gfx_init_ctxt(&gfx_ctxt, fb, 720, 1280, 768);
gfx_clear_grey(&gfx_ctxt, 0x1B); gfx_clear_grey(&gfx_ctxt, 0x1B);
#ifdef MENU_LOGO_ENABLE #ifdef MENU_LOGO_ENABLE
Kc_MENU_LOGO = (u8 *)malloc(36864); Kc_MENU_LOGO = (u8 *)malloc(36864);
LZ_Uncompress(Kc_MENU_LOGOlz, Kc_MENU_LOGO, SZ_MENU_LOGOLZ); LZ_Uncompress(Kc_MENU_LOGOlz, Kc_MENU_LOGO, SZ_MENU_LOGOLZ);
#endif //MENU_LOGO_ENABLE #endif //MENU_LOGO_ENABLE
gfx_con_init(&gfx_con, &gfx_ctxt); gfx_con_init(&gfx_con, &gfx_ctxt);
// Enable backlight after initializing gfx // Enable backlight after initializing gfx