diff --git a/source/tegraexplorer/common/common.h b/source/tegraexplorer/common/common.h index 263e001..38b1eb4 100644 --- a/source/tegraexplorer/common/common.h +++ b/source/tegraexplorer/common/common.h @@ -16,7 +16,9 @@ enum utils_err_codes_te_call { ERR_PART_NOT_FOUND, ERR_BISKEY_DUMP_FAILED, ERR_MEM_ALLOC_FAILED, - ERR_EMMC_READ_FAILED + ERR_EMMC_READ_FAILED, + ERR_EMMC_WRITE_FAILED, + ERR_FILE_TOO_BIG_FOR_DEST }; extern const char *utils_err_codes_te[]; @@ -60,8 +62,8 @@ enum mainmenu_tools_return { extern menu_entry mainmenu_tools[]; enum mainmenu_format_return { - FORMAT_EMUMMC = 1, - FORMAT_ALL_FAT32 + FORMAT_ALL_FAT32 = 1, + FORMAT_EMUMMC }; extern menu_entry mainmenu_format[]; diff --git a/source/tegraexplorer/common/strings.c b/source/tegraexplorer/common/strings.c index df5c50b..b37fc1e 100644 --- a/source/tegraexplorer/common/strings.c +++ b/source/tegraexplorer/common/strings.c @@ -46,7 +46,9 @@ const char *utils_err_codes_te[] = { // these start at 50 "PART NOT FOUND", "BISKEY DUMP FAILED", "MEM ALLOC FAILED", - "EMMC READ FAILED" + "EMMC READ FAILED", + "EMMC WRITE FAILED", + "FILE TOO BIG FOR DEST" }; const char *pkg2names[] = { diff --git a/source/tegraexplorer/emmc/emmcoperations.h b/source/tegraexplorer/emmc/emmcoperations.h index 5a06cb5..05f5e0e 100644 --- a/source/tegraexplorer/emmc/emmcoperations.h +++ b/source/tegraexplorer/emmc/emmcoperations.h @@ -1,4 +1,5 @@ #pragma once #include "../../utils/types.h" -int dump_emmc_parts(u16 parts, u8 mmctype); \ No newline at end of file +int dump_emmc_parts(u16 parts, u8 mmctype); +int restore_bis_using_file(char *path, u8 mmctype); \ No newline at end of file diff --git a/source/tegraexplorer/emmc/emmcrestorebis.c b/source/tegraexplorer/emmc/emmcrestorebis.c new file mode 100644 index 0000000..10ddefd --- /dev/null +++ b/source/tegraexplorer/emmc/emmcrestorebis.c @@ -0,0 +1,167 @@ +#include +#include "emmcoperations.h" +#include "../../gfx/gfx.h" +#include "../gfx/gfxutils.h" +#include "../../utils/types.h" +#include "emmc.h" +#include "../../storage/emummc.h" +#include "../common/common.h" +#include "../../libs/fatfs/ff.h" +#include "../../utils/sprintf.h" +#include "../../utils/btn.h" +#include "../../mem/heap.h" +#include "../../storage/nx_emmc.h" +#include "../common/types.h" +#include "../utils/utils.h" +#include "../fs/fsutils.h" + +extern sdmmc_storage_t storage; +extern emmc_part_t *system_part; + +int restore_emmc_part(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){ + FIL fp; + FILINFO fno; + u8 *buf; + u32 lba_curr = part->lba_start; + u32 bytesWritten = 0; + u32 totalSectorsDest = part->lba_end - part->lba_start + 1; + u64 totalSizeDest = (u64)((u64)totalSectorsDest << 9); + u64 totalSize; + u32 num = 0; + u32 pct = 0; + int res; + + gfx_printf("Initializing\r"); + + buf = calloc(16384, sizeof(u8)); + + if (!buf){ + gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1); + return -1; + } + + if ((res = f_stat(path, &fno))){ + gfx_errDisplay("restore_emmc_part", res, 2); + return -1; + } + + totalSize = fno.fsize; + u64 totalSectors = totalSize / NX_EMMC_BLOCKSIZE; + + if (totalSize > totalSizeDest){ + gfx_errDisplay("restore_emmc_part", ERR_FILE_TOO_BIG_FOR_DEST, 3); + return -1; + } + + gfx_printf("Flashing %s\n", part->name); + + if (totalSize < totalSizeDest){ + SWAPCOLOR(COLOR_ORANGE); + gfx_printf("File is too small for destenation.\nDo you want to flash it anyway?\n\nVol +/- to Cancel\n"); + u8 btnres = gfx_makewaitmenu( + "Power to Confirm", + 2 + ); + + RESETCOLOR; + + if (!btnres){ + gfx_printf("\nCancelled: %s\n\n", part->name); + return 0; + } + else + gfx_printf("\nFlashing %s\n", part->name); + } + + if ((res = f_open(&fp, path, FA_OPEN_ALWAYS | FA_READ))){ + gfx_errDisplay("restore_emmc_part", res, 4); + return -1; + } + + while (totalSectors > 0){ + num = MIN(totalSectors, 32); + + if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){ + gfx_errDisplay("restore_emmc_part", res, 5); + return -1; + } + + if (!emummc_storage_write(mmcstorage, lba_curr, num, buf)){ + gfx_errDisplay("restore_emmc_part", ERR_EMMC_WRITE_FAILED, 2); + return -1; + } + + lba_curr += num; + totalSectors -= num; + bytesWritten += num * NX_EMMC_BLOCKSIZE; + + pct = (u64)((u64)(bytesWritten) * 100u) / (u64)(fno.fsize); + gfx_printf("Progress: %d%%\r", pct); + } + + gfx_printf(" \r"); + f_close(&fp); + free(buf); + return 0; +} + +int restore_emmc_file(char *path, const char *target, u8 partition, u8 mmctype){ + connect_mmc(mmctype); + + if (partition){ + emmc_part_t bootPart; + const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17; + memset(&bootPart, 0, sizeof(bootPart)); + + bootPart.lba_start = 0; + bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; + + strcpy(bootPart.name, target); + + emummc_storage_set_mmc_partition(&storage, partition); + restore_emmc_part(path, &storage, &bootPart); + } + else { + if (connect_part(target)){ + gfx_errDisplay("restore_emmc_part", ERR_PART_NOT_FOUND, 0); + return -1; + } + restore_emmc_part(path, &storage, system_part); + } + return 0; +} + +int restore_bis_using_file(char *path, u8 mmctype){ + f_mkdir("sd:/tegraexplorer"); + f_mkdir("sd:/tegraexplorer/bis"); + gfx_clearscreen(); + + if (extract_bis_file(path, "sd:/tegraexplorer/bis")) + return -1; + + SWAPBGCOLOR(COLOR_RED); + SWAPCOLOR(COLOR_DEFAULT); + gfx_printf("\nAre you sure you want to flash these files\nThis could leave your switch unbootable!\nTarget is SysMMC\n\nVol +/- to cancel\n"); + if (!gfx_makewaitmenu( + "Power to confirm", + 10 + )) + { + return 0; + } + RESETCOLOR; + + gfx_printf("\nRestoring BIS...\n\n"); + + restore_emmc_file("sd:/tegraexplorer/bis/BOOT0.bin", "BOOT0", 1, mmctype); + restore_emmc_file("sd:/tegraexplorer/bis/BOOT1.bin", "BOOT1", 2, mmctype); + restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-1-Normal-Main", pkg2names[0], 0, mmctype); + restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-1-Normal-Main", pkg2names[1], 0, mmctype); + restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-3-SafeMode-Main", pkg2names[2], 0, mmctype); + restore_emmc_file("sd:/tegraexplorer/bis/BCPKG2-3-SafeMode-Main", pkg2names[3], 0, mmctype); + + gfx_printf("\n\nDone!\nPress any button to return"); + btn_wait(); + + return 0; +} \ No newline at end of file diff --git a/source/tegraexplorer/fs/filemenu.c b/source/tegraexplorer/fs/filemenu.c index db71527..8c0360a 100644 --- a/source/tegraexplorer/fs/filemenu.c +++ b/source/tegraexplorer/fs/filemenu.c @@ -14,6 +14,7 @@ #include "../common/types.h" #include "../../utils/sprintf.h" #include "../utils/script.h" +#include "../emmc/emmcoperations.h" extern char *currentpath; extern char *clipboard; @@ -170,14 +171,13 @@ int filemenu(menu_entry file){ viewbytes(fsutil_getnextloc(currentpath, file.name)); break; case FILE_DUMPBIS: - /* - clearscreen(); - extract_bis_file(getnextloc(currentpath, file.name), currentpath); + gfx_clearscreen(); + extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath); + fsreader_readfolder(currentpath); btn_wait(); - */ break; case FILE_RESTOREBIS: - gfx_message(COLOR_ORANGE, "Stubbed"); + restore_bis_using_file(fsutil_getnextloc(currentpath, file.name), SYSMMC); break; } diff --git a/source/tegraexplorer/fs/fsextractbis.c b/source/tegraexplorer/fs/fsextractbis.c new file mode 100644 index 0000000..5e50b91 --- /dev/null +++ b/source/tegraexplorer/fs/fsextractbis.c @@ -0,0 +1,94 @@ +#include "fsutils.h" +#include +#include "../../gfx/gfx.h" +#include "../gfx/gfxutils.h" +#include "../../utils/types.h" +#include "../../storage/emummc.h" +#include "../common/common.h" +#include "../../libs/fatfs/ff.h" +#include "../../utils/sprintf.h" +#include "../../utils/btn.h" +#include "../../mem/heap.h" +#include "../../storage/nx_emmc.h" +#include "../common/types.h" +#include "../utils/utils.h" + +u32 DecodeInt(u8* data) { + u32 out = 0; + + for (int i = 0; i < 4; i++) { + out |= (data[i] << ((3 - i) * 8)); + } + + return out; +} + +void copy_fil_size(FIL* in_src, FIL* out_src, int size_src){ + u8* buff; + buff = calloc(16384, sizeof(u8)); + + int size = size_src; + int copysize; + + while (size > 0){ + copysize = MIN(16834, size); + f_read(in_src, buff, copysize, NULL); + f_write(out_src, buff, copysize, NULL); + size -= copysize; + } + + free(buff); +} + +void gen_part(int size, FIL* in, char *path){ + FIL out; + + f_open(&out, path, FA_WRITE | FA_CREATE_ALWAYS); + copy_fil_size(in, &out, size); + f_close(&out); +} + +int extract_bis_file(char *path, char *outfolder){ + FIL in; + int res; + u8 version[0x10]; + u8 args; + u8 temp[0x4]; + u32 filesizes[4]; + + if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){ + gfx_errDisplay("extract_bis_file", res, 0); + return -1; + } + + f_read(&in, version, 0x10, NULL); + f_read(&in, &args, 1, NULL); + + for (int i = 0; i < 4; i++){ + f_read(&in, temp, 4, NULL); + filesizes[i] = DecodeInt(temp); + } + + gfx_printf("Version: %s\n\n", version); + + gfx_printf("\nExtracting BOOT0\n"); + if (args & BOOT0_ARG) + gen_part(filesizes[0], &in, fsutil_getnextloc(outfolder, "BOOT0.bin")); + + gfx_printf("Extracting BOOT1\n"); + if (args & BOOT1_ARG) + gen_part(filesizes[1], &in, fsutil_getnextloc(outfolder, "BOOT1.bin")); + + gfx_printf("Extracting BCPKG2_1\n"); + if (args & BCPKG2_1_ARG) + gen_part(filesizes[2], &in, fsutil_getnextloc(outfolder, "BCPKG2-1-Normal-Main")); + + gfx_printf("Extracting BCPKG2_3\n"); + if (args & BCPKG2_3_ARG) + gen_part(filesizes[3], &in, fsutil_getnextloc(outfolder, "BCPKG2-3-SafeMode-Main")); + + gfx_printf("\n\nDone!\n"); + + f_close(&in); + return 0; +} \ No newline at end of file diff --git a/source/tegraexplorer/fs/fsutils.h b/source/tegraexplorer/fs/fsutils.h index 6001b1e..37c0b5f 100644 --- a/source/tegraexplorer/fs/fsutils.h +++ b/source/tegraexplorer/fs/fsutils.h @@ -7,4 +7,5 @@ char *fsutil_getprevloc(char *current); int fsutil_getfileobjamount(menu_entry *entries); bool fsutil_checkfile(char* path); u64 fsutil_getfilesize(char *path); -int fsutil_getfolderentryamount(const char *path); \ No newline at end of file +int fsutil_getfolderentryamount(const char *path); +int extract_bis_file(char *path, char *outfolder); \ No newline at end of file diff --git a/source/tegraexplorer/gfx/gfxutils.c b/source/tegraexplorer/gfx/gfxutils.c index 747d58c..ae55a79 100644 --- a/source/tegraexplorer/gfx/gfxutils.c +++ b/source/tegraexplorer/gfx/gfxutils.c @@ -50,7 +50,7 @@ int gfx_errDisplay(char *src_func, int err, int loc){ if (err < 15) gfx_printf("Desc: %s\n", utils_err_codes[err]); - else if (err >= 50 && err <= ERR_BISKEY_DUMP_FAILED) + else if (err >= ERR_SAME_LOC && err <= ERR_FILE_TOO_BIG_FOR_DEST) gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]); if (loc) diff --git a/source/tegraexplorer/gfx/menu.c b/source/tegraexplorer/gfx/menu.c index d302a82..3ff75da 100644 --- a/source/tegraexplorer/gfx/menu.c +++ b/source/tegraexplorer/gfx/menu.c @@ -54,7 +54,7 @@ void _printentry(menu_entry entry, bool highlighted, bool refresh){ } int menu_make(menu_entry *entries, int amount, char *toptext){ - int currentpos = 0, i, res = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 59; + int currentpos = 0, res = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 59; u32 scrolltimer, timer; bool refresh = false;