diff --git a/Makefile b/Makefile index 0636af7..7299bda 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules IPL_LOAD_ADDR := 0x40003000 LPVERSION_MAJOR := 2 LPVERSION_MINOR := 3 -LPVERSION_BUGFX := 2 +LPVERSION_BUGFX := 3 ################################################################################ diff --git a/source/tegraexplorer/fs.c b/source/tegraexplorer/fs.c index 0fbf989..ee7c37a 100644 --- a/source/tegraexplorer/fs.c +++ b/source/tegraexplorer/fs.c @@ -19,7 +19,7 @@ u8 clipboardhelper = 0; extern const char sizevalues[4][3]; extern int launch_payload(char *path); -menu_item explfilemenu[11] = { +menu_item explfilemenu[12] = { {"-- File Menu --", COLOR_BLUE, -1, 0}, {"FILE", COLOR_GREEN, -1, 0}, {"\nSIZE", COLOR_VIOLET, -1, 0}, @@ -30,7 +30,8 @@ menu_item explfilemenu[11] = { {"\nDelete file\n", COLOR_RED, DELETE, 1}, {"Launch Payload", COLOR_ORANGE, PAYLOAD, 1}, {"Launch Script", COLOR_YELLOW, SCRIPT, 1}, - {"View Hex", COLOR_GREEN, HEXVIEW, 1} + {"View Hex", COLOR_GREEN, HEXVIEW, 1}, + {"Extract Bis", COLOR_RED, DUMPBIS, 1} }; menu_item explfoldermenu[6] = { @@ -316,7 +317,12 @@ int filemenu(fs_entry file){ else explfilemenu[9].property = -1; - temp = makemenu(explfilemenu, 11); + if (strstr(file.name, ".bis") != NULL) + explfilemenu[11].property = 1; + else + explfilemenu[11].property = -1; + + temp = makemenu(explfilemenu, 12); switch (temp){ case COPY: @@ -337,6 +343,11 @@ int filemenu(fs_entry file){ case HEXVIEW: viewbytes(getnextloc(currentpath, file.name)); break; + case DUMPBIS: + clearscreen(); + extract_bis_file(getnextloc(currentpath, file.name), currentpath); + btn_wait(); + break; } return 0; diff --git a/source/tegraexplorer/fs.h b/source/tegraexplorer/fs.h index a3edb09..fa3b681 100644 --- a/source/tegraexplorer/fs.h +++ b/source/tegraexplorer/fs.h @@ -35,7 +35,8 @@ enum filemenuoptions { DELETE, PAYLOAD, SCRIPT, - HEXVIEW + HEXVIEW, + DUMPBIS }; enum foldermenuoptions { diff --git a/source/tegraexplorer/gfx.c b/source/tegraexplorer/gfx.c index 1753eca..1f241e5 100644 --- a/source/tegraexplorer/gfx.c +++ b/source/tegraexplorer/gfx.c @@ -38,7 +38,7 @@ void clearscreen(){ gfx_box(0, 0, 719, 15, COLOR_WHITE); gfx_con_setpos(0, 0); - gfx_printf("Tegraexplorer v1.3.2\n"); + gfx_printf("Tegraexplorer v1.3.3\n"); RESETCOLOR; } @@ -108,11 +108,17 @@ void printbytes(u8 print[], u32 size, u32 offset){ int makewaitmenu(char *initialmessage, char *hiddenmessage, int timer){ clearscreen(); + return makewaitmenunoclear(initialmessage, hiddenmessage, timer); +} + +int makewaitmenunoclear(char *initialmessage, char *hiddenmessage, int timer){ int res; u32 start = get_tmr_s(); gfx_printf(initialmessage); + while (btn_read() != 0); + while(1){ res = btn_read(); diff --git a/source/tegraexplorer/gfx.h b/source/tegraexplorer/gfx.h index c2e6ff7..064773c 100644 --- a/source/tegraexplorer/gfx.h +++ b/source/tegraexplorer/gfx.h @@ -1,6 +1,7 @@ #pragma once #include "te.h" #include "fs.h" +#include "../gfx/gfx.h" #define SWAPCOLOR(color) gfx_printf("%k", color) #define SWAPBGCOLOR(color) gfx_printf("%K", color) @@ -13,3 +14,4 @@ int makefilemenu(fs_entry *files, int amount, char *path); void printbytes(u8 print[], u32 size, u32 offset); int makewaitmenu(char *initialmessage, char *hiddenmessage, int timer); void gfx_print_length(int size, char *toprint); +int makewaitmenunoclear(char *initialmessage, char *hiddenmessage, int timer); \ No newline at end of file diff --git a/source/tegraexplorer/io.c b/source/tegraexplorer/io.c index d9add65..2391b29 100644 --- a/source/tegraexplorer/io.c +++ b/source/tegraexplorer/io.c @@ -13,6 +13,7 @@ #include "../storage/sdmmc.h" #include "../storage/nx_emmc.h" #include "../utils/types.h" +#include "../storage/emummc.h" extern sdmmc_storage_t storage; extern emmc_part_t *system_part; @@ -261,7 +262,7 @@ int copy_recursive(char *path, char *dstpath){ return 0; } -int dump_emmc_part(char *path, sdmmc_storage_t *storage, emmc_part_t *part){ +int dump_emmc_part(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){ FIL fp; u8 *buf; u32 lba_curr = part->lba_start; @@ -272,6 +273,7 @@ int dump_emmc_part(char *path, sdmmc_storage_t *storage, emmc_part_t *part){ u32 pct = 0; int res; + gfx_printf("Initializing\r"); buf = calloc(16384, sizeof(u8)); if ((res = f_open(&fp, path, FA_CREATE_ALWAYS | FA_WRITE))){ @@ -284,7 +286,7 @@ int dump_emmc_part(char *path, sdmmc_storage_t *storage, emmc_part_t *part){ while (totalSectors > 0){ num = MIN(totalSectors, 32); - if (!sdmmc_storage_read(storage, lba_curr, num, buf)){ + if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){ message(COLOR_RED, "eMMC read failed!"); return -1; } @@ -354,4 +356,231 @@ int dump_emmc_parts(u16 parts, u8 mmctype){ gfx_printf("\nDone!"); btn_wait(); return 0; +} + +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 ((res = f_stat(path, &fno))){ + message(COLOR_RED, "f_stat() failed! err: %d", res); + return -1; + } + + totalSize = fno.fsize; + u64 totalSectors = totalSize / NX_EMMC_BLOCKSIZE; + + if (totalSize > totalSizeDest){ + message(COLOR_RED, "File too big for destenation!"); + return -1; + } + + gfx_printf("Flashing %s\n", part->name); + + if (totalSize < totalSizeDest){ + SWAPCOLOR(COLOR_ORANGE); + u8 btnres = makewaitmenunoclear( + "File is too small for destenation.\nDo you want to flash it anyway?\n\nVol +/- to Cancel\n", + "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))){ + message(COLOR_RED, "f_open() failed! err: %d", res); + return -1; + } + + while (totalSectors > 0){ + num = MIN(totalSectors, 32); + + if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){ + message(COLOR_RED, "f_read() failed! err: %d", res); + return -1; + } + + if (!emummc_storage_write(mmcstorage, lba_curr, num, buf)){ + message(COLOR_RED, "eMMC write failed!"); + return -1; + } + + lba_curr += num; + totalSectors -= num; + bytesWritten += num * NX_EMMC_BLOCKSIZE; + + pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); + 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); + + sdmmc_storage_set_mmc_partition(&storage, partition); + restore_emmc_part(path, &storage, &bootPart); + } + else { + sdmmc_storage_set_mmc_partition(&storage, partition); + if (connect_part(target)){ + message(COLOR_RED, "Find of partition failed!\nPart: %s", target); + 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"); + clearscreen(); + + if (extract_bis_file(path, "sd:/tegraexplorer/bis")){ + message(COLOR_ORANGE, "Failed to find file!"); + return -1; + } + + if (!makewaitmenunoclear( + "\nAre you sure you want to flash these files\nThis could leave your switch unbootable!\n\nVol +/- to cancel\n", + "Power to confirm", + 5 + )) + { + return 0; + } + + 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; +} + +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; + } +} + +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))){ + message(COLOR_RED, "Opening file failed! err: %d", res); + 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); + + /* + for (int i = 0; i < 4; i++) { + gfx_printf("%d ", filesizes[i]); + } + */ + + gfx_printf("\nExtracting BOOT0\n"); + if (args & BOOT0_ARG) + gen_part(filesizes[0], &in, getnextloc(outfolder, "BOOT0.bin")); + + gfx_printf("Extracting BOOT1\n"); + if (args & BOOT1_ARG) + gen_part(filesizes[1], &in, getnextloc(outfolder, "BOOT1.bin")); + + gfx_printf("Extracting BCPKG2_1\n"); + if (args & BCPKG2_1_ARG) + gen_part(filesizes[2], &in, getnextloc(outfolder, "BCPKG2-1-Normal-Main")); + + gfx_printf("Extracting BCPKG2_3\n"); + if (args & BCPKG2_3_ARG) + gen_part(filesizes[3], &in, 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/io.h b/source/tegraexplorer/io.h index 539fd52..bc1b7cb 100644 --- a/source/tegraexplorer/io.h +++ b/source/tegraexplorer/io.h @@ -9,10 +9,17 @@ void makestring(char *in, char **out); int del_recursive(char *path); int copy_recursive(char *path, char *dstpath); int dump_emmc_parts(u16 parts, u8 mmctype); +int extract_bis_file(char *path, char *outfolder); +int restore_bis_using_file(char *path, u8 mmctype); #define PART_BOOT 0x1 #define PART_PKG2 0x2 +#define BOOT0_ARG 0x80 +#define BOOT1_ARG 0x40 +#define BCPKG2_1_ARG 0x20 +#define BCPKG2_3_ARG 0x10 + static const char *pkg2names[] = { "BCPKG2-1-Normal-Main", "BCPKG2-2-Normal-Sub", diff --git a/source/tegraexplorer/script.c b/source/tegraexplorer/script.c index 40aefd8..673f2f8 100644 --- a/source/tegraexplorer/script.c +++ b/source/tegraexplorer/script.c @@ -17,7 +17,7 @@ char func[11] = "", args[2][128] = {"", ""}; int res, errcode; -const int scriptver = 131; +const int scriptver = 133; bool forceExit = false; u32 currentcolor; diff --git a/source/tegraexplorer/te.c b/source/tegraexplorer/te.c index 4620313..b4d9d26 100644 --- a/source/tegraexplorer/te.c +++ b/source/tegraexplorer/te.c @@ -41,14 +41,15 @@ menu_item shutdownmenu[7] = { {"Reboot to Atmosphere", COLOR_GREEN, AMS, -1} }; -menu_item toolsmenu[7] = { +menu_item toolsmenu[8] = { {"-- TOOLS --\n", COLOR_VIOLET, -1, 0}, {"Back", COLOR_WHITE, -1, 1}, {"\nDisplay Console Info", COLOR_GREEN, DISPLAY_INFO, 1}, {"Display GPIO pins", COLOR_VIOLET, DISPLAY_GPIO, 1}, {"Dump Firmware", COLOR_BLUE, DUMPFIRMWARE, 1}, {"Dump User Saves", COLOR_YELLOW, DUMPUSERSAVE, 1}, - {"[DEBUG] Dump bis", COLOR_RED, DUMP_BOOT, 1} + {"[DEBUG] Dump bis", COLOR_RED, DUMP_BOOT, 1}, + {"[DEBUG] Restore bis", COLOR_RED, RESTORE_BOOT, 1} }; menu_item formatmenu[4] = { @@ -104,7 +105,7 @@ void MainMenu_MountSD(){ } void MainMenu_Tools(){ - res = makemenu(toolsmenu, 7); + res = makemenu(toolsmenu, 8); switch(res){ case DISPLAY_INFO: @@ -128,6 +129,22 @@ void MainMenu_Tools(){ case DUMP_BOOT: dump_emmc_parts(PART_BOOT | PART_PKG2, SYSMMC); break; + case RESTORE_BOOT: + SWAPCOLOR(COLOR_ORANGE); + if (makewaitmenu( + "WARNING!\nThis will mess with your switch boot files\nMake a nand backup beforehand!\n\nThis will pull from path:\nsd:/tegraexplorer/boot.bis\n\nVol +/- to cancel\n", + "Power to confirm", + 5 + )) + { + if (emu_cfg.enabled){ + if ((res = makemenu(mmcChoice, 3)) >= 0) + restore_bis_using_file("sd:/tegraexplorer/boot.bis", res); + } + else + restore_bis_using_file("sd:/tegraexplorer/boot.bis", SYSMMC); + } + break; } } diff --git a/source/tegraexplorer/te.h b/source/tegraexplorer/te.h index 92c972d..908a076 100644 --- a/source/tegraexplorer/te.h +++ b/source/tegraexplorer/te.h @@ -39,7 +39,8 @@ enum toolsmenu_return { DISPLAY_GPIO, DUMPFIRMWARE, DUMPUSERSAVE, - DUMP_BOOT + DUMP_BOOT, + RESTORE_BOOT }; enum formatmenu_return {