From 4b62b1f69fcf3c5468037a413f3c848cf367f9c3 Mon Sep 17 00:00:00 2001 From: CTCaer Date: Thu, 30 Apr 2020 16:12:55 +0300 Subject: [PATCH] nyx: Introducing Partition Manager for SD Card Allow you to select up to 2 emuMMC + Linux + Android. Any combo is allowed, even if you just want to repartition it back to one FAT partition. The procedure is automatic on selecting sizes and offsets. The tool is also able to backup your SD Card into Ramdisk and then get restored, if the total used size is less than 1GB. If you have more files than that, you will be asked to copy your files to your PC via UMS. It also allows you to flash L4T Linux images and Android Twrp images. The Flash Android can be also used to reboot into Twrp if a file to flash is not found. --- nyx/Makefile | 6 +- nyx/nyx_gui/frontend/gui_emummc_tools.c | 18 + nyx/nyx_gui/frontend/gui_tools.c | 16 + .../frontend/gui_tools_partition_manager.c | 2267 +++++++++++++++++ .../frontend/gui_tools_partition_manager.h | 22 + 5 files changed, 2326 insertions(+), 3 deletions(-) create mode 100644 nyx/nyx_gui/frontend/gui_tools_partition_manager.c create mode 100644 nyx/nyx_gui/frontend/gui_tools_partition_manager.h diff --git a/nyx/Makefile b/nyx/Makefile index 7420cb7..a41dcfd 100644 --- a/nyx/Makefile +++ b/nyx/Makefile @@ -24,7 +24,7 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ start.o exception_handlers.o \ nyx.o heap.o \ gfx.o \ - gui.o gui_info.o gui_tools.o gui_options.o gui_emmc_tools.o gui_emummc_tools.o \ + gui.o gui_info.o gui_tools.o gui_options.o gui_emmc_tools.o gui_emummc_tools.o gui_tools_partition_manager.o \ fe_emummc_tools.o fe_emmc_tools.o \ ) @@ -33,7 +33,7 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ bpmp.o clock.o cluster.o di.o gpio.o i2c.o irq.o pinmux.o se.o smmu.o tsec.o uart.o \ fuse.o kfuse.o \ mc.o sdram.o minerva.o ramdisk.o \ - sdmmc.o sdmmc_driver.o nx_emmc.o nx_sd.o \ + sdmmc.o sdmmc_driver.o nx_emmc.o nx_emmc_bis.o nx_sd.o \ bq24193.o max17050.o max7762x.o max77620-rtc.o regulator_5v.o \ touch.o joycon.o tmp451.o fan.o \ usbd.o usb_gadget_ums.o usb_gadget_hid.o \ @@ -56,7 +56,7 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ # Libraries. OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \ diskio.o ff.o ffunicode.o ffsystem.o \ - elfload.o elfreloc_arm.o \ + elfload.o elfreloc_arm.o blz.o \ lv_group.o lv_indev.o lv_obj.o lv_refr.o lv_style.o lv_vdb.o \ lv_draw.o lv_draw_rbasic.o lv_draw_vbasic.o lv_draw_arc.o lv_draw_img.o \ lv_draw_label.o lv_draw_line.o lv_draw_rect.o lv_draw_triangle.o \ diff --git a/nyx/nyx_gui/frontend/gui_emummc_tools.c b/nyx/nyx_gui/frontend/gui_emummc_tools.c index 465374e..8cafa8c 100644 --- a/nyx/nyx_gui/frontend/gui_emummc_tools.c +++ b/nyx/nyx_gui/frontend/gui_emummc_tools.c @@ -18,6 +18,8 @@ #include "gui.h" #include "fe_emummc_tools.h" +#include "gui_tools_partition_manager.h" +#include "../../../common/memory_map.h" #include "../config/ini.h" #include "../libs/fatfs/ff.h" #include "../mem/heap.h" @@ -144,6 +146,22 @@ static void _create_window_emummc() nyx_window_toggle_buttons(win, false); } +static lv_res_t _create_emummc_raw_format(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + // Create partition window. + if (!btn_idx) + create_window_partition_manager(btns); + + mbr_ctx.part_idx = 0; + mbr_ctx.sector_start = 0; + + return LV_RES_INV; +} static lv_res_t _create_emummc_raw_action(lv_obj_t * btns, const char * txt) { diff --git a/nyx/nyx_gui/frontend/gui_tools.c b/nyx/nyx_gui/frontend/gui_tools.c index c753a0e..7c91707 100644 --- a/nyx/nyx_gui/frontend/gui_tools.c +++ b/nyx/nyx_gui/frontend/gui_tools.c @@ -19,6 +19,7 @@ #include "gui.h" #include "gui_tools.h" +#include "gui_tools_partition_manager.h" #include "gui_emmc_tools.h" #include "fe_emummc_tools.h" #include "../../../common/memory_map.h" @@ -1611,6 +1612,21 @@ static void _create_tab_tools_arc_autorcm(lv_theme_t *th, lv_obj_t *parent) label_sep = lv_label_create(h2, NULL); lv_label_set_static_text(label_sep, ""); lv_obj_align(label_sep, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 11 / 7); + + // Create Partition SD Card button. + lv_obj_t *btn4 = lv_btn_create(h2, btn); + label_btn = lv_label_create(btn4, NULL); + lv_label_set_static_text(label_btn, SYMBOL_SD" Partition SD Card"); + lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, create_window_partition_manager); + + label_txt2 = lv_label_create(h2, NULL); + lv_label_set_recolor(label_txt2, true); + lv_label_set_static_text(label_txt2, + "Allows you to partition your SD Card for using it with #C7EA46 emuMMC#,\n" + "#C7EA46 Android# and #C7EA46 Linux#. You can also flash Linux and Android."); + lv_obj_set_style(label_txt2, &hint_small_style); + lv_obj_align(label_txt2, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); } void create_tab_tools(lv_theme_t *th, lv_obj_t *parent) diff --git a/nyx/nyx_gui/frontend/gui_tools_partition_manager.c b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c new file mode 100644 index 0000000..db85498 --- /dev/null +++ b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c @@ -0,0 +1,2267 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "gui.h" +#include "gui_tools.h" +#include "gui_tools_partition_manager.h" +#include "../libs/fatfs/diskio.h" +#include "../libs/lvgl/lvgl.h" +#include "../mem/heap.h" +#include "../sec/se.h" +#include "../soc/hw_init.h" +#include "../soc/pmc.h" +#include "../soc/t210.h" +#include "../storage/mbr_gpt.h" +#include "../storage/nx_emmc.h" +#include "../storage/nx_sd.h" +#include "../storage/ramdisk.h" +#include "../storage/sdmmc.h" +#include "../utils/btn.h" +#include "../utils/sprintf.h" +#include "../utils/util.h" + +extern volatile boot_cfg_t *b_cfg; +extern volatile nyx_storage_t *nyx_str; + +typedef struct _partition_ctxt_t +{ + u32 total_sct; + int backup_possible; + + s32 hos_size; + u32 emu_size; + u32 l4t_size; + u32 and_size; + + lv_obj_t *bar_hos; + lv_obj_t *bar_emu; + lv_obj_t *bar_l4t; + lv_obj_t *bar_and; + + lv_obj_t *sep_emu; + lv_obj_t *sep_l4t; + lv_obj_t *sep_and; + + lv_obj_t *slider_bar_hos; + lv_obj_t *slider_emu; + lv_obj_t *slider_l4t; + lv_obj_t *slider_and; + + lv_obj_t *lbl_hos; + lv_obj_t *lbl_emu; + lv_obj_t *lbl_l4t; + lv_obj_t *lbl_and; + + lv_obj_t *btn_partition; +} partition_ctxt_t; + +typedef struct _l4t_flasher_ctxt_t +{ + u32 offset_sct; + u32 image_size_sct; +} l4t_flasher_ctxt_t; + +partition_ctxt_t part_info; +l4t_flasher_ctxt_t l4t_flash_ctxt; + +static int _backup_and_restore_files(char *path, u32 *total_files, u32 *total_size, const char *dst, const char *src, lv_obj_t **labels) +{ + FRESULT res; + FIL fp_src; + FIL fp_dst; + DIR dir; + u32 dirLength = 0; + static FILINFO fno; + + if (src) + f_chdrive(src); + + // Open directory. + res = f_opendir(&dir, path); + if (res != FR_OK) + return res; + + if (labels) + lv_label_set_text(labels[0], path); + + dirLength = strlen(path); + for (;;) + { + // Clear file path. + path[dirLength] = 0; + + // Read a directory item. + res = f_readdir(&dir, &fno); + + // Break on error or end of dir. + if (res != FR_OK || fno.fname[0] == 0) + break; + + // Set new directory or file. + memcpy(&path[dirLength], "/", 1); + strcpy(&path[dirLength + 1], fno.fname); + + if (labels) + { + lv_label_set_text(labels[1], fno.fname); + manual_system_maintenance(true); + } + + // Copy file to destination disk. + if (!(fno.fattrib & AM_DIR)) + { + u32 file_size = fno.fsize > RAMDISK_CLUSTER_SZ ? fno.fsize : RAMDISK_CLUSTER_SZ; // Ramdisk cluster size. + *total_size += file_size; + *total_files += 1; + + if (src && dst) + { + u32 file_size = fno.fsize; + + // Open file for writing. + f_chdrive(dst); + f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE); + f_lseek(&fp_dst, fno.fsize); + f_lseek(&fp_dst, 0); + + // Open file for reading. + f_chdrive(src); + f_open(&fp_src, path, FA_READ); + + while (file_size) + { + u32 chunk_size = MIN(file_size, 0x400000); // 4MB chunks. + file_size -= chunk_size; + + // Copy file to buffer. + f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL); + manual_system_maintenance(true); + + // Write file to disk. + f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL); + } + f_close(&fp_src); + + // Finalize copied file. + f_close(&fp_dst); + f_chdrive(dst); + f_chmod(path, fno.fattrib, 0xFF); + + f_chdrive(src); + } + + // If total is > 1GB exit. + if (*total_size > (RAM_DISK_SZ - 0x1000000)) // 0x2400000. + break; + } + else // It's a directory. + { + if (!memcmp("System Volume Information", fno.fname, 25)) + continue; + + // Create folder to destination. + if (dst) + { + f_chdrive(dst); + f_mkdir(path); + } + // Enter the directory. + res = _backup_and_restore_files(path, total_files, total_size, dst, src, labels); + if (res != FR_OK) + break; + + if (labels) + { + // Clear folder path. + path[dirLength] = 0; + lv_label_set_text(labels[0], path); + } + } + } + + f_closedir(&dir); + + return res; +} + +static void _prepare_and_flash_mbr_gpt() +{ + u8 random_number[16]; + mbr_t mbr; + gpt_t gpt = { 0 }; + gpt_header_t gpt_hdr_backup = { 0 }; + + // Read current MBR. + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + // Clear the first 16MB. + memset((void *)SDMMC_UPPER_BUFFER, 0, 0x8000); + sdmmc_storage_write(&sd_storage, 0, 0x8000, (void *)SDMMC_UPPER_BUFFER); + + u8 mbr_idx = 1; + se_gen_prng128(random_number); + memcpy(&mbr.signature, random_number, 4); + + // Apply L4T Linux second to MBR if no Android. + if (part_info.l4t_size && !part_info.and_size) + { + mbr.partitions[mbr_idx].type = 0x83; // Linux system partition. + mbr.partitions[mbr_idx].start_sct = 0x8000 + (part_info.hos_size << 11); + mbr.partitions[mbr_idx].size_sct = part_info.l4t_size << 11; + mbr_idx++; + } + + // emuMMC goes second or third. Next to L4T if no Android. + bool double_emummc = part_info.emu_size > 29856; + if (part_info.emu_size) + { + mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition. + mbr.partitions[mbr_idx].start_sct = 0x8000 + (part_info.hos_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11); + + if (!double_emummc) + { + if (!part_info.and_size) + mbr.partitions[mbr_idx].size_sct = part_info.emu_size << 11; + else + mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 11) - 0x800; // Reserve 1MB. + } + else + { + mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition. + mbr.partitions[mbr_idx].size_sct = part_info.emu_size << 10; + mbr_idx++; + + // 2nd emuMMC. + mbr.partitions[mbr_idx].start_sct = mbr.partitions[mbr_idx - 1].start_sct + (part_info.emu_size << 10); + if (!part_info.and_size) + mbr.partitions[mbr_idx].size_sct = part_info.emu_size << 10; + else + mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 10) - 0x800; // Reserve 1MB. + } + mbr_idx++; + } + + if (part_info.and_size) + { + mbr.partitions[mbr_idx].type = 0xEE; // GPT protective partition. + mbr.partitions[mbr_idx].start_sct = 1; + mbr.partitions[mbr_idx].size_sct = part_info.total_sct - 1; + mbr_idx++; + + // Set GPT header. + memcpy(&gpt.header.signature, "EFI PART", 8); + gpt.header.revision = 0x10000; + gpt.header.size = 92; + gpt.header.my_lba = 1; + gpt.header.alt_lba = part_info.total_sct - 1; + gpt.header.first_use_lba = (sizeof(mbr_t) + sizeof(gpt_t)) >> 9; + gpt.header.last_use_lba = part_info.total_sct - 0x800 - 1; // part_info.total_sct - 33 is start of backup gpt partition entries. + se_gen_prng128(random_number); + memcpy(gpt.header.disk_guid, random_number, 10); + memcpy(gpt.header.disk_guid + 10, "NYXGPT", 6); + gpt.header.part_ent_lba = 2; + gpt.header.part_ent_size = 128; + + // Set GPT partitions. + u8 basic_part_guid[] = { 0xA2, 0xA0, 0xD0, 0xEB, 0xE5, 0xB9, 0x33, 0x44, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }; + memcpy(gpt.entries[0].type_guid, basic_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[0].part_guid, random_number, 16); + + // Clear non-standard Windows MBR attributes. bit4: Read only, bit5: Shadow copy, bit6: Hidden, bit7: No drive letter. + gpt.entries[0].part_guid[7] = 0; + + gpt.entries[0].lba_start = mbr.partitions[0].start_sct; + gpt.entries[0].lba_end = mbr.partitions[0].start_sct + mbr.partitions[0].size_sct - 1; + memcpy(gpt.entries[0].name, (char[]) { 'h', 0, 'o', 0, 's', 0, '_', 0, 'd', 0, 'a', 0, 't', 0, 'a', 0 }, 16); + + u8 gpt_idx = 1; + u32 curr_part_lba = 0x8000 + (part_info.hos_size << 11); + u8 android_part_guid[] = { 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 }; + if (part_info.l4t_size) + { + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + (part_info.l4t_size << 11) - 1; + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'l', 0, '4', 0, 't', 0 }, 6); + + curr_part_lba += (part_info.l4t_size << 11); + gpt_idx++; + } + + // Android Vendor partition. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + 0x200000 - 1; // 1GB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'v', 0, 'e', 0, 'n', 0, 'd', 0, 'o', 0, 'r', 0 }, 12); + curr_part_lba += 0x200000; + gpt_idx++; + + // Android System partition. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + 0x400000 - 1; // 2GB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'A', 0, 'P', 0, 'P', 0 }, 6); + curr_part_lba += 0x400000; + gpt_idx++; + + // Android Linux Kernel partition. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + 0x10000 - 1; // 32MB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6); + curr_part_lba += 0x10000; + gpt_idx++; + + // Android Recovery partition. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + 0x20000 - 1; // 64MB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6); + curr_part_lba += 0x20000; + gpt_idx++; + + // Android Device Tree Reference partition. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + 0x800 - 1; // 1MB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6); + curr_part_lba += 0x800; + gpt_idx++; + + // Android Encryption partition. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + 0x8000 - 1; // 16MB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'M', 0, 'D', 0, 'A', 0 }, 6); + curr_part_lba += 0x8000; + gpt_idx++; + + // Android Cache partition. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + 0x15E000 - 1; // 700MB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'C', 0, 'A', 0, 'C', 0 }, 6); + curr_part_lba += 0x15E000; + gpt_idx++; + + // Android Userdata partition. + u32 align_diff = ALIGN(curr_part_lba, 0x8000) - curr_part_lba; + curr_part_lba += align_diff; // Align to 16MB. + u32 user_size = (part_info.and_size << 11) - 0x796800 - align_diff; // Subtract the other partitions (3885MB). + if (!part_info.emu_size) + user_size -= 0x800; // Reserve 1MB. + memcpy(gpt.entries[gpt_idx].type_guid, android_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + user_size - 1; + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'U', 0, 'D', 0, 'A', 0 }, 6); + curr_part_lba += user_size; + gpt_idx++; + + if (part_info.emu_size) + { + u8 emu_part_guid[] = { 0x00, 0x7E, 0xCA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'e', 'm', 'u', 'M', 'M', 'C' }; + memcpy(gpt.entries[gpt_idx].type_guid, emu_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + if (!double_emummc) + gpt.entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 11) - 0x800 - 1; // Reserve 1MB. + else + gpt.entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10); // Reserve 1MB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'e', 0, 'm', 0, 'u', 0, 'm', 0, 'm', 0, 'c', 0 }, 12); + gpt_idx++; + + if (double_emummc) + { + curr_part_lba += (part_info.emu_size << 10); + memcpy(gpt.entries[gpt_idx].type_guid, emu_part_guid, 16); + se_gen_prng128(random_number); + memcpy(gpt.entries[gpt_idx].part_guid, random_number, 16); + gpt.entries[gpt_idx].lba_start = curr_part_lba; + gpt.entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 0x800 - 1; // Reserve 1MB. + memcpy(gpt.entries[gpt_idx].name, (char[]) { 'e', 0, 'm', 0, 'u', 0, 'm', 0, 'm', 0, 'c', 0, '2', 0 }, 14); + gpt_idx++; + } + } + + // Set final GPT header parameters. + gpt.header.num_part_ents = 128; + gpt.header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt.entries, sizeof(gpt_entry_t) * 128); + gpt.header.crc32 = 0; // Set to 0 for calculation. + gpt.header.crc32 = crc32_calc(0, (const u8 *)&gpt.header, gpt.header.size); + + memcpy(&gpt_hdr_backup, &gpt.header, sizeof(gpt_header_t)); + gpt_hdr_backup.my_lba = part_info.total_sct - 1; + gpt_hdr_backup.alt_lba = 1; + gpt_hdr_backup.part_ent_lba = part_info.total_sct - 33; + gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation. + gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size); + + // Write main GPT. + sdmmc_storage_write(&sd_storage, gpt.header.my_lba, sizeof(gpt_t) >> 9, &gpt); + + // Write backup GPT partition table. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt.entries); + + // Write backup GPT header. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup); + } + + // Write MBR. + sdmmc_storage_write(&sd_storage, 0, 1, &mbr); +} + +static lv_res_t _action_part_manager_ums_sd(lv_obj_t *btn) +{ + action_ums_sd(btn); + + if (lv_btn_get_state(part_info.btn_partition) != LV_BTN_STATE_INA) + { + lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK); + close_btn_action(close_btn); + lv_obj_del(ums_mbox); + create_window_partition_manager(NULL); + + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _action_delete_linux_installer_files(lv_obj_t * btns, const char * txt) +{ + + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + // Flash Linux. + if (!btn_idx) + { + char path[128]; + + sd_mount(); + + strcpy(path, "switchroot/install/l4t."); + + // Delete all l4t.xx files. + u32 idx = 0; + while (true) + { + if (idx < 10) + { + path[23] = '0'; + itoa(idx, &path[23 + 1], 10); + } + else + itoa(idx, &path[23], 10); + + if (!f_stat(path, NULL)) + { + f_unlink(path); + } + else + break; + + idx++; + } + + sd_unmount(false); + } + + return LV_RES_INV; +} + +static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + bool succeeded = false; + + // Flash Linux. + if (!btn_idx) + { + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "\211", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5); + + lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux..."); + + // Create container to keep content inside. + lv_obj_t *h1 = lv_cont_create(mbox, NULL); + lv_cont_set_fit(h1, true, true); + lv_cont_set_style(h1, &lv_style_transp_tight); + + lv_obj_t *bar = lv_bar_create(h1, NULL); + lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5); + lv_bar_set_range(bar, 0, 100); + lv_bar_set_value(bar, 0); + + lv_obj_t *label_pct = lv_label_create(h1, NULL); + lv_label_set_recolor(label_pct, true); + lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%"); + lv_label_set_style(label_pct, lv_theme_get_current()->label.prim); + lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + sd_mount(); + + int res = 0; + char *path = malloc(1024); + char *txt_buf = malloc(0x1000); + strcpy(path, "switchroot/install/l4t.00"); + u32 path_len = strlen(path) - 2; + + FIL fp; + + res = f_open(&fp, path, FA_READ); + if (res) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!"); + + goto exit; + } + + u64 fileSize = (u64)f_size(&fp); + + u32 num = 0; + u32 pct = 0; + u32 lba_curr = 0; + u32 bytesWritten = 0; + u32 currPartIdx = 0; + u32 prevPct = 200; + int retryCount = 0; + u32 total_size_sct = l4t_flash_ctxt.image_size_sct; + + u8 *buf = (u8 *)MIXD_BUF_ALIGNED; + DWORD *clmt = f_expand_cltbl(&fp, 0x400000, 0); + + while (total_size_sct > 0) + { + // If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that. + if (bytesWritten >= fileSize) + { + // If we have more bytes written then close the file pointer and increase the part index we are using + f_close(&fp); + free(clmt); + memset(&fp, 0, sizeof(fp)); + currPartIdx++; + + if (currPartIdx < 10) + { + path[path_len] = '0'; + itoa(currPartIdx, &path[path_len + 1], 10); + } + else + itoa(currPartIdx, &path[path_len], 10); + + // Try to open the next file part + res = f_open(&fp, path, FA_READ); + if (res) + { + s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx); + lv_label_set_text(lbl_status, txt_buf); + manual_system_maintenance(true); + + goto exit; + } + fileSize = (u64)f_size(&fp); + bytesWritten = 0; + clmt = f_expand_cltbl(&fp, 0x400000, 0); + } + + retryCount = 0; + num = MIN(total_size_sct, 8192); + + res = f_read_fast(&fp, buf, num << 9); + manual_system_maintenance(false); + + if (res) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!"); + manual_system_maintenance(true); + + f_close(&fp); + free(clmt); + goto exit; + } + res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf); + + manual_system_maintenance(false); + + while (res) + { + msleep(150); + manual_system_maintenance(true); + + if (retryCount >= 3) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!"); + manual_system_maintenance(true); + + f_close(&fp); + free(clmt); + goto exit; + } + + res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf); + manual_system_maintenance(false); + } + pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct; + if (pct != prevPct) + { + lv_bar_set_value(bar, pct); + s_printf(txt_buf, " "SYMBOL_DOT" %d%%", pct); + lv_label_set_text(label_pct, txt_buf); + manual_system_maintenance(true); + prevPct = pct; + } + + lba_curr += num; + total_size_sct -= num; + bytesWritten += num * NX_EMMC_BLOCKSIZE; + } + lv_bar_set_value(bar, 100); + lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%"); + manual_system_maintenance(true); + + // Restore operation ended successfully. + f_close(&fp); + free(clmt); + + succeeded = true; + +exit: + free(path); + free(txt_buf); + + if (!succeeded) + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + else + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + sd_unmount(false); + } + + return LV_RES_INV; +} + +static lv_res_t _action_check_flash_linux(lv_obj_t *btn) +{ + FILINFO fno; + char path[128]; + mbr_t mbr = { 0 }; + gpt_t gpt = { 0 }; + + memset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t)); + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + static const char *mbox_btn_map2[] = { "\222Continue", "\222Cancel", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions..."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + manual_system_maintenance(true); + + sd_mount(); + + strcpy(path, "switchroot/install/l4t.00"); + if (f_stat(path, NULL)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Installation files not found!"); + goto error; + } + + // Read MBR. + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + // Read main GPT. + sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, &gpt); + + // Search for a suitable partition. + u32 size_sct = 0; + if (!memcmp(&gpt.header.signature, "EFI PART", 8)) + { + for (u32 i = 0; i < gpt.header.num_part_ents; i++) + { + if (!memcmp(gpt.entries[i].name, (char[]) { 'l', 0, '4', 0, 't', 0 }, 6)) + { + l4t_flash_ctxt.offset_sct = gpt.entries[i].lba_start; + size_sct = (gpt.entries[i].lba_end + 1) - gpt.entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + } + else + { + for (u32 i = 1; i < 4; i++) + { + if (mbr.partitions[i].type == 0x83) + { + l4t_flash_ctxt.offset_sct = mbr.partitions[i].start_sct; + size_sct = mbr.partitions[i].size_sct; + break; + } + } + } + + if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# No partition found!"); + goto error; + } + + u32 idx = 0; + path[23] = 0; + while (true) + { + if (idx < 10) + { + path[23] = '0'; + itoa(idx, &path[23 + 1], 10); + } + else + itoa(idx, &path[23], 10); + + // Check for alignment. + if (!f_stat(path, &fno)) + { + if ((u64)fno.fsize % 0x400000) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!"); + goto error; + } + l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9; + } + else + break; + + idx++; + } + + if (l4t_flash_ctxt.image_size_sct > size_sct) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is bigger than the partition!"); + goto error; + } + + char *txt_buf = malloc(0x1000); + s_printf(txt_buf, + "#C7EA46 Status:# Found installation files and partition.\n" + "#00DDFF Offset:# %08x, #00DDFF Size:# %X, #00DDFF Image size:# %d MiB\n" + "\nDo you want to continue?", l4t_flash_ctxt.offset_sct, size_sct, l4t_flash_ctxt.image_size_sct >> 11); + lv_label_set_text(lbl_status, txt_buf); + free(txt_buf); + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_flash_linux_data); + goto exit; + +error: + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + +exit: + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + sd_unmount(false); + + return LV_RES_OK; +} + +static lv_res_t _action_reboot_twrp(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + if (!btn_idx) + { + PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY; + + b_cfg->boot_cfg = BOOT_CFG_FROM_ID | BOOT_CFG_AUTOBOOT_EN; + + strcpy((char *)b_cfg->id, "SWANDR"); + + void (*main_ptr)() = (void *)nyx_str->hekate; + + sd_unmount(true); + + reconfig_hw_workaround(false, 0); + + (*main_ptr)(); + } + + return LV_RES_INV; +} + +static lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + // Delete parent mbox. + mbox_action(btns, txt); + + // Flash Android components. + if (!btn_idx) + { + char path[128]; + gpt_t gpt = { 0 }; + char *txt_buf = malloc(0x1000); + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + static const char *mbox_btn_map2[] = { "\222Continue", "\222Cancel", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Android Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions..."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + manual_system_maintenance(true); + + sd_mount(); + + // Read main GPT. + sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, &gpt); + + bool boot_twrp = false; + if (memcmp(&gpt.header.signature, "EFI PART", 8)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!"); + goto error; + } + + strcpy(path, "switchroot/install/boot.img"); + if (!f_stat(path, NULL)) + { + u32 offset_sct = 0; + u32 size_sct = 0; + for (u32 i = 0; i < gpt.header.num_part_ents; i++) + { + if (!memcmp(gpt.entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6)) + { + offset_sct = gpt.entries[i].lba_start; + size_sct = (gpt.entries[i].lba_end + 1) - gpt.entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + + if (offset_sct && size_sct) + { + u32 file_size = 0; + u8 *buf = sd_file_read(path, &file_size); + + if (file_size % 0x200) + { + file_size = ALIGN(file_size, 0x200); + u8 *buf_tmp = calloc(file_size, 1); + memcpy(buf_tmp, buf, file_size); + free(buf); + buf = buf_tmp; + } + + if ((file_size >> 9) > size_sct) + s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n"); + else + { + sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf); + + s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n"); + f_unlink(path); + } + + free(buf); + } + else + s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n"); + } + else + s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n"); + + lv_label_set_text(lbl_status, txt_buf); + manual_system_maintenance(true); + + strcpy(path, "switchroot/install/twrp.img"); + if (!f_stat(path, NULL)) + { + u32 offset_sct = 0; + u32 size_sct = 0; + for (u32 i = 0; i < gpt.header.num_part_ents; i++) + { + if (!memcmp(gpt.entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6)) + { + offset_sct = gpt.entries[i].lba_start; + size_sct = (gpt.entries[i].lba_end + 1) - gpt.entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + + if (offset_sct && size_sct) + { + u32 file_size = 0; + u8 *buf = sd_file_read(path, &file_size); + + if (file_size % 0x200) + { + file_size = ALIGN(file_size, 0x200); + u8 *buf_tmp = calloc(file_size, 1); + memcpy(buf_tmp, buf, file_size); + free(buf); + buf = buf_tmp; + } + + if ((file_size >> 9) > size_sct) + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Warning:# TWRP image too big!\n"); + else + { + sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf); + s_printf(txt_buf + strlen(txt_buf), "#C7EA46 Success:# TWRP image flashed!\n"); + f_unlink(path); + } + + free(buf); + } + else + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Warning:# TWRP partition not found!\n"); + } + else + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Warning:# TWRP image not found!\n"); + + lv_label_set_text(lbl_status, txt_buf); + manual_system_maintenance(true); + + strcpy(path, "switchroot/install/tegra210-icosa.dtb"); + if (!f_stat(path, NULL)) + { + u32 offset_sct = 0; + u32 size_sct = 0; + for (u32 i = 0; i < gpt.header.num_part_ents; i++) + { + if (!memcmp(gpt.entries[i].name, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6)) + { + offset_sct = gpt.entries[i].lba_start; + size_sct = (gpt.entries[i].lba_end + 1) - gpt.entries[i].lba_start; + break; + } + + if (i > 126) + break; + } + + if (offset_sct && size_sct) + { + u32 file_size = 0; + u8 *buf = sd_file_read(path, &file_size); + + if (file_size % 0x200) + { + file_size = ALIGN(file_size, 0x200); + u8 *buf_tmp = calloc(file_size, 1); + memcpy(buf_tmp, buf, file_size); + free(buf); + buf = buf_tmp; + } + + if ((file_size >> 9) > size_sct) + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Warning:# DTB image too big!"); + else + { + sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf); + s_printf(txt_buf + strlen(txt_buf), "#C7EA46 Success:# DTB image flashed!"); + f_unlink(path); + } + + free(buf); + } + else + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Warning:# DTB partition not found!"); + } + else + s_printf(txt_buf + strlen(txt_buf), "#FF8000 Warning:# DTB image not found!"); + + lv_label_set_text(lbl_status, txt_buf); + + // Check if TWRP is flashed unconditionally. + for (u32 i = 0; i < gpt.header.num_part_ents; i++) + { + if (!memcmp(gpt.entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6)) + { + u8 *buf = malloc(512); + sdmmc_storage_read(&sd_storage, gpt.entries[i].lba_start, 1, buf); + if (!memcmp(buf, "ANDROID", 7)) + boot_twrp = true; + free(buf); + break; + } + + if (i > 126) + break; + } + +error: + if (boot_twrp) + { + s_printf(txt_buf + strlen(txt_buf),"\n\nDo you want to reboot into TWRP\nto finish Android installation?"); + lv_label_set_text(lbl_status, txt_buf); + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_twrp); + } + else + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + free(txt_buf); + + sd_unmount(false); + } + + return LV_RES_INV; +} + +static lv_res_t _action_flash_android(lv_obj_t *btn) +{ + memset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t)); + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Android Flasher#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_text(lbl_status, + "This will flash #C7EA46 Kernel#, #C7EA46 DTB# and #C7EA46 TWRP# if found.\n" + "Do you want to continue?"); + + lv_mbox_add_btns(mbox, mbox_btn_map, _action_flash_android_data); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +static lv_res_t _action_part_manager_flash_options0(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + lv_obj_del(ums_mbox); + break; + case 1: + _action_check_flash_linux(btns); + break; + case 2: + _action_flash_android(btns); + break; + case 3: + mbox_action(btns, txt); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _action_part_manager_flash_options1(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + lv_obj_del(ums_mbox); + break; + case 1: + mbox_action(btns, txt); + _action_check_flash_linux(NULL); + return LV_RES_INV; + case 2: + mbox_action(btns, txt); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _action_part_manager_flash_options2(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + lv_obj_del(ums_mbox); + break; + case 1: + mbox_action(btns, txt); + _action_flash_android(NULL); + return LV_RES_INV; + case 2: + mbox_action(btns, txt); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_start_partitioning(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + static const char *mbox_btn_map1[] = { "\222SD UMS", "\222Flash Linux", "\222Flash Android", "\221OK", "" }; + static const char *mbox_btn_map2[] = { "\222SD UMS", "\222Flash Linux", "\221OK", "" }; + static const char *mbox_btn_map3[] = { "\222SD UMS", "\222Flash Android", "\221OK", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "#FF8000 Partition Manager#"); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + bool buttons_set = false; + + if (!part_info.backup_possible) + { + char *txt_buf = malloc(0x1000); + strcpy(txt_buf, "#FF8000 Partition Manager#\n\nSafety wait ends in "); + lv_mbox_set_text(mbox, txt_buf); + + u32 seconds = 5; + u32 text_idx = strlen(txt_buf); + while (seconds) + { + s_printf(txt_buf + text_idx, "%d seconds...", seconds); + lv_mbox_set_text(mbox, txt_buf); + manual_system_maintenance(true); + msleep(1000); + seconds--; + } + + lv_mbox_set_text(mbox, + "#FF8000 Partition Manager#\n\n" + "#FFDD00 Warning: Do you really want to continue?!#\n\n" + "Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort."); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + + free(txt_buf); + + if (!(btn_wait() & BTN_POWER)) + goto exit; + } + + lv_mbox_set_text(mbox, "#FF8000 Partition Manager#"); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + + lv_obj_t *lbl_paths[2]; + + lbl_paths[0] = lv_label_create(mbox, NULL); + lv_label_set_text(lbl_paths[0], "/"); + lv_label_set_long_mode(lbl_paths[0], LV_LABEL_LONG_DOT); + lv_cont_set_fit(lbl_paths[0], false, true); + lv_obj_set_width(lbl_paths[0], (LV_HOR_RES / 9 * 6) - LV_DPI / 2); + lv_label_set_align(lbl_paths[0], LV_LABEL_ALIGN_CENTER); + lbl_paths[1] = lv_label_create(mbox, NULL); + lv_label_set_text(lbl_paths[1], " "); + lv_label_set_long_mode(lbl_paths[1], LV_LABEL_LONG_DOT); + lv_cont_set_fit(lbl_paths[1], false, true); + lv_obj_set_width(lbl_paths[1], (LV_HOR_RES / 9 * 6) - LV_DPI / 2); + lv_label_set_align(lbl_paths[1], LV_LABEL_ALIGN_CENTER); + + sd_mount(); + + FATFS ram_fs; + char *path = malloc(1024); + u32 total_files = 0; + u32 total_size = 0; + + lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing Ramdisk..."); + lv_label_set_text(lbl_paths[0], "Please wait..."); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + manual_system_maintenance(true); + if (ram_disk_init(&ram_fs)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to initialize Ramdisk!"); + goto error; + } + + if (!part_info.backup_possible) + { + strcpy(path, "bootloader"); + f_chdrive("ram:"); + f_mkdir(path); + } + else + path[0] = 0; + + lv_label_set_text(lbl_status, "#00DDFF Status:# Backing up files..."); + manual_system_maintenance(true); + if (_backup_and_restore_files(path, &total_files, &total_size, "ram:", "sd:", lbl_paths)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!"); + goto error; + } + total_files = 0; + total_size = 0; + + if (!part_info.backup_possible) + strcpy(path, "bootloader"); + else + path[0] = 0; + + f_mount(NULL, "sd:", 1); // Unmount SD card. + + lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting FAT32 partition..."); + lv_label_set_text(lbl_paths[0], "Please wait..."); + lv_label_set_text(lbl_paths[1], " "); + manual_system_maintenance(true); + + // Set reserved size. + u32 part_rsvd_size = (part_info.emu_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11); + disk_set_info(DRIVE_SD, SET_SECTOR_COUNT, &part_rsvd_size); + u8 *buf = malloc(0x400000); + + u32 cluster_size = part_info.hos_size < 2560 ? 4096 : 65536; + if (f_mkfs("sd:", FM_FAT32, cluster_size, buf, 0x400000)) + { + // Retry. + if (f_mkfs("sd:", FM_FAT32, cluster_size, buf, 0x400000)) + { + // Failed to format. + lv_label_set_text(lbl_status, + "#FFDD00 Error:# Failed to format disk!\n\n" + "Remove the SD card and check that is OK. If not, format it and press any key!"); + manual_system_maintenance(true); + + sd_unmount(true); + + while (!(btn_wait() & BTN_POWER)); + + sd_mount(); + + if (!part_info.backup_possible) + { + f_chdrive("sd:"); + f_mkdir(path); + } + + lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files..."); + manual_system_maintenance(true); + if (_backup_and_restore_files(path, &total_files, &total_size, "sd:", "ram:", NULL)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!"); + free(buf); + goto error; + } + lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!"); + f_mount(NULL, "ram:", 1); // Unmount ramdisk. + free(buf); + goto error; + } + } + free(buf); + + f_mount(&sd_fs, "sd:", 1); // Mount SD card. + + if (!part_info.backup_possible) + { + f_chdrive("sd:"); + f_mkdir(path); + } + + lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files..."); + manual_system_maintenance(true); + if (_backup_and_restore_files(path, &total_files, &total_size, "sd:", "ram:", lbl_paths)) + { + total_files = 0; + total_size = 0; + + if (!part_info.backup_possible) + { + strcpy(path, "bootloader"); + f_chdrive("sd:"); + f_mkdir(path); + } + else + path[0] = 0; + + if (_backup_and_restore_files(path, &total_files, &total_size, "sd:", "ram:", NULL)) + { + lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!"); + goto error; + } + } + + f_mount(NULL, "ram:", 1); // Unmount ramdisk. + f_chdrive("sd:"); + + // Set Volume label. + f_setlabel("0:SWITCH SD"); + + lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table..."); + lv_label_set_text(lbl_paths[0], "Please wait..."); + lv_label_set_text(lbl_paths[1], " "); + manual_system_maintenance(true); + _prepare_and_flash_mbr_gpt(); + + sd_unmount(false); + lv_label_set_text(lbl_status, "#00DDFF Status:# Done!"); + manual_system_maintenance(true); + + if (part_info.l4t_size && part_info.and_size) + lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0); + else if (part_info.l4t_size) + lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1); + else if (part_info.and_size) + lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2); + + if (part_info.l4t_size || part_info.and_size) + buttons_set = true; + + goto out; + +error: + f_chdrive("sd:"); + free(path); + +out: + lv_obj_del(lbl_paths[0]); + lv_obj_del(lbl_paths[1]); +exit: + if (!buttons_set) + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + // Disable partitioning button. + if (btn) + lv_btn_set_state(btn, LV_BTN_STATE_INA); + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_partitioning_option0(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + switch (btn_idx) + { + case 0: + action_ums_sd(btns); + return LV_RES_OK; + case 1: + mbox_action(btns, txt); + _create_mbox_start_partitioning(NULL); + break; + case 2: + mbox_action(btns, txt); + break; + } + + return LV_RES_INV; +} + +static lv_res_t _create_mbox_partitioning_option1(lv_obj_t *btns, const char *txt) +{ + int btn_idx = lv_btnm_get_pressed(btns); + + mbox_action(btns, txt); + + if (!btn_idx) + { + mbox_action(btns, txt); + _create_mbox_start_partitioning(NULL); + return LV_RES_INV; + } + + return LV_RES_OK; +} + +static lv_res_t _create_mbox_partitioning_next(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\222SD UMS", "\222Start", "\222Cancel", "" }; + static const char *mbox_btn_map2[] = { "\222Start", "\222Cancel", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + char *txt_buf = malloc(0x1000); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + lv_mbox_set_text(mbox, "#FF8000 Partition Manager#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + + s_printf(txt_buf, "#FFDD00 Warning: This will partition your SD Card!#\n\n"); + + if (part_info.backup_possible) + s_printf(txt_buf + strlen(txt_buf), "#C7EA46 Your files will be backed up and restored!#"); + else + s_printf(txt_buf + strlen(txt_buf), "#FFDD00 Your files will be wiped!#\n#FFDD00 Use USB UMS to copy them over!#"); + + lv_label_set_text(lbl_status, txt_buf); + + if (part_info.backup_possible) + lv_mbox_add_btns(mbox, mbox_btn_map2, _create_mbox_partitioning_option1); + else + lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_option0); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + free(txt_buf); + + return LV_RES_OK; +} + +static void _update_partition_bar() +{ + lv_obj_t *h1 = lv_obj_get_parent(part_info.bar_hos); + u32 total_size = (part_info.total_sct - 0x8000) / 0x200000; + u32 bar_hos_size = lv_obj_get_width(h1) * (part_info.hos_size >> 10) / total_size; + u32 bar_emu_size = lv_obj_get_width(h1) * (part_info.emu_size >> 10) / total_size; + u32 bar_l4t_size = lv_obj_get_width(h1) * (part_info.l4t_size >> 10) / total_size; + u32 bar_and_size = lv_obj_get_width(h1) * (part_info.and_size >> 10) / total_size; + + lv_obj_set_size(part_info.bar_hos, bar_hos_size, LV_DPI / 2); + lv_obj_set_size(part_info.bar_emu, bar_emu_size, LV_DPI / 2); + lv_obj_set_size(part_info.bar_l4t, bar_l4t_size, LV_DPI / 2); + lv_obj_set_size(part_info.bar_and, bar_and_size, LV_DPI / 2); + + lv_obj_align(part_info.bar_emu, part_info.bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + lv_obj_align(part_info.bar_l4t, part_info.bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + lv_obj_align(part_info.bar_and, part_info.bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + lv_obj_set_size(part_info.sep_emu, bar_emu_size ? 8 : 0, LV_DPI / 2); + lv_obj_align(part_info.sep_emu, part_info.bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + lv_obj_set_size(part_info.sep_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 2); + lv_obj_align(part_info.sep_l4t, part_info.bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + lv_obj_set_size(part_info.sep_and, bar_and_size ? 8 : 0, LV_DPI / 2); + lv_obj_align(part_info.sep_and, part_info.bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0); +} + +static lv_res_t _action_slider_emu(lv_obj_t *slider) +{ + char lbl_text[64]; + + int slide_val = lv_slider_get_value(slider); + u32 size = slide_val ? ((slide_val < 2) ? 29856 : 59712) : 0; + s32 hos_size = (part_info.total_sct >> 11) - 16 - size - part_info.l4t_size - part_info.and_size; + + if (hos_size > 2048) + { + part_info.emu_size = size; + part_info.hos_size = hos_size; + + s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10); + lv_label_set_text(part_info.lbl_hos, lbl_text); + lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10); + + if (slide_val < 2) + s_printf(lbl_text, "#FF3C28 %d GiB#", size >> 10); + else + s_printf(lbl_text, "#FF3C28 2x%d GiB#", size >> 11); + lv_label_set_text(part_info.lbl_emu, lbl_text); + } + else + lv_slider_set_value(slider, 0); + + _update_partition_bar(); + + return LV_RES_OK; +} + +static lv_res_t _action_slider_l4t(lv_obj_t *slider) +{ + char lbl_text[64]; + + u32 size = (u32)lv_slider_get_value(slider) << 10; + if (size < 4096) + size = 0; + else if (size < 8192) + size = 8192; + + s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - size - part_info.and_size; + + if (hos_size > 2048) + { + if (size <= 8192) + lv_slider_set_value(slider, size >> 10); + } + else + { + size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - 2048; + hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - size; + if (hos_size < 2048 || size < 8192) + { + lv_slider_set_value(slider, part_info.l4t_size >> 10); + goto out; + } + lv_slider_set_value(slider, size >> 10); + } + + part_info.l4t_size = size; + part_info.hos_size = hos_size; + + s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10); + lv_label_set_text(part_info.lbl_hos, lbl_text); + lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10); + s_printf(lbl_text, "#00DDFF %d GiB#", size >> 10); + lv_label_set_text(part_info.lbl_l4t, lbl_text); + + _update_partition_bar(); + +out: + return LV_RES_OK; +} + +static lv_res_t _action_slider_and(lv_obj_t *slider) +{ + char lbl_text[64]; + + u32 user_size = (u32)lv_slider_get_value(slider) << 10; + if (user_size < 2048) + user_size = 0; + else if (user_size < 4096) + user_size = 4096; + + u32 and_size = user_size ? (user_size + 4096) : 0; // Add Android reserved partitions size. + s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size; + + if (hos_size > 2048) + { + if (user_size <= 4096) + lv_slider_set_value(slider, user_size >> 10); + } + else + { + and_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - 2048; + hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size; + if (hos_size < 2048 || and_size < 8192) + { + lv_slider_set_value(slider, part_info.and_size >> 10); + goto out; + } + user_size = and_size - 4096; + lv_slider_set_value(slider, user_size >> 10); + } + + part_info.and_size = and_size; + part_info.hos_size = hos_size; + + s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10); + lv_label_set_text(part_info.lbl_hos, lbl_text); + lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10); + s_printf(lbl_text, "#FF8000 %d GiB#", user_size >> 10); + lv_label_set_text(part_info.lbl_and, lbl_text); + + _update_partition_bar(); + +out: + return LV_RES_OK; +} + +static void create_mbox_check_files_total_size() +{ + static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind; + static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg; + + lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic); + bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00); + bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color; + + lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic); + bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28); + bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color; + + lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic); + bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF); + bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color; + + lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic); + bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000); + bar_and_ind.body.grad_color = bar_and_ind.body.main_color; + + lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont); + sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28); + sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color; + sep_emu_bg.body.radius = 0; + lv_style_copy(&sep_l4t_bg, &sep_emu_bg); + sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF); + sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color; + lv_style_copy(&sep_and_bg, &sep_emu_bg); + sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000); + sep_and_bg.body.grad_color = sep_and_bg.body.main_color; + + char *txt_buf = malloc(0x2000); + + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + + lv_mbox_set_text(mbox, "Analyzing SD card usage. This might take a while..."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + manual_system_maintenance(true); + + char *path = malloc(1024); + u32 total_files = 0; + u32 total_size = 0; + path[0] = 0; + + // Check total size of files. + _backup_and_restore_files(path, &total_files, &total_size, NULL, NULL, NULL); + + // Not more than 1.0GB. + part_info.backup_possible = !(total_size > (RAM_DISK_SZ - 0x1000000)); // 0x2400000 + + if (part_info.backup_possible) + { + s_printf(txt_buf, + "#96FF00 Your SD Card files will be backed up automatically!#\n\n" + "#00DDFF Total files:# %d, #00DDFF Total size:# %d MiB", total_files, total_size >> 20); + lv_mbox_set_text(mbox, txt_buf); + } + else + { + lv_mbox_set_text(mbox, + "#FFDD00 Your SD Card cannot be backed up!#\n\n" + "You will be asked to back up your files later via UMS."); + } + + // Create container to keep content inside. + lv_obj_t *h1 = lv_cont_create(mbox, NULL); + lv_cont_set_fit(h1, false, true); + lv_cont_set_style(h1, &lv_style_transp_tight); + lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI * 3); + + lv_obj_t *lbl_part = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_part, true); + lv_label_set_text(lbl_part, "#00DDFF Current partition layout:#"); + + // Read current MBR. + mbr_t mbr = { 0 }; + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + total_size = (sd_storage.sec_cnt - 0x8000) / 0x200000; + u32 bar_hos_size = lv_obj_get_width(h1) * (mbr.partitions[0].size_sct / 0x200000) / total_size; + u32 bar_emu_size = 0; + for (u32 i = 1; i < 4; i++) + if (mbr.partitions[i].type == 0xE0) + bar_emu_size += mbr.partitions[i].size_sct; + bar_emu_size = lv_obj_get_width(h1) * (bar_emu_size / 0x200000) / total_size; + + u32 bar_l4t_size = 0; + for (u32 i = 1; i < 4; i++) + if (mbr.partitions[i].type == 0x83) + bar_l4t_size += mbr.partitions[i].size_sct; + bar_l4t_size = lv_obj_get_width(h1) * (bar_l4t_size / 0x200000) / total_size; + + u32 bar_and_size = lv_obj_get_width(h1) - bar_hos_size - bar_emu_size - bar_l4t_size; + + // Create bar objects. + lv_obj_t *bar_mbr_hos = lv_bar_create(h1, NULL); + lv_obj_set_size(bar_mbr_hos, bar_hos_size, LV_DPI / 3); + lv_bar_set_range(bar_mbr_hos, 0, 1); + lv_bar_set_value(bar_mbr_hos, 1); + lv_bar_set_style(bar_mbr_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind); + lv_obj_align(bar_mbr_hos, lbl_part, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6); + + lv_obj_t *bar_mbr_emu = lv_bar_create(h1, bar_mbr_hos); + lv_obj_set_size(bar_mbr_emu, bar_emu_size, LV_DPI / 3); + lv_bar_set_style(bar_mbr_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind); + lv_obj_align(bar_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + lv_obj_t *bar_mbr_l4t = lv_bar_create(h1, bar_mbr_hos); + lv_obj_set_size(bar_mbr_l4t, bar_l4t_size, LV_DPI / 3); + lv_bar_set_style(bar_mbr_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind); + lv_obj_align(bar_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + lv_obj_t *bar_mbr_rest = lv_bar_create(h1, bar_mbr_hos); + lv_obj_set_size(bar_mbr_rest, bar_and_size > 1 ? bar_and_size : 0, LV_DPI / 3); + lv_bar_set_style(bar_mbr_rest, LV_BAR_STYLE_INDIC, &bar_and_ind); + lv_obj_align(bar_mbr_rest, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + + // Create separator objects. + lv_obj_t *sep_mbr_emu = lv_cont_create(h1, NULL); + lv_obj_set_size(sep_mbr_emu, bar_emu_size ? 8 : 0, LV_DPI / 3); + lv_obj_set_style(sep_mbr_emu, &sep_emu_bg); + lv_obj_align(sep_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + lv_obj_t *sep_mbr_l4t = lv_cont_create(h1, sep_mbr_emu); + lv_obj_set_size(sep_mbr_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 3); + lv_obj_set_style(sep_mbr_l4t, &sep_l4t_bg); + lv_obj_align(sep_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + lv_obj_t *sep_mbr_rest = lv_cont_create(h1, sep_mbr_emu); + lv_obj_set_size(sep_mbr_rest, bar_and_size ? (bar_and_size > 1 ? 8 : 0) : 0, LV_DPI / 3); + lv_obj_set_style(sep_mbr_rest, &sep_and_bg); + lv_obj_align(sep_mbr_rest, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + + // Print partition table info. + s_printf(txt_buf, + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x", + mbr.partitions[0].type, mbr.partitions[0].start_sct, mbr.partitions[0].size_sct, + mbr.partitions[1].type, mbr.partitions[1].start_sct, mbr.partitions[1].size_sct, + mbr.partitions[2].type, mbr.partitions[2].start_sct, mbr.partitions[2].size_sct, + mbr.partitions[3].type, mbr.partitions[3].start_sct, mbr.partitions[3].size_sct); + + lv_obj_t *lbl_table = lv_label_create(h1, NULL); + lv_label_set_style(lbl_table, &monospace_text); + lv_label_set_text(lbl_table, txt_buf); + lv_obj_align(lbl_table, h1, LV_ALIGN_IN_TOP_MID, 0, LV_DPI); + + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + + free(txt_buf); + free(path); +} + +static lv_res_t _action_fix_mbr(lv_obj_t *btn) +{ + lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); + lv_obj_set_style(dark_bg, &mbox_darken); + lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES); + + static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; + lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL); + lv_mbox_set_recolor_text(mbox, true); + + lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); + lv_mbox_set_text(mbox, "#FF8000 Fix Hybrid MBR#"); + + lv_obj_t *lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + + if (!sd_mount()) + { + lv_label_set_text(lbl_status, "#FFDD00 Failed to init SD!#"); + goto out; + } + + mbr_t mbr[2] = { 0 }; + gpt_t gpt = { 0 }; + + sdmmc_storage_read(&sd_storage, 0, 1, &mbr[0]); + sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, &gpt); + + memcpy(&mbr[1], &mbr[0], sizeof(mbr_t)); + + sd_unmount(false); + + if (memcmp(&gpt.header.signature, "EFI PART", 8)) + { + lv_label_set_text(lbl_status, "#FFDD00 Warning:# No GPT was found!"); + goto out; + } + + // Parse GPT. + LIST_INIT(gpt_parsed); + for (u32 i = 0; i < gpt.header.num_part_ents; i++) + { + emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1); + + if (gpt.entries[i].lba_start < gpt.header.first_use_lba) + continue; + + part->index = i; + part->lba_start = gpt.entries[i].lba_start; + part->lba_end = gpt.entries[i].lba_end; + part->attrs = gpt.entries[i].attrs; + + // ASCII conversion. Copy only the LSByte of the UTF-16LE name. + for (u32 j = 0; j < 36; j++) + part->name[j] = gpt.entries[i].name[j]; + part->name[35] = 0; + + list_append(&gpt_parsed, &part->link); + } + + u32 mbr_idx = 0; + LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link) + { + if (!strcmp(part->name, "hos_data")) + { + mbr[1].partitions[mbr_idx].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC; + mbr[1].partitions[mbr_idx].start_sct = part->lba_start; + mbr[1].partitions[mbr_idx].size_sct = (part->lba_end - part->lba_start + 1); + mbr_idx++; + } + if (!strcmp(part->name, "emummc") || !strcmp(part->name, "emummc2")) + { + mbr[1].partitions[mbr_idx].type = 0xE0; + mbr[1].partitions[mbr_idx].start_sct = part->lba_start; + mbr[1].partitions[mbr_idx].size_sct = (part->lba_end - part->lba_start + 1); + mbr_idx++; + } + + if (mbr_idx > 2) + break; + } + + mbr[1].partitions[mbr_idx].type = 0xEE; // GPT protective partition. + mbr[1].partitions[mbr_idx].start_sct = 1; + mbr[1].partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1; + + // Check for differences. + bool changed = false; + for (u32 i = 1; i < 4; i++) + { + if ((mbr[0].partitions[i].type != mbr[1].partitions[i].type) || + (mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) || + (mbr[0].partitions[i].size_sct != mbr[1].partitions[i].size_sct)) + { + changed = true; + break; + } + } + + if (!changed) + { + lv_label_set_text(lbl_status, "#96FF00 Warning:# The Hybrid MBR needs no change!#"); + goto out; + } + + char *txt_buf = malloc(0x4000); + + s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n"); + s_printf(txt_buf + strlen(txt_buf), + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n", + mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct, + mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct, + mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct, + mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct); + + s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n"); + s_printf(txt_buf + strlen(txt_buf), + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x", + mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct, + mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct, + mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct, + mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct); + + lv_label_set_text(lbl_status, txt_buf); + lv_label_set_style(lbl_status, &monospace_text); + + free(txt_buf); + + lbl_status = lv_label_create(mbox, NULL); + lv_label_set_recolor(lbl_status, true); + lv_label_set_align(lbl_status, LV_LABEL_ALIGN_CENTER); + + lv_label_set_text(lbl_status, + "#FF8000 Warning: Do you really want to continue?!#\n\n" + "Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort."); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + manual_system_maintenance(true); + + if (btn_wait() & BTN_POWER) + { + // Write MBR. + sd_mount(); + sdmmc_storage_write(&sd_storage, 0, 1, &mbr[1]); + sd_unmount(false); + lv_label_set_text(lbl_status, "#96FF00 The new Hybrid MBR was written successfully!#"); + } + else + lv_label_set_text(lbl_status, "#FFDD00 Warning: The Hybrid MBR Fix was canceled!#"); + +out: + lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); + + lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_top(mbox, true); + + return LV_RES_OK; +} + +lv_res_t create_window_partition_manager(lv_obj_t *btn) +{ + lv_obj_t *win = nyx_create_standard_window(SYMBOL_SD" Partition Manager"); + + lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR", _action_fix_mbr); + + static lv_style_t bar_hos_bg, bar_emu_bg, bar_l4t_bg, bar_and_bg; + static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind; + static lv_style_t bar_hos_btn, bar_emu_btn, bar_l4t_btn, bar_and_btn; + static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg; + + lv_style_copy(&bar_hos_bg, lv_theme_get_current()->bar.bg); + bar_hos_bg.body.main_color = LV_COLOR_HEX(0x4A8000); + bar_hos_bg.body.grad_color = bar_hos_bg.body.main_color; + lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic); + bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00); + bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color; + lv_style_copy(&bar_hos_btn, lv_theme_get_current()->slider.knob); + bar_hos_btn.body.main_color = LV_COLOR_HEX(0x77CC00); + bar_hos_btn.body.grad_color = bar_hos_btn.body.main_color; + + lv_style_copy(&bar_emu_bg, lv_theme_get_current()->bar.bg); + bar_emu_bg.body.main_color = LV_COLOR_HEX(0x940F00); + bar_emu_bg.body.grad_color = bar_emu_bg.body.main_color; + lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic); + bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28); + bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color; + lv_style_copy(&bar_emu_btn, lv_theme_get_current()->slider.knob); + bar_emu_btn.body.main_color = LV_COLOR_HEX(0xB31200); + bar_emu_btn.body.grad_color = bar_emu_btn.body.main_color; + lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont); + sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28); + sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color; + sep_emu_bg.body.radius = 0; + + lv_style_copy(&bar_l4t_bg, lv_theme_get_current()->bar.bg); + bar_l4t_bg.body.main_color = LV_COLOR_HEX(0x006E80); + bar_l4t_bg.body.grad_color = bar_l4t_bg.body.main_color; + lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic); + bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF); + bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color; + lv_style_copy(&bar_l4t_btn, lv_theme_get_current()->slider.knob); + bar_l4t_btn.body.main_color = LV_COLOR_HEX(0x00B1CC); + bar_l4t_btn.body.grad_color = bar_l4t_btn.body.main_color; + lv_style_copy(&sep_l4t_bg, &sep_emu_bg); + sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF); + sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color; + + lv_style_copy(&bar_and_bg, lv_theme_get_current()->bar.bg); + bar_and_bg.body.main_color = LV_COLOR_HEX(0x804000); + bar_and_bg.body.grad_color = bar_and_bg.body.main_color; + lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic); + bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000); + bar_and_ind.body.grad_color = bar_and_ind.body.main_color; + lv_style_copy(&bar_and_btn, lv_theme_get_current()->slider.knob); + bar_and_btn.body.main_color = LV_COLOR_HEX(0xCC6600); + bar_and_btn.body.grad_color = bar_and_btn.body.main_color; + lv_style_copy(&sep_and_bg, &sep_emu_bg); + sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000); + sep_and_bg.body.grad_color = sep_and_bg.body.main_color; + + lv_obj_t *sep = lv_label_create(win, NULL); + lv_label_set_static_text(sep, ""); + lv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); + + // Create container to keep content inside. + lv_obj_t *h1 = lv_cont_create(win, NULL); + lv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES - LV_DPI); + + if (!sd_mount()) + { + lv_obj_t *lbl = lv_label_create(h1, NULL); + lv_label_set_text(lbl, "#FFDD00 Failed to init SD!#"); + return LV_RES_OK; + } + + memset(&part_info, 0, sizeof(partition_ctxt_t)); + create_mbox_check_files_total_size(); + + char *txt_buf = malloc(0x2000); + + part_info.total_sct = sd_storage.sec_cnt; + u32 extra_sct = 0x8000 + 0x400000; // Reserved 16MB alignment for FAT partition + 2GB. + + // Read current MBR. + mbr_t mbr = { 0 }; + sdmmc_storage_read(&sd_storage, 0, 1, &mbr); + + u32 bar_hos_size = lv_obj_get_width(h1); + u32 bar_emu_size = 0; + u32 bar_l4t_size = 0; + u32 bar_and_size = 0; + + lv_obj_t *lbl = lv_label_create(h1, NULL); + lv_label_set_text(lbl, "New partition layout:"); + + lv_obj_t *bar_hos = lv_bar_create(h1, NULL); + lv_obj_set_size(bar_hos, bar_hos_size, LV_DPI / 2); + lv_bar_set_range(bar_hos, 0, 1); + lv_bar_set_value(bar_hos, 1); + lv_bar_set_style(bar_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind); + lv_obj_align(bar_hos, lbl, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6); + part_info.bar_hos = bar_hos; + + lv_obj_t *bar_emu = lv_bar_create(h1, bar_hos); + lv_obj_set_size(bar_emu, bar_emu_size, LV_DPI / 2); + lv_bar_set_style(bar_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind); + lv_obj_align(bar_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + part_info.bar_emu = bar_emu; + + lv_obj_t *bar_l4t = lv_bar_create(h1, bar_hos); + lv_obj_set_size(bar_l4t, bar_l4t_size, LV_DPI / 2); + lv_bar_set_style(bar_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind); + lv_obj_align(bar_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + part_info.bar_l4t = bar_l4t; + + lv_obj_t *bar_and = lv_bar_create(h1, bar_hos); + lv_obj_set_size(bar_and, bar_and_size, LV_DPI / 2); + lv_bar_set_style(bar_and, LV_BAR_STYLE_INDIC, &bar_and_ind); + lv_obj_align(bar_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0); + part_info.bar_and = bar_and; + + lv_obj_t *sep_emu = lv_cont_create(h1, NULL); + lv_cont_set_fit(sep_emu, false, false); + lv_obj_set_size(sep_emu, 0, LV_DPI / 2); // 8. + lv_obj_set_style(sep_emu, &sep_emu_bg); + lv_obj_align(sep_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + part_info.sep_emu = sep_emu; + + lv_obj_t *sep_l4t = lv_cont_create(h1, sep_emu); + lv_obj_set_style(sep_l4t, &sep_l4t_bg); + lv_obj_align(sep_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + part_info.sep_l4t = sep_l4t; + + lv_obj_t *sep_and = lv_cont_create(h1, sep_emu); + lv_obj_set_style(sep_and, &sep_and_bg); + lv_obj_align(sep_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0); + part_info.sep_and = sep_and; + + lv_obj_t *lbl_hos = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_hos, true); + lv_label_set_static_text(lbl_hos, "#96FF00 "SYMBOL_DOT" HOS (FAT32):#"); + lv_obj_align(lbl_hos, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2); + + lv_obj_t *lbl_emu = lv_label_create(h1, lbl_hos); + lv_label_set_static_text(lbl_emu, "#FF3C28 "SYMBOL_DOT" emuMMC (RAW):#"); + lv_obj_align(lbl_emu, lbl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + lv_obj_t *lbl_l4t = lv_label_create(h1, lbl_hos); + lv_label_set_static_text(lbl_l4t, "#00DDFF "SYMBOL_DOT" Linux (EXT4):#"); + lv_obj_align(lbl_l4t, lbl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + lv_obj_t *lbl_and = lv_label_create(h1, lbl_hos); + lv_label_set_static_text(lbl_and, "#FF8000 "SYMBOL_DOT" Android (USER):#"); + lv_obj_align(lbl_and, lbl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + + lv_obj_t *slider_bar_hos = lv_bar_create(h1, NULL); + lv_obj_set_size(slider_bar_hos, LV_DPI * 7, LV_DPI * 3 / 17); + lv_bar_set_range(slider_bar_hos, 0, (part_info.total_sct - 0x8000) / 0x200000); + lv_bar_set_value(slider_bar_hos, (part_info.total_sct - 0x8000) / 0x200000); + lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_BG, &bar_hos_bg); + lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_INDIC, &bar_hos_ind); + lv_obj_align(slider_bar_hos, lbl_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 6 / 4, 0); + part_info.slider_bar_hos = slider_bar_hos; + + lv_obj_t *slider_emu = lv_slider_create(h1, NULL); + lv_obj_set_size(slider_emu, LV_DPI * 7, LV_DPI / 3); + lv_slider_set_range(slider_emu, 0, 2); + lv_slider_set_value(slider_emu, 0); + lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_BG, &bar_emu_bg); + lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_INDIC, &bar_emu_ind); + lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_KNOB, &bar_emu_btn); + lv_obj_align(slider_emu, slider_bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 + 5); + lv_slider_set_action(slider_emu, _action_slider_emu); + part_info.slider_emu = slider_bar_hos; + + lv_obj_t *slider_l4t = lv_slider_create(h1, NULL); + lv_obj_set_size(slider_l4t, LV_DPI * 7, LV_DPI / 3); + lv_slider_set_range(slider_l4t, 0, (part_info.total_sct - extra_sct) / 0x200000); + lv_slider_set_value(slider_l4t, 0); + lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_BG, &bar_l4t_bg); + lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_INDIC, &bar_l4t_ind); + lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_KNOB, &bar_l4t_btn); + lv_obj_align(slider_l4t, slider_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3); + lv_slider_set_action(slider_l4t, _action_slider_l4t); + part_info.slider_l4t = slider_l4t; + + lv_obj_t *slider_and = lv_slider_create(h1, NULL); + lv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3); + lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / 0x200000 - 4); // Subtract android reserved size. + lv_slider_set_value(slider_and, 0); + lv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg); + lv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind); + lv_slider_set_style(slider_and, LV_SLIDER_STYLE_KNOB, &bar_and_btn); + lv_obj_align(slider_and, slider_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3); + lv_slider_set_action(slider_and, _action_slider_and); + part_info.slider_and = slider_and; + + lv_obj_t *lbl_sl_hos = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_sl_hos, true); + s_printf(txt_buf, "#96FF00 %d GiB#", (part_info.total_sct - 0x8000) >> 11 >> 10); + lv_label_set_text(lbl_sl_hos, txt_buf); + lv_obj_align(lbl_sl_hos, slider_bar_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 4 / 7, 0); + part_info.lbl_hos = lbl_sl_hos; + + lv_obj_t *lbl_sl_emu = lv_label_create(h1, lbl_sl_hos); + lv_label_set_text(lbl_sl_emu, "#FF3C28 0 GiB#"); + lv_obj_align(lbl_sl_emu, lbl_sl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + part_info.lbl_emu = lbl_sl_emu; + + lv_obj_t *lbl_sl_l4t = lv_label_create(h1, lbl_sl_hos); + lv_label_set_text(lbl_sl_l4t, "#00DDFF 0 GiB#"); + lv_obj_align(lbl_sl_l4t, lbl_sl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + part_info.lbl_l4t = lbl_sl_l4t; + + lv_obj_t *lbl_sl_and = lv_label_create(h1, lbl_sl_hos); + lv_label_set_text(lbl_sl_and, "#FF8000 0 GiB#"); + lv_obj_align(lbl_sl_and, lbl_sl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3); + part_info.lbl_and = lbl_sl_and; + + lv_obj_t *lbl_notes = lv_label_create(h1, NULL); + lv_label_set_recolor(lbl_notes, true); + lv_label_set_static_text(lbl_notes, + "Note 1: Only up to #C7EA46 1GB# can be backed up. If more, you will be asked to back them manually at the next step.\n" + "Note 2: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# work independently and will flash files if suitable partitions and installer files are found.\n" + "Note 3: The installation files reside in #C7EA46 switchroot/install# folder. Linux uses #C7EA46 l4t.XX# and Android uses #C7EA46 twrp.img# and #C7EA46 tegra210-icosa.dtb#.\n" + "Note 4: #FFDD00 The installation files will be deleted after a successful flashing.#"); + lv_label_set_style(lbl_notes, &hint_small_style); + lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5); + + lv_obj_t *btn1 = lv_btn_create(h1, NULL); + lv_obj_t *label_btn = lv_label_create(btn1, NULL); + lv_btn_set_fit(btn1, true, true); + lv_label_set_static_text(label_btn, SYMBOL_USB" SD UMS"); + lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5); + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_part_manager_ums_sd); + + lv_obj_t *btn2 = lv_btn_create(h1, NULL); + lv_obj_t *label_btn2 = lv_label_create(btn2, NULL); + lv_btn_set_fit(btn2, true, true); + lv_label_set_static_text(label_btn2, SYMBOL_DOWNLOAD" Flash Linux"); + lv_obj_align(btn2, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0); + lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _action_check_flash_linux); + + btn1 = lv_btn_create(h1, NULL); + label_btn = lv_label_create(btn1, NULL); + lv_btn_set_fit(btn1, true, true); + lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android"); + lv_obj_align(btn1, btn2, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0); + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_flash_android); + + btn1 = lv_btn_create(h1, NULL); + label_btn = lv_label_create(btn1, NULL); + lv_btn_set_fit(btn1, true, true); + lv_label_set_static_text(label_btn, SYMBOL_SD" Next Step"); + lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_RIGHT, 0, LV_DPI * 5); + lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _create_mbox_partitioning_next); + part_info.btn_partition = btn1; + + free(txt_buf); + + sd_unmount(false); + + return LV_RES_OK; +} diff --git a/nyx/nyx_gui/frontend/gui_tools_partition_manager.h b/nyx/nyx_gui/frontend/gui_tools_partition_manager.h new file mode 100644 index 0000000..005016a --- /dev/null +++ b/nyx/nyx_gui/frontend/gui_tools_partition_manager.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2019-2020 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _GUI_TOOLS_PART_MANAGER_H_ +#define _GUI_TOOLS_PART_MANAGER_H_ + +lv_res_t create_window_partition_manager(lv_obj_t *btn); + +#endif