Path: blob/master/nyx/nyx_gui/frontend/gui_tools_partition_manager.c
1476 views
/*1* Copyright (c) 2019-2024 CTCaer2*3* This program is free software; you can redistribute it and/or modify it4* under the terms and conditions of the GNU General Public License,5* version 2, as published by the Free Software Foundation.6*7* This program is distributed in the hope it will be useful, but WITHOUT8* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or9* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for10* more details.11*12* You should have received a copy of the GNU General Public License13* along with this program. If not, see <http://www.gnu.org/licenses/>.14*/1516#include <stdlib.h>1718#include <bdk.h>1920#include "gui.h"21#include "gui_tools.h"22#include "gui_tools_partition_manager.h"23#include <libs/fatfs/diskio.h>24#include <libs/lvgl/lvgl.h>2526#define AU_ALIGN_SECTORS 0x8000 // 16MB.27#define AU_ALIGN_BYTES (AU_ALIGN_SECTORS * SD_BLOCKSIZE)2829#define SECTORS_PER_GB 0x2000003031#define HOS_MIN_SIZE_MB 204832#define ANDROID_SYSTEM_SIZE_MB 6144 // 6 GB. Fits both Legacy (4912MB) and Dynamic (6144MB) partition schemes.3334extern volatile boot_cfg_t *b_cfg;35extern volatile nyx_storage_t *nyx_str;3637typedef struct _partition_ctxt_t38{39u32 total_sct;40u32 alignment;41int backup_possible;4243s32 hos_size;44u32 emu_size;45u32 l4t_size;46u32 and_size;4748bool emu_double;49bool emmc_is_64gb;5051bool and_dynamic;5253mbr_t mbr_old;5455lv_obj_t *bar_hos;56lv_obj_t *bar_emu;57lv_obj_t *bar_l4t;58lv_obj_t *bar_and;5960lv_obj_t *sep_emu;61lv_obj_t *sep_l4t;62lv_obj_t *sep_and;6364lv_obj_t *slider_bar_hos;65lv_obj_t *slider_emu;66lv_obj_t *slider_l4t;67lv_obj_t *slider_and;6869lv_obj_t *lbl_hos;70lv_obj_t *lbl_emu;71lv_obj_t *lbl_l4t;72lv_obj_t *lbl_and;73} partition_ctxt_t;7475typedef struct _l4t_flasher_ctxt_t76{77u32 offset_sct;78u32 image_size_sct;79} l4t_flasher_ctxt_t;8081partition_ctxt_t part_info;82l4t_flasher_ctxt_t l4t_flash_ctxt;8384lv_obj_t *btn_flash_l4t;85lv_obj_t *btn_flash_android;8687int _copy_file(const char *src, const char *dst, const char *path)88{89FIL fp_src;90FIL fp_dst;91int res;9293// Open file for reading.94f_chdrive(src);95res = f_open(&fp_src, path, FA_READ);96if (res != FR_OK)97return res;9899u32 file_bytes_left = f_size(&fp_src);100101// Open file for writing.102f_chdrive(dst);103f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);104f_lseek(&fp_dst, f_size(&fp_src));105f_lseek(&fp_dst, 0);106107while (file_bytes_left)108{109u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.110file_bytes_left -= chunk_size;111112// Copy file to buffer.113f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);114115// Write file to disk.116f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);117}118119f_close(&fp_dst);120f_chdrive(src);121f_close(&fp_src);122123return FR_OK;124}125126static int _stat_and_copy_files(const char *src, const char *dst, char *path, u32 *total_files, u32 *total_size, lv_obj_t **labels)127{128FRESULT res;129FIL fp_src;130FIL fp_dst;131DIR dir;132u32 dirLength = 0;133static FILINFO fno;134135f_chdrive(src);136137// Open directory.138res = f_opendir(&dir, path);139if (res != FR_OK)140return res;141142if (labels)143lv_label_set_text(labels[0], path);144145dirLength = strlen(path);146147// Hard limit path to 1024 characters. Do not result to error.148if (dirLength > 1024)149goto out;150151for (;;)152{153// Clear file path.154path[dirLength] = 0;155156// Read a directory item.157res = f_readdir(&dir, &fno);158159// Break on error or end of dir.160if (res != FR_OK || fno.fname[0] == 0)161break;162163// Set new directory or file.164memcpy(&path[dirLength], "/", 1);165strcpy(&path[dirLength + 1], fno.fname);166167if (labels)168{169lv_label_set_text(labels[1], fno.fname);170manual_system_maintenance(true);171}172173// Copy file to destination disk.174if (!(fno.fattrib & AM_DIR))175{176u32 file_size = fno.fsize > RAMDISK_CLUSTER_SZ ? fno.fsize : RAMDISK_CLUSTER_SZ; // Ramdisk cluster size.177178// Check for overflow.179if ((file_size + *total_size) < *total_size)180{181// Set size to > 1GB, skip next folders and return.182*total_size = SZ_2G;183res = -1;184break;185}186187*total_size += file_size;188*total_files += 1;189190if (dst)191{192u32 file_bytes_left = fno.fsize;193194// Open file for writing.195f_chdrive(dst);196f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);197f_lseek(&fp_dst, fno.fsize);198f_lseek(&fp_dst, 0);199200// Open file for reading.201f_chdrive(src);202f_open(&fp_src, path, FA_READ);203204while (file_bytes_left)205{206u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.207file_bytes_left -= chunk_size;208209// Copy file to buffer.210f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);211manual_system_maintenance(true);212213// Write file to disk.214f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);215}216217// Finalize copied file.218f_close(&fp_dst);219f_chdrive(dst);220f_chmod(path, fno.fattrib, 0xFF);221222f_chdrive(src);223f_close(&fp_src);224}225226// If total is > 1GB exit.227if (*total_size > (RAM_DISK_SZ - SZ_16M)) // 0x2400000.228{229// Skip next folders and return.230res = -1;231break;232}233}234else // It's a directory.235{236if (!memcmp("System Volume Information", fno.fname, 25))237continue;238239// Create folder to destination.240if (dst)241{242f_chdrive(dst);243f_mkdir(path);244f_chmod(path, fno.fattrib, 0xFF);245}246247// Enter the directory.248res = _stat_and_copy_files(src, dst, path, total_files, total_size, labels);249if (res != FR_OK)250break;251252if (labels)253{254// Clear folder path.255path[dirLength] = 0;256lv_label_set_text(labels[0], path);257}258}259}260261out:262f_closedir(&dir);263264return res;265}266267static void _create_gpt_partition(gpt_t *gpt, u8 *gpt_idx, u32 *curr_part_lba, u32 size_lba, const char *name, int name_size)268{269static const u8 linux_part_guid[] = { 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 };270u8 random_number[16];271272// Create GPT partition.273memcpy(gpt->entries[*gpt_idx].type_guid, linux_part_guid, 16);274275// Set randomly created GUID276se_gen_prng128(random_number);277memcpy(gpt->entries[*gpt_idx].part_guid, random_number, 16);278279// Set partition start and end.280gpt->entries[*gpt_idx].lba_start = *curr_part_lba;281gpt->entries[*gpt_idx].lba_end = *curr_part_lba + size_lba - 1;282283// Set name.284memcpy(gpt->entries[*gpt_idx].name, name, name_size);285286// Wipe the first 1MB to sanitize it as raw-empty partition.287sdmmc_storage_write(&sd_storage, *curr_part_lba, 0x800, (void *)SDMMC_UPPER_BUFFER);288289// Prepare for next.290(*curr_part_lba) += size_lba;291(*gpt_idx)++;292}293294static void _prepare_and_flash_mbr_gpt()295{296mbr_t mbr;297u8 random_number[16];298299// Read current MBR.300sdmmc_storage_read(&sd_storage, 0, 1, &mbr);301302// Copy over metadata if they exist.303if (*(u32 *)&part_info.mbr_old.bootstrap[0x80])304memcpy(&mbr.bootstrap[0x80], &part_info.mbr_old.bootstrap[0x80], 304);305306// Clear the first 16MB.307memset((void *)SDMMC_UPPER_BUFFER, 0, AU_ALIGN_BYTES);308sdmmc_storage_write(&sd_storage, 0, AU_ALIGN_SECTORS, (void *)SDMMC_UPPER_BUFFER);309310u8 mbr_idx = 1;311se_gen_prng128(random_number);312memcpy(&mbr.signature, random_number, 4);313314// Apply L4T Linux second to MBR if no Android.315if (part_info.l4t_size && !part_info.and_size)316{317mbr.partitions[mbr_idx].type = 0x83; // Linux system partition.318mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);319mbr.partitions[mbr_idx].size_sct = part_info.l4t_size << 11;320sdmmc_storage_write(&sd_storage, mbr.partitions[mbr_idx].start_sct, 0x800, (void *)SDMMC_UPPER_BUFFER); // Clear the first 1MB.321mbr_idx++;322}323324// emuMMC goes second or third. Next to L4T if no Android.325if (part_info.emu_size)326{327mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.328mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);329330if (!part_info.emu_double)331mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 11) - 0x800; // Reserve 1MB.332else333{334mbr.partitions[mbr_idx].size_sct = part_info.emu_size << 10;335mbr_idx++;336337// 2nd emuMMC.338mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.339mbr.partitions[mbr_idx].start_sct = mbr.partitions[mbr_idx - 1].start_sct + (part_info.emu_size << 10);340mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 10) - 0x800; // Reserve 1MB.341}342mbr_idx++;343}344345if (part_info.and_size)346{347gpt_t *gpt = zalloc(sizeof(gpt_t));348gpt_header_t gpt_hdr_backup = { 0 };349350// Set GPT protective partition in MBR.351mbr.partitions[mbr_idx].type = 0xEE;352mbr.partitions[mbr_idx].start_sct = 1;353mbr.partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;354mbr_idx++;355356// Set GPT header.357memcpy(&gpt->header.signature, "EFI PART", 8);358gpt->header.revision = 0x10000;359gpt->header.size = 92;360gpt->header.my_lba = 1;361gpt->header.alt_lba = sd_storage.sec_cnt - 1;362gpt->header.first_use_lba = (sizeof(mbr_t) + sizeof(gpt_t)) >> 9;363gpt->header.last_use_lba = sd_storage.sec_cnt - 0x800 - 1; // sd_storage.sec_cnt - 33 is start of backup gpt partition entries.364se_gen_prng128(random_number);365memcpy(gpt->header.disk_guid, random_number, 10);366memcpy(gpt->header.disk_guid + 10, "NYXGPT", 6);367gpt->header.part_ent_lba = 2;368gpt->header.part_ent_size = 128;369370// Set FAT GPT partition manually.371const u8 basic_part_guid[] = { 0xA2, 0xA0, 0xD0, 0xEB, 0xE5, 0xB9, 0x33, 0x44, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 };372memcpy(gpt->entries[0].type_guid, basic_part_guid, 16);373se_gen_prng128(random_number);374memcpy(gpt->entries[0].part_guid, random_number, 16);375376// Clear non-standard Windows MBR attributes. bit4: Read only, bit5: Shadow copy, bit6: Hidden, bit7: No drive letter.377gpt->entries[0].part_guid[7] = 0;378379gpt->entries[0].lba_start = mbr.partitions[0].start_sct;380gpt->entries[0].lba_end = mbr.partitions[0].start_sct + mbr.partitions[0].size_sct - 1;381memcpy(gpt->entries[0].name, (char[]) { 'h', 0, 'o', 0, 's', 0, '_', 0, 'd', 0, 'a', 0, 't', 0, 'a', 0 }, 16);382383// Set the rest of GPT partitions.384u8 gpt_idx = 1;385u32 curr_part_lba = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);386387// L4T partition.388if (part_info.l4t_size)389_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, part_info.l4t_size << 11, (char[]) { 'l', 0, '4', 0, 't', 0 }, 6);390391if (part_info.and_dynamic)392{393// Android Linux Kernel partition. 64MB.394_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8);395396// Android Recovery partition. 64MB.397_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, (char[]) { 'r', 0, 'e', 0, 'c', 0, 'o', 0, 'v', 0, 'e', 0, 'r', 0, 'y', 0 }, 16);398399// Android Device Tree Reference partition. 1MB.400_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, (char[]) { 'd', 0, 't', 0, 'b', 0 }, 6);401402// Android Misc partition. 3MB.403_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, (char[]) { 'm', 0, 'i', 0, 's', 0, 'c', 0 }, 8);404405// Android Cache partition. 60MB.406_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1E000, (char[]) { 'c', 0, 'a', 0, 'c', 0, 'h', 0, 'e', 0 }, 10);407408// Android Super dynamic partition. 5922MB.409_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xB91000, (char[]) { 's', 0, 'u', 0, 'p', 0, 'e', 0, 'r', 0 }, 10);410411// Android Userdata partition.412u32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).413if (!part_info.emu_size)414uda_size -= 0x800; // Reserve 1MB.415_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, (char[]) { 'u', 0, 's', 0, 'e', 0, 'r', 0, 'd', 0, 'a', 0, 't', 0, 'a', 0 }, 16);416}417else418{419// Android Vendor partition. 1GB420_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, (char[]) { 'v', 0, 'e', 0, 'n', 0, 'd', 0, 'o', 0, 'r', 0 }, 12);421422// Android System partition. 3GB.423_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, (char[]) { 'A', 0, 'P', 0, 'P', 0 }, 6);424425// Android Linux Kernel partition. 32MB.426_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x10000, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6);427428// Android Recovery partition. 64MB.429_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6);430431// Android Device Tree Reference partition. 1MB.432_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6);433434// Android Encryption partition. 16MB.435// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.436sdmmc_storage_write(&sd_storage, curr_part_lba, 0x8000, (void *)SDMMC_UPPER_BUFFER); // Clear the whole of it.437_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x8000, (char[]) { 'M', 0, 'D', 0, 'A', 0 }, 6);438439// Android Cache partition. 700MB.440_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, (char[]) { 'C', 0, 'A', 0, 'C', 0 }, 6);441442// Android Misc partition. 3MB.443_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, (char[]) { 'M', 0, 'S', 0, 'C', 0 }, 6);444445// Android Userdata partition.446u32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).447if (!part_info.emu_size)448uda_size -= 0x800; // Reserve 1MB.449_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, (char[]) { 'U', 0, 'D', 0, 'A', 0 }, 6);450}451452// Handle emuMMC partitions manually.453if (part_info.emu_size)454{455// Set 1st emuMMC.456u8 emu_part_guid[] = { 0x00, 0x7E, 0xCA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'e', 'm', 'u', 'M', 'M', 'C' };457memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);458se_gen_prng128(random_number);459memcpy(gpt->entries[gpt_idx].part_guid, random_number, 16);460gpt->entries[gpt_idx].lba_start = curr_part_lba;461if (!part_info.emu_double)462gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 11) - 0x800 - 1; // Reserve 1MB.463else464gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 1;465memcpy(gpt->entries[gpt_idx].name, (char[]) { 'e', 0, 'm', 0, 'u', 0, 'm', 0, 'm', 0, 'c', 0 }, 12);466gpt_idx++;467468// Set 2nd emuMMC.469if (part_info.emu_double)470{471curr_part_lba += (part_info.emu_size << 10);472memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);473se_gen_prng128(random_number);474memcpy(gpt->entries[gpt_idx].part_guid, random_number, 16);475gpt->entries[gpt_idx].lba_start = curr_part_lba;476gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 0x800 - 1; // Reserve 1MB.477memcpy(gpt->entries[gpt_idx].name, (char[]) { 'e', 0, 'm', 0, 'u', 0, 'm', 0, 'm', 0, 'c', 0, '2', 0 }, 14);478gpt_idx++;479}480}481482// Set final GPT header parameters.483gpt->header.num_part_ents = gpt_idx;484gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);485gpt->header.crc32 = 0; // Set to 0 for calculation.486gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);487488// Set final backup GPT header parameters.489memcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));490gpt_hdr_backup.my_lba = sd_storage.sec_cnt - 1;491gpt_hdr_backup.alt_lba = 1;492gpt_hdr_backup.part_ent_lba = sd_storage.sec_cnt - 33;493gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.494gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);495496// Write main GPT.497sdmmc_storage_write(&sd_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);498499// Write backup GPT partition table.500sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);501502// Write backup GPT header.503sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);504505free(gpt);506}507508// Write MBR.509sdmmc_storage_write(&sd_storage, 0, 1, &mbr);510}511512static lv_res_t _action_part_manager_ums_sd(lv_obj_t *btn)513{514action_ums_sd(btn);515516// Close and reopen partition manager.517lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK);518close_btn_action(close_btn);519lv_obj_del(ums_mbox);520create_window_partition_manager(NULL);521522return LV_RES_INV;523}524525static lv_res_t _action_delete_linux_installer_files(lv_obj_t * btns, const char * txt)526{527528int btn_idx = lv_btnm_get_pressed(btns);529530// Delete parent mbox.531mbox_action(btns, txt);532533// Flash Linux.534if (!btn_idx)535{536char path[128];537538sd_mount();539540strcpy(path, "switchroot/install/l4t.");541542// Delete all l4t.xx files.543u32 idx = 0;544while (true)545{546if (idx < 10)547{548path[23] = '0';549itoa(idx, &path[23 + 1], 10);550}551else552itoa(idx, &path[23], 10);553554if (!f_stat(path, NULL))555{556f_unlink(path);557}558else559break;560561idx++;562}563564sd_unmount();565}566567return LV_RES_INV;568}569570static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt)571{572int btn_idx = lv_btnm_get_pressed(btns);573574// Delete parent mbox.575mbox_action(btns, txt);576577bool succeeded = false;578579if (btn_idx)580return LV_RES_INV;581582// Flash Linux.583lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);584lv_obj_set_style(dark_bg, &mbox_darken);585lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);586587static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };588static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "" };589lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);590lv_mbox_set_recolor_text(mbox, true);591lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);592593lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");594595lv_obj_t *lbl_status = lv_label_create(mbox, NULL);596lv_label_set_recolor(lbl_status, true);597lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux...");598599// Create container to keep content inside.600lv_obj_t *h1 = lv_cont_create(mbox, NULL);601lv_cont_set_fit(h1, true, true);602lv_cont_set_style(h1, &lv_style_transp_tight);603604lv_obj_t *bar = lv_bar_create(h1, NULL);605lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5);606lv_bar_set_range(bar, 0, 100);607lv_bar_set_value(bar, 0);608609lv_obj_t *label_pct = lv_label_create(h1, NULL);610lv_label_set_recolor(label_pct, true);611lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%");612lv_label_set_style(label_pct, lv_theme_get_current()->label.prim);613lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);614615lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);616lv_obj_set_top(mbox, true);617618sd_mount();619620int res = 0;621char *path = malloc(1024);622char *txt_buf = malloc(SZ_4K);623strcpy(path, "switchroot/install/l4t.00");624u32 path_len = strlen(path) - 2;625626FIL fp;627628res = f_open(&fp, path, FA_READ);629if (res)630{631lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!");632633goto exit;634}635636u64 fileSize = (u64)f_size(&fp);637638u32 num = 0;639u32 pct = 0;640u32 lba_curr = 0;641u32 bytesWritten = 0;642u32 currPartIdx = 0;643u32 prevPct = 200;644int retryCount = 0;645u32 total_size_sct = l4t_flash_ctxt.image_size_sct;646647u8 *buf = (u8 *)MIXD_BUF_ALIGNED;648DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);649650// Start flashing L4T.651while (total_size_sct > 0)652{653// 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.654if (bytesWritten >= fileSize)655{656// If we have more bytes written then close the file pointer and increase the part index we are using657f_close(&fp);658free(clmt);659memset(&fp, 0, sizeof(fp));660currPartIdx++;661662if (currPartIdx < 10)663{664path[path_len] = '0';665itoa(currPartIdx, &path[path_len + 1], 10);666}667else668itoa(currPartIdx, &path[path_len], 10);669670// Try to open the next file part671res = f_open(&fp, path, FA_READ);672if (res)673{674s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx);675lv_label_set_text(lbl_status, txt_buf);676manual_system_maintenance(true);677678goto exit;679}680fileSize = (u64)f_size(&fp);681bytesWritten = 0;682clmt = f_expand_cltbl(&fp, SZ_4M, 0);683}684685retryCount = 0;686num = MIN(total_size_sct, 8192);687688// Read next data block from SD.689res = f_read_fast(&fp, buf, num << 9);690manual_system_maintenance(false);691692if (res)693{694lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!");695manual_system_maintenance(true);696697f_close(&fp);698free(clmt);699goto exit;700}701702// Write data block to L4T partition.703res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);704705manual_system_maintenance(false);706707// If failed, retry 3 more times.708while (res)709{710msleep(150);711manual_system_maintenance(true);712713if (retryCount >= 3)714{715lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!");716manual_system_maintenance(true);717718f_close(&fp);719free(clmt);720goto exit;721}722723res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);724manual_system_maintenance(false);725}726727// Update completion percentage.728pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct;729if (pct != prevPct)730{731lv_bar_set_value(bar, pct);732s_printf(txt_buf, " #DDDDDD "SYMBOL_DOT"# %d%%", pct);733lv_label_set_text(label_pct, txt_buf);734manual_system_maintenance(true);735prevPct = pct;736}737738lba_curr += num;739total_size_sct -= num;740bytesWritten += num * EMMC_BLOCKSIZE;741}742lv_bar_set_value(bar, 100);743lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%");744manual_system_maintenance(true);745746// Restore operation ended successfully.747f_close(&fp);748free(clmt);749750succeeded = true;751752exit:753free(path);754free(txt_buf);755756if (!succeeded)757lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);758else759lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files);760lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);761762sd_unmount();763764return LV_RES_INV;765}766767static u32 _get_available_l4t_partition()768{769mbr_t mbr = { 0 };770gpt_t *gpt = zalloc(sizeof(gpt_t));771772memset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t));773774// Read MBR.775sdmmc_storage_read(&sd_storage, 0, 1, &mbr);776777// Read main GPT.778sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);779780// Search for a suitable partition.781u32 size_sct = 0;782if (!memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)783{784for (u32 i = 0; i < gpt->header.num_part_ents; i++)785{786if (!memcmp(gpt->entries[i].name, (char[]) { 'l', 0, '4', 0, 't', 0 }, 6))787{788l4t_flash_ctxt.offset_sct = gpt->entries[i].lba_start;789size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;790break;791}792793if (i > 126)794break;795}796}797else798{799for (u32 i = 1; i < 4; i++)800{801if (mbr.partitions[i].type == 0x83)802{803l4t_flash_ctxt.offset_sct = mbr.partitions[i].start_sct;804size_sct = mbr.partitions[i].size_sct;805break;806}807}808}809810free(gpt);811812return size_sct;813}814815static int _get_available_android_partition()816{817gpt_t *gpt = zalloc(sizeof(gpt_t));818819// Read main GPT.820sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);821822// Check if GPT.823if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)824goto out;825826// Find kernel partition.827for (u32 i = 0; i < gpt->header.num_part_ents; i++)828{829if (gpt->entries[i].lba_start)830{831int found = !memcmp(gpt->entries[i].name, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8) ? 2 : 0;832found |= !memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6) ? 1 : 0;833834if (found)835{836free(gpt);837838return found;839}840}841842if (i > 126)843break;844}845846out:847free(gpt);848849return false;850}851852static lv_res_t _action_check_flash_linux(lv_obj_t *btn)853{854FILINFO fno;855char path[128];856857lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);858lv_obj_set_style(dark_bg, &mbox_darken);859lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);860861static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };862static const char *mbox_btn_map2[] = { "\222Continue", "\222Cancel", "" };863lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);864lv_mbox_set_recolor_text(mbox, true);865lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);866867lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");868869lv_obj_t *lbl_status = lv_label_create(mbox, NULL);870lv_label_set_recolor(lbl_status, true);871lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");872873lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);874lv_obj_set_top(mbox, true);875876manual_system_maintenance(true);877878sd_mount();879880// Check if L4T image exists.881strcpy(path, "switchroot/install/l4t.00");882if (f_stat(path, NULL))883{884lv_label_set_text(lbl_status, "#FFDD00 Error:# Installation files not found!");885goto error;886}887888// Find an applicable partition for L4T.889u32 size_sct = _get_available_l4t_partition();890if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)891{892lv_label_set_text(lbl_status, "#FFDD00 Error:# No partition found!");893goto error;894}895896u32 idx = 0;897path[23] = 0;898899// Validate L4T images and consolidate their info.900while (true)901{902if (idx < 10)903{904path[23] = '0';905itoa(idx, &path[23 + 1], 10);906}907else908itoa(idx, &path[23], 10);909910// Check for alignment.911if (f_stat(path, &fno))912break;913914// Check if current part is unaligned.915if ((u64)fno.fsize % SZ_4M)916{917// Get next part filename.918idx++;919if (idx < 10)920{921path[23] = '0';922itoa(idx, &path[23 + 1], 10);923}924else925itoa(idx, &path[23], 10);926927// If it exists, unaligned size for current part is not permitted.928if (!f_stat(path, NULL)) // NULL: Don't override current part fs info.929{930lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!");931goto error;932}933934// Last part. Align size to LBA (SD_BLOCKSIZE).935fno.fsize = ALIGN((u64)fno.fsize, SD_BLOCKSIZE);936idx--;937}938l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9;939940idx++;941}942943// Check if image size is bigger than the partition available.944if (l4t_flash_ctxt.image_size_sct > size_sct)945{946lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is bigger than the partition!");947goto error;948}949950char *txt_buf = malloc(SZ_4K);951s_printf(txt_buf,952"#C7EA46 Status:# Found installation files and partition.\n"953"#00DDFF Offset:# %08x, #00DDFF Size:# %X, #00DDFF Image size:# %d MiB\n"954"\nDo you want to continue?", l4t_flash_ctxt.offset_sct, size_sct, l4t_flash_ctxt.image_size_sct >> 11);955lv_label_set_text(lbl_status, txt_buf);956free(txt_buf);957lv_mbox_add_btns(mbox, mbox_btn_map2, _action_flash_linux_data);958goto exit;959960error:961lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);962963exit:964lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);965966sd_unmount();967968return LV_RES_OK;969}970971static lv_res_t _action_reboot_recovery(lv_obj_t * btns, const char * txt)972{973int btn_idx = lv_btnm_get_pressed(btns);974975// Delete parent mbox.976mbox_action(btns, txt);977978if (!btn_idx)979{980// Set custom reboot type to Android Recovery.981PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY;982983// Enable hekate boot configuration.984b_cfg->boot_cfg = BOOT_CFG_FROM_ID | BOOT_CFG_AUTOBOOT_EN;985986// Set id to Android.987strcpy((char *)b_cfg->id, "SWANDR");988989void (*main_ptr)() = (void *)nyx_str->hekate;990991// Deinit hardware.992sd_end();993hw_deinit(false, 0);994995// Chainload to hekate main.996(*main_ptr)();997}998999return LV_RES_INV;1000}10011002static lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt)1003{1004int btn_idx = lv_btnm_get_pressed(btns);1005bool boot_recovery = false;10061007// Delete parent mbox.1008mbox_action(btns, txt);10091010if (btn_idx)1011return LV_RES_INV;10121013// Flash Android components.1014char path[128];1015gpt_t *gpt = zalloc(sizeof(gpt_t));1016char *txt_buf = malloc(SZ_4K);10171018lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1019lv_obj_set_style(dark_bg, &mbox_darken);1020lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);10211022static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1023static const char *mbox_btn_map2[] = { "\222Continue", "\222No", "" };1024lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1025lv_mbox_set_recolor_text(mbox, true);1026lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);10271028lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");10291030lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1031lv_label_set_recolor(lbl_status, true);1032lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");10331034lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1035lv_obj_set_top(mbox, true);10361037manual_system_maintenance(true);10381039sd_mount();10401041// Read main GPT.1042sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);10431044// Validate GPT header.1045if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)1046{1047lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!");1048goto error;1049}10501051u32 offset_sct = 0;1052u32 size_sct = 0;10531054// Check if Kernel image should be flashed.1055strcpy(path, "switchroot/install/boot.img");1056if (f_stat(path, NULL))1057{1058s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n");1059goto boot_img_not_found;1060}10611062// Find Kernel partition.1063for (u32 i = 0; i < gpt->header.num_part_ents; i++)1064{1065if (!memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8))1066{1067offset_sct = gpt->entries[i].lba_start;1068size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1069break;1070}10711072if (i > 126)1073break;1074}10751076// Flash Kernel.1077if (offset_sct && size_sct)1078{1079u32 file_size = 0;1080u8 *buf = sd_file_read(path, &file_size);10811082if (file_size % 0x200)1083{1084file_size = ALIGN(file_size, 0x200);1085u8 *buf_tmp = zalloc(file_size);1086memcpy(buf_tmp, buf, file_size);1087free(buf);1088buf = buf_tmp;1089}10901091if ((file_size >> 9) > size_sct)1092s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n");1093else1094{1095sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);10961097s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n");1098f_unlink(path);1099}11001101free(buf);1102}1103else1104s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n");11051106boot_img_not_found:1107lv_label_set_text(lbl_status, txt_buf);1108manual_system_maintenance(true);11091110// Check if Recovery should be flashed.1111strcpy(path, "switchroot/install/recovery.img");1112if (f_stat(path, NULL))1113{1114// Not found, try twrp.img instead.1115strcpy(path, "switchroot/install/twrp.img");1116if (f_stat(path, NULL))1117{1118strcat(txt_buf, "#FF8000 Warning:# Recovery image not found!\n");1119goto recovery_not_found;1120}1121}11221123offset_sct = 0;1124size_sct = 0;11251126// Find Recovery partition.1127for (u32 i = 0; i < gpt->header.num_part_ents; i++)1128{1129if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'r', 0, 'e', 0, 'c', 0, 'o', 0, 'v', 0, 'e', 0, 'r', 0, 'y', 0 }, 16))1130{1131offset_sct = gpt->entries[i].lba_start;1132size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1133break;1134}11351136if (i > 126)1137break;1138}11391140// Flash Recovery.1141if (offset_sct && size_sct)1142{1143u32 file_size = 0;1144u8 *buf = sd_file_read(path, &file_size);11451146if (file_size % 0x200)1147{1148file_size = ALIGN(file_size, 0x200);1149u8 *buf_tmp = zalloc(file_size);1150memcpy(buf_tmp, buf, file_size);1151free(buf);1152buf = buf_tmp;1153}11541155if ((file_size >> 9) > size_sct)1156strcat(txt_buf, "#FF8000 Warning:# Recovery image too big!\n");1157else1158{1159sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);1160strcat(txt_buf, "#C7EA46 Success:# Recovery image flashed!\n");1161f_unlink(path);1162}11631164free(buf);1165}1166else1167strcat(txt_buf, "#FF8000 Warning:# Recovery partition not found!\n");11681169recovery_not_found:1170lv_label_set_text(lbl_status, txt_buf);1171manual_system_maintenance(true);11721173// Check if Device Tree should be flashed.1174strcpy(path, "switchroot/install/nx-plat.dtimg");1175if (f_stat(path, NULL))1176{1177strcpy(path, "switchroot/install/tegra210-icosa.dtb");1178if (f_stat(path, NULL))1179{1180strcat(txt_buf, "#FF8000 Warning:# DTB image not found!");1181goto dtb_not_found;1182}1183}11841185offset_sct = 0;1186size_sct = 0;11871188// Find Device Tree partition.1189for (u32 i = 0; i < gpt->header.num_part_ents; i++)1190{1191if (!memcmp(gpt->entries[i].name, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'd', 0, 't', 0, 'b', 0 }, 6))1192{1193offset_sct = gpt->entries[i].lba_start;1194size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1195break;1196}11971198if (i > 126)1199break;1200}12011202// Flash Device Tree.1203if (offset_sct && size_sct)1204{1205u32 file_size = 0;1206u8 *buf = sd_file_read(path, &file_size);12071208if (file_size % 0x200)1209{1210file_size = ALIGN(file_size, 0x200);1211u8 *buf_tmp = zalloc(file_size);1212memcpy(buf_tmp, buf, file_size);1213free(buf);1214buf = buf_tmp;1215}12161217if ((file_size >> 9) > size_sct)1218strcat(txt_buf, "#FF8000 Warning:# DTB image too big!");1219else1220{1221sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);1222strcat(txt_buf, "#C7EA46 Success:# DTB image flashed!");1223f_unlink(path);1224}12251226free(buf);1227}1228else1229strcat(txt_buf, "#FF8000 Warning:# DTB partition not found!");12301231dtb_not_found:1232lv_label_set_text(lbl_status, txt_buf);12331234// Check if Recovery is flashed unconditionally.1235for (u32 i = 0; i < gpt->header.num_part_ents; i++)1236{1237if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'r', 0, 'e', 0, 'c', 0, 'o', 0, 'v', 0, 'e', 0, 'r', 0, 'y', 0 }, 16))1238{1239u8 *buf = malloc(SD_BLOCKSIZE);1240sdmmc_storage_read(&sd_storage, gpt->entries[i].lba_start, 1, buf);1241if (!memcmp(buf, "ANDROID", 7))1242boot_recovery = true;1243free(buf);1244break;1245}12461247if (i > 126)1248break;1249}12501251error:1252if (boot_recovery)1253{1254// If a Recovery partition was found, ask user if rebooting into it is wanted.1255strcat(txt_buf,"\n\nDo you want to reboot into Recovery\nto finish Android installation?");1256lv_label_set_text(lbl_status, txt_buf);1257lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_recovery);1258}1259else1260lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);12611262lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);12631264free(txt_buf);1265free(gpt);12661267sd_unmount();12681269return LV_RES_INV;1270}12711272static lv_res_t _action_flash_android(lv_obj_t *btn)1273{1274lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1275lv_obj_set_style(dark_bg, &mbox_darken);1276lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);12771278static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" };1279lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1280lv_mbox_set_recolor_text(mbox, true);1281lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);12821283lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");12841285lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1286lv_label_set_recolor(lbl_status, true);1287lv_label_set_text(lbl_status,1288"This will flash #C7EA46 Kernel#, #C7EA46 DTB# and #C7EA46 Recovery# if found.\n"1289"These will be deleted after a successful flash.\n"1290"Do you want to continue?");12911292lv_mbox_add_btns(mbox, mbox_btn_map, _action_flash_android_data);1293lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1294lv_obj_set_top(mbox, true);12951296return LV_RES_OK;1297}12981299static lv_res_t _action_part_manager_flash_options0(lv_obj_t *btns, const char *txt)1300{1301int btn_idx = lv_btnm_get_pressed(btns);13021303switch (btn_idx)1304{1305case 0:1306action_ums_sd(btns);1307lv_obj_del(ums_mbox);1308break;1309case 1:1310_action_check_flash_linux(btns);1311break;1312case 2:1313_action_flash_android(btns);1314break;1315case 3:1316mbox_action(btns, txt);1317return LV_RES_INV;1318}13191320return LV_RES_OK;1321}13221323static lv_res_t _action_part_manager_flash_options1(lv_obj_t *btns, const char *txt)1324{1325int btn_idx = lv_btnm_get_pressed(btns);13261327switch (btn_idx)1328{1329case 0:1330action_ums_sd(btns);1331lv_obj_del(ums_mbox);1332break;1333case 1:1334mbox_action(btns, txt);1335_action_check_flash_linux(NULL);1336return LV_RES_INV;1337case 2:1338mbox_action(btns, txt);1339return LV_RES_INV;1340}13411342return LV_RES_OK;1343}13441345static lv_res_t _action_part_manager_flash_options2(lv_obj_t *btns, const char *txt)1346{1347int btn_idx = lv_btnm_get_pressed(btns);13481349switch (btn_idx)1350{1351case 0:1352action_ums_sd(btns);1353lv_obj_del(ums_mbox);1354break;1355case 1:1356mbox_action(btns, txt);1357_action_flash_android(NULL);1358return LV_RES_INV;1359case 2:1360mbox_action(btns, txt);1361return LV_RES_INV;1362}13631364return LV_RES_OK;1365}13661367static int _backup_and_restore_files(bool backup, lv_obj_t **labels)1368{1369const char *src_drv = backup ? "sd:" : "ram:";1370const char *dst_drv = backup ? "ram:" : "sd:";13711372int res = 0;1373u32 total_size = 0;1374u32 total_files = 0;1375char *path = malloc(0x1000);1376path[0] = 0; // Set default as root folder.13771378// Check if Mariko Warmboot Storage exists in source drive.1379f_chdrive(src_drv);1380bool backup_mws = !part_info.backup_possible && !f_stat("warmboot_mariko", NULL);1381bool backup_pld = !part_info.backup_possible && !f_stat("payload.bin", NULL);13821383if (!part_info.backup_possible)1384{1385// Change path to hekate/Nyx.1386strcpy(path, "bootloader");13871388// Create hekate/Nyx/MWS folders in destination drive.1389f_chdrive(dst_drv);1390f_mkdir("bootloader");1391if (backup_mws)1392f_mkdir("warmboot_mariko");1393}13941395// Copy all or hekate/Nyx files.1396res = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels);13971398// If incomplete backup mode, copy MWS and payload.bin also.1399if (!res)1400{1401if (backup_mws)1402{1403strcpy(path, "warmboot_mariko");1404res = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels);1405}14061407if (!res && backup_pld)1408{1409strcpy(path, "payload.bin");1410res = _copy_file(src_drv, dst_drv, path);1411}1412}14131414free(path);14151416return res;1417}14181419static lv_res_t _create_mbox_start_partitioning(lv_obj_t *btn)1420{1421lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1422lv_obj_set_style(dark_bg, &mbox_darken);1423lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);14241425static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1426static const char *mbox_btn_map1[] = { "\222SD UMS", "\222Flash Linux", "\222Flash Android", "\221OK", "" };1427static const char *mbox_btn_map2[] = { "\222SD UMS", "\222Flash Linux", "\221OK", "" };1428static const char *mbox_btn_map3[] = { "\222SD UMS", "\222Flash Android", "\221OK", "" };1429lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1430lv_mbox_set_recolor_text(mbox, true);1431lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);14321433lv_mbox_set_text(mbox, "#FF8000 Partition Manager#");1434lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1435lv_obj_set_top(mbox, true);14361437bool buttons_set = false;14381439// Use safety wait if backup is not possible.1440char *txt_buf = malloc(SZ_4K);1441strcpy(txt_buf, "#FF8000 Partition Manager#\n\nSafety wait ends in ");1442lv_mbox_set_text(mbox, txt_buf);14431444u32 seconds = 5;1445u32 text_idx = strlen(txt_buf);1446while (seconds)1447{1448s_printf(txt_buf + text_idx, "%d seconds...", seconds);1449lv_mbox_set_text(mbox, txt_buf);1450manual_system_maintenance(true);1451msleep(1000);1452seconds--;1453}14541455lv_mbox_set_text(mbox,1456"#FF8000 Partition Manager#\n\n"1457"#FFDD00 Warning: Do you really want to continue?!#\n\n"1458"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");1459lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1460manual_system_maintenance(true);14611462free(txt_buf);14631464if (!(btn_wait() & BTN_POWER))1465goto exit;14661467// Start partitioning.1468lv_mbox_set_text(mbox, "#FF8000 Partition Manager#");1469lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1470manual_system_maintenance(true);14711472lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1473lv_label_set_recolor(lbl_status, true);14741475lv_obj_t *lbl_paths[2];14761477// Create backup/restore paths labels.1478lbl_paths[0] = lv_label_create(mbox, NULL);1479lv_label_set_text(lbl_paths[0], "/");1480lv_label_set_long_mode(lbl_paths[0], LV_LABEL_LONG_DOT);1481lv_cont_set_fit(lbl_paths[0], false, true);1482lv_obj_set_width(lbl_paths[0], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1483lv_label_set_align(lbl_paths[0], LV_LABEL_ALIGN_CENTER);1484lbl_paths[1] = lv_label_create(mbox, NULL);1485lv_label_set_text(lbl_paths[1], " ");1486lv_label_set_long_mode(lbl_paths[1], LV_LABEL_LONG_DOT);1487lv_cont_set_fit(lbl_paths[1], false, true);1488lv_obj_set_width(lbl_paths[1], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1489lv_label_set_align(lbl_paths[1], LV_LABEL_ALIGN_CENTER);14901491sd_mount();14921493FATFS ram_fs;14941495// Read current MBR.1496sdmmc_storage_read(&sd_storage, 0, 1, &part_info.mbr_old);14971498lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing Ramdisk...");1499lv_label_set_text(lbl_paths[0], "Please wait...");1500lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1501manual_system_maintenance(true);15021503// Initialize RAM disk.1504if (ram_disk_init(&ram_fs, RAM_DISK_SZ))1505{1506lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to initialize Ramdisk!");1507goto error;1508}15091510lv_label_set_text(lbl_status, "#00DDFF Status:# Backing up files...");1511manual_system_maintenance(true);15121513// Do full or hekate/Nyx backup.1514if (_backup_and_restore_files(true, lbl_paths))1515{1516if (part_info.backup_possible)1517lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!");1518else1519lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!\nBootloader folder exceeds 1GB or corrupt!");15201521goto error;1522}15231524f_mount(NULL, "sd:", 1); // Unmount SD card.15251526lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting FAT32 partition...");1527lv_label_set_text(lbl_paths[0], "Please wait...");1528lv_label_set_text(lbl_paths[1], " ");1529manual_system_maintenance(true);15301531// Set reserved size.1532u32 part_rsvd_size = (part_info.emu_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);1533part_rsvd_size += part_rsvd_size ? part_info.alignment : 0; // Do not reserve alignment space if no extra partitions.1534disk_set_info(DRIVE_SD, SET_SECTOR_COUNT, &part_rsvd_size);1535u8 *buf = malloc(SZ_4M);15361537// Set cluster size to 64KB and try to format.1538u32 cluster_size = 65536;1539u32 mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);15401541if (!mkfs_error)1542goto mkfs_no_error;15431544// Retry formatting by halving cluster size, until one succeeds.1545while (cluster_size > 4096)1546{1547cluster_size /= 2;1548mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);15491550if (!mkfs_error)1551break;1552}15531554if (mkfs_error)1555{1556// Failed to format.1557s_printf((char *)buf, "#FFDD00 Error:# Failed to format disk (%d)!\n\n"1558"Remove the SD card and check that is OK.\nIf not, format it, reinsert it and\npress #FF8000 POWER#!", mkfs_error);15591560lv_label_set_text(lbl_status, (char *)buf);1561lv_label_set_text(lbl_paths[0], " ");1562manual_system_maintenance(true);15631564sd_end();15651566while (!(btn_wait() & BTN_POWER));15671568sd_mount();15691570lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");1571manual_system_maintenance(true);15721573// Restore backed up files back to SD.1574if (_backup_and_restore_files(false, lbl_paths))1575{1576// Failed to restore files. Try again once more.1577if (_backup_and_restore_files(false, lbl_paths))1578{1579lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");1580free(buf);1581goto error;1582}1583}15841585lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!");1586f_mount(NULL, "ram:", 1); // Unmount ramdisk.1587free(buf);1588goto error;1589}15901591mkfs_no_error:1592free(buf);15931594// Remount sd card as it was unmounted from formatting it.1595f_mount(&sd_fs, "sd:", 1); // Mount SD card.15961597lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");1598manual_system_maintenance(true);15991600// Restore backed up files back to SD.1601if (_backup_and_restore_files(false, lbl_paths))1602{1603// Failed to restore files. Try again once more.1604if (_backup_and_restore_files(false, lbl_paths))1605{1606lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");1607goto error;1608}1609}16101611f_mount(NULL, "ram:", 1); // Unmount ramdisk.1612f_chdrive("sd:");16131614// Set Volume label.1615f_setlabel("0:SWITCH SD");16161617lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table...");1618lv_label_set_text(lbl_paths[0], "Please wait...");1619lv_label_set_text(lbl_paths[1], " ");1620manual_system_maintenance(true);16211622// Prepare MBR and GPT header and partition entries and flash them.1623_prepare_and_flash_mbr_gpt();16241625// Enable/Disable buttons depending on partition layout.1626if (part_info.l4t_size)1627{1628lv_obj_set_click(btn_flash_l4t, true);1629lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);1630}1631else1632{1633lv_obj_set_click(btn_flash_l4t, false);1634lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);1635}16361637// Enable/Disable buttons depending on partition layout.1638if (part_info.and_size)1639{1640lv_obj_set_click(btn_flash_android, true);1641lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);1642}1643else1644{1645lv_obj_set_click(btn_flash_android, false);1646lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);1647}16481649sd_unmount();1650lv_label_set_text(lbl_status, "#00DDFF Status:# Done!");1651manual_system_maintenance(true);16521653// Set buttons depending on what user chose to create.1654if (part_info.l4t_size && part_info.and_size)1655lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);1656else if (part_info.l4t_size)1657lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);1658else if (part_info.and_size)1659lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);16601661if (part_info.l4t_size || part_info.and_size)1662buttons_set = true;16631664goto out;16651666error:1667f_chdrive("sd:");16681669out:1670lv_obj_del(lbl_paths[0]);1671lv_obj_del(lbl_paths[1]);1672exit:1673if (!buttons_set)1674lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);1675lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1676lv_obj_set_top(mbox, true);16771678// Disable partitioning button.1679if (btn)1680lv_btn_set_state(btn, LV_BTN_STATE_INA);16811682return LV_RES_OK;1683}16841685static lv_res_t _create_mbox_partitioning_option0(lv_obj_t *btns, const char *txt)1686{1687int btn_idx = lv_btnm_get_pressed(btns);16881689switch (btn_idx)1690{1691case 0:1692action_ums_sd(btns);1693return LV_RES_OK;1694case 1:1695mbox_action(btns, txt);1696_create_mbox_start_partitioning(NULL);1697break;1698case 2:1699mbox_action(btns, txt);1700break;1701}17021703return LV_RES_INV;1704}17051706static lv_res_t _create_mbox_partitioning_option1(lv_obj_t *btns, const char *txt)1707{1708int btn_idx = lv_btnm_get_pressed(btns);17091710mbox_action(btns, txt);17111712if (!btn_idx)1713{1714mbox_action(btns, txt);1715_create_mbox_start_partitioning(NULL);1716return LV_RES_INV;1717}17181719return LV_RES_OK;1720}17211722static lv_res_t _create_mbox_partitioning_warn(lv_obj_t *btn)1723{1724lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1725lv_obj_set_style(dark_bg, &mbox_darken);1726lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);17271728static const char *mbox_btn_map[] = { "\222SD UMS", "\222Start", "\222Cancel", "" };1729static const char *mbox_btn_map2[] = { "\222Start", "\222Cancel", "" };1730lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);1731lv_mbox_set_recolor_text(mbox, true);17321733char *txt_buf = malloc(SZ_4K);1734lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);1735lv_mbox_set_text(mbox, "#FF8000 Partition Manager#");17361737lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1738lv_label_set_recolor(lbl_status, true);17391740s_printf(txt_buf, "#FFDD00 Warning: This will partition the SD Card!#\n\n");17411742if (part_info.backup_possible)1743{1744strcat(txt_buf, "#C7EA46 Your files will be backed up and restored!#\n"1745"#FFDD00 Any other partition will be wiped!#");1746}1747else1748{1749strcat(txt_buf, "#FFDD00 Your files will be wiped!#\n"1750"#FFDD00 Any other partition will be also wiped!#\n"1751"#FFDD00 Use USB UMS to copy them over!#");1752}17531754lv_label_set_text(lbl_status, txt_buf);17551756if (part_info.backup_possible)1757lv_mbox_add_btns(mbox, mbox_btn_map2, _create_mbox_partitioning_option1);1758else1759lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_option0);17601761lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1762lv_obj_set_top(mbox, true);17631764free(txt_buf);17651766return LV_RES_OK;1767}17681769static lv_res_t _create_mbox_partitioning_android(lv_obj_t *btns, const char *txt)1770{1771int btn_idx = lv_btnm_get_pressed(btns);17721773mbox_action(btns, txt);17741775part_info.and_dynamic = !btn_idx;1776_create_mbox_partitioning_warn(NULL);17771778return LV_RES_INV;1779}17801781static lv_res_t _create_mbox_partitioning_andr_part(lv_obj_t *btn)1782{1783lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1784lv_obj_set_style(dark_bg, &mbox_darken);1785lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);17861787static const char *mbox_btn_map[] = { "\222Dynamic", "\222Legacy", "" };1788lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);1789lv_mbox_set_recolor_text(mbox, true);17901791lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);1792lv_mbox_set_text(mbox, "#FF8000 Android Partitioning#");17931794lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1795lv_label_set_recolor(lbl_status, true);17961797lv_label_set_text(lbl_status,1798"Please select a partition scheme:\n\n"1799"#C7EA46 Dynamic:# Android 13+\n"1800"#C7EA46 Legacy:# Android 10-11\n");18011802lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_android);1803lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1804lv_obj_set_top(mbox, true);18051806return LV_RES_OK;1807}18081809static lv_res_t _create_mbox_partitioning_next(lv_obj_t *btn) {1810if (part_info.and_size)1811return _create_mbox_partitioning_andr_part(NULL);1812else1813return _create_mbox_partitioning_warn(NULL);1814}18151816static void _update_partition_bar()1817{1818lv_obj_t *h1 = lv_obj_get_parent(part_info.bar_hos);18191820// Set widths based on max bar width.1821u32 total_size = (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB;1822u32 bar_hos_size = lv_obj_get_width(h1) * (part_info.hos_size >> 10) / total_size;1823u32 bar_emu_size = lv_obj_get_width(h1) * (part_info.emu_size >> 10) / total_size;1824u32 bar_l4t_size = lv_obj_get_width(h1) * (part_info.l4t_size >> 10) / total_size;1825u32 bar_and_size = lv_obj_get_width(h1) * (part_info.and_size >> 10) / total_size;18261827// Update bar widths.1828lv_obj_set_size(part_info.bar_hos, bar_hos_size, LV_DPI / 2);1829lv_obj_set_size(part_info.bar_emu, bar_emu_size, LV_DPI / 2);1830lv_obj_set_size(part_info.bar_l4t, bar_l4t_size, LV_DPI / 2);1831lv_obj_set_size(part_info.bar_and, bar_and_size, LV_DPI / 2);18321833// Re-align bars.1834lv_obj_align(part_info.bar_emu, part_info.bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);1835lv_obj_align(part_info.bar_l4t, part_info.bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);1836lv_obj_align(part_info.bar_and, part_info.bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);18371838// Set emuMMC blending separator sizes and realign.1839lv_obj_set_size(part_info.sep_emu, bar_emu_size ? 8 : 0, LV_DPI / 2);1840lv_obj_align(part_info.sep_emu, part_info.bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);18411842// Set L4T blending separator sizes and realign.1843lv_obj_set_size(part_info.sep_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 2);1844lv_obj_align(part_info.sep_l4t, part_info.bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);18451846// Set Android blending separator sizes and realign.1847lv_obj_set_size(part_info.sep_and, bar_and_size ? 8 : 0, LV_DPI / 2);1848lv_obj_align(part_info.sep_and, part_info.bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);1849}18501851static lv_res_t _action_slider_emu(lv_obj_t *slider)1852{1853#define EMUMMC_32GB_FULL 298561854#define EMUMMC_64GB_FULL (59664 + 1) // 1MB extra for backup GPT.18551856static const u32 rsvd_mb = 4 + 4 + 16 + 8; // BOOT0 + BOOT1 + 16MB offset + 8MB alignment.1857u32 size;1858char lbl_text[64];1859bool prev_emu_double = part_info.emu_double;1860int slide_val = lv_slider_get_value(slider);1861u32 max_emmc_size = !part_info.emmc_is_64gb ? EMUMMC_32GB_FULL : EMUMMC_64GB_FULL;18621863part_info.emu_double = false;18641865size = (slide_val > 10 ? (slide_val - 10) : slide_val) + 3; // Min 4GB.1866size *= 1024; // Convert to GB.1867size += rsvd_mb; // Add reserved size.18681869if (!slide_val)1870size = 0; // Reset if 0.1871else if (slide_val >= 11)1872{1873size *= 2;1874part_info.emu_double = true;1875}18761877// Handle special cases. 2nd value is for 64GB Aula.1878if (slide_val == 10)1879size = max_emmc_size;1880else if (slide_val == 20)1881size = 2 * max_emmc_size;18821883// Sanitize sizes based on new HOS size.1884s32 hos_size = (part_info.total_sct >> 11) - 16 - size - part_info.l4t_size - part_info.and_size;1885if (hos_size > HOS_MIN_SIZE_MB)1886{1887part_info.emu_size = size;1888part_info.hos_size = hos_size;18891890s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10);1891lv_label_set_text(part_info.lbl_hos, lbl_text);1892lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);18931894if (!part_info.emu_double)1895{1896if (slide_val != 10)1897s_printf(lbl_text, "#FF3C28 %d GiB#", size >> 10);1898else1899s_printf(lbl_text, "#FF3C28 %d FULL#", size >> 10);1900}1901else1902s_printf(lbl_text, "#FFDD00 2x##FF3C28 %d#", size >> 11);1903lv_label_set_text(part_info.lbl_emu, lbl_text);1904}1905else1906{1907u32 emu_size = part_info.emu_size;19081909if (emu_size == max_emmc_size)1910emu_size = 10;1911else if (emu_size == 2 * max_emmc_size)1912emu_size = 20;1913else if (emu_size)1914{1915if (prev_emu_double)1916emu_size /= 2;1917emu_size -= rsvd_mb;1918emu_size /= 1024;1919emu_size -= 3;19201921if (prev_emu_double)1922emu_size += 11;1923}19241925int new_slider_val = emu_size;1926part_info.emu_double = prev_emu_double ? true : false;19271928lv_slider_set_value(slider, new_slider_val);1929}19301931_update_partition_bar();19321933return LV_RES_OK;1934}19351936static lv_res_t _action_slider_l4t(lv_obj_t *slider)1937{1938char lbl_text[64];19391940u32 size = (u32)lv_slider_get_value(slider) << 10;1941if (size < 4096)1942size = 0;1943else if (size < 8192)1944size = 8192;19451946s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - size - part_info.and_size;19471948// Sanitize sizes based on new HOS size.1949if (hos_size > HOS_MIN_SIZE_MB)1950{1951if (size <= 8192)1952lv_slider_set_value(slider, size >> 10);1953}1954else1955{1956size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - 2048;1957hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - size;1958if (hos_size < HOS_MIN_SIZE_MB || size < 8192)1959{1960lv_slider_set_value(slider, part_info.l4t_size >> 10);1961goto out;1962}1963lv_slider_set_value(slider, size >> 10);1964}19651966part_info.l4t_size = size;1967part_info.hos_size = hos_size;19681969s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10);1970lv_label_set_text(part_info.lbl_hos, lbl_text);1971lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);1972s_printf(lbl_text, "#00DDFF %d GiB#", size >> 10);1973lv_label_set_text(part_info.lbl_l4t, lbl_text);19741975_update_partition_bar();19761977out:1978return LV_RES_OK;1979}19801981static lv_res_t _action_slider_and(lv_obj_t *slider)1982{1983char lbl_text[64];19841985u32 user_size = (u32)lv_slider_get_value(slider) << 10;1986if (user_size < 2048)1987user_size = 0;1988else if (user_size < 4096)1989user_size = 4096;19901991u32 and_size = user_size ? (user_size + ANDROID_SYSTEM_SIZE_MB) : 0;1992s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;19931994// Sanitize sizes based on new HOS size.1995if (hos_size > HOS_MIN_SIZE_MB)1996{1997if (user_size <= 4096)1998lv_slider_set_value(slider, user_size >> 10);1999}2000else2001{2002and_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - 2048;2003hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;2004if (hos_size < HOS_MIN_SIZE_MB || and_size < 8192)2005{2006lv_slider_set_value(slider, part_info.and_size >> 10);2007goto out;2008}2009user_size = and_size - ANDROID_SYSTEM_SIZE_MB;2010lv_slider_set_value(slider, user_size >> 10);2011}20122013part_info.and_size = and_size;2014part_info.hos_size = hos_size;20152016s_printf(lbl_text, "#96FF00 %d GiB#", hos_size >> 10);2017lv_label_set_text(part_info.lbl_hos, lbl_text);2018lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);2019s_printf(lbl_text, "#FF8000 %d GiB#", user_size >> 10);2020lv_label_set_text(part_info.lbl_and, lbl_text);20212022_update_partition_bar();20232024out:2025return LV_RES_OK;2026}20272028static lv_res_t _mbox_check_files_total_size_option(lv_obj_t *btns, const char *txt)2029{2030// If "don't backup" button was pressed, disable backup/restore of files.2031if (!lv_btnm_get_pressed(btns))2032part_info.backup_possible = false;20332034mbox_action(btns, txt);20352036return LV_RES_INV;2037}20382039static void _create_mbox_check_files_total_size()2040{2041static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;2042static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;20432044// Set HOS bar style.2045lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);2046bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);2047bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;20482049// Set emuMMC bar style.2050lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);2051bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);2052bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;20532054// Set L4T bar style.2055lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);2056bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);2057bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;20582059// Set GPT bar style.2060lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);2061bar_and_ind.body.main_color = LV_COLOR_HEX(0xC000FF);2062bar_and_ind.body.grad_color = bar_and_ind.body.main_color;20632064// Set separator styles.2065lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);2066sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);2067sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;2068sep_emu_bg.body.radius = 0;2069lv_style_copy(&sep_l4t_bg, &sep_emu_bg);2070sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);2071sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;2072lv_style_copy(&sep_and_bg, &sep_emu_bg);2073sep_and_bg.body.main_color = LV_COLOR_HEX(0xC000FF);2074sep_and_bg.body.grad_color = sep_and_bg.body.main_color;20752076char *txt_buf = malloc(SZ_8K);20772078lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2079lv_obj_set_style(dark_bg, &mbox_darken);2080lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);20812082static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };2083static const char *mbox_btn_map2[] = { "\222Don't Backup", "\222OK", "" };2084lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);2085lv_mbox_set_recolor_text(mbox, true);2086lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);20872088lv_mbox_set_text(mbox, "Analyzing SD card usage. This might take a while...");20892090lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2091lv_obj_set_top(mbox, true);2092manual_system_maintenance(true);20932094char *path = malloc(0x1000);2095u32 total_files = 0;2096u32 total_size = 0;2097path[0] = 0;20982099// Check total size of files.2100int res = _stat_and_copy_files("sd:", NULL, path, &total_files, &total_size, NULL);21012102// Not more than 1.0GB.2103part_info.backup_possible = !res && !(total_size > (RAM_DISK_SZ - SZ_16M));21042105if (part_info.backup_possible)2106{2107s_printf(txt_buf,2108"#96FF00 The SD Card files will be backed up automatically!#\n"2109"#FFDD00 Any other partition will be wiped!#\n"2110"#00DDFF Total files:# %d, #00DDFF Total size:# %d MiB", total_files, total_size >> 20);2111lv_mbox_set_text(mbox, txt_buf);2112}2113else2114{2115lv_mbox_set_text(mbox,2116"#FFDD00 The SD Card cannot be backed up automatically!#\n"2117"#FFDD00 Any other partition will be also wiped!#\n\n"2118"You will be asked to back up your files later via UMS.");2119}21202121// Create container to keep content inside.2122lv_obj_t *h1 = lv_cont_create(mbox, NULL);2123lv_cont_set_fit(h1, false, true);2124lv_cont_set_style(h1, &lv_style_transp_tight);2125lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI * 3);21262127lv_obj_t *lbl_part = lv_label_create(h1, NULL);2128lv_label_set_recolor(lbl_part, true);2129lv_label_set_text(lbl_part, "#00DDFF Current MBR partition layout:#");21302131// Read current MBR.2132mbr_t mbr = { 0 };2133sdmmc_storage_read(&sd_storage, 0, 1, &mbr);21342135// Calculate MBR partitions size.2136total_size = (sd_storage.sec_cnt - AU_ALIGN_SECTORS) / SECTORS_PER_GB;2137u32 bar_hos_size = lv_obj_get_width(h1) * (mbr.partitions[0].size_sct / SECTORS_PER_GB) / total_size;2138u32 bar_emu_size = 0;2139for (u32 i = 1; i < 4; i++)2140if (mbr.partitions[i].type == 0xE0)2141bar_emu_size += mbr.partitions[i].size_sct;2142bar_emu_size = lv_obj_get_width(h1) * (bar_emu_size / SECTORS_PER_GB) / total_size;21432144u32 bar_l4t_size = 0;2145for (u32 i = 1; i < 4; i++)2146if (mbr.partitions[i].type == 0x83)2147bar_l4t_size += mbr.partitions[i].size_sct;2148bar_l4t_size = lv_obj_get_width(h1) * (bar_l4t_size / SECTORS_PER_GB) / total_size;21492150u32 bar_and_size = lv_obj_get_width(h1) - bar_hos_size - bar_emu_size - bar_l4t_size;21512152// Create HOS bar.2153lv_obj_t *bar_mbr_hos = lv_bar_create(h1, NULL);2154lv_obj_set_size(bar_mbr_hos, bar_hos_size, LV_DPI / 3);2155lv_bar_set_range(bar_mbr_hos, 0, 1);2156lv_bar_set_value(bar_mbr_hos, 1);2157lv_bar_set_style(bar_mbr_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);2158lv_obj_align(bar_mbr_hos, lbl_part, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);21592160// Create emuMMC bar.2161lv_obj_t *bar_mbr_emu = lv_bar_create(h1, bar_mbr_hos);2162lv_obj_set_size(bar_mbr_emu, bar_emu_size, LV_DPI / 3);2163lv_bar_set_style(bar_mbr_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);2164lv_obj_align(bar_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);21652166// Create L4T bar.2167lv_obj_t *bar_mbr_l4t = lv_bar_create(h1, bar_mbr_hos);2168lv_obj_set_size(bar_mbr_l4t, bar_l4t_size, LV_DPI / 3);2169lv_bar_set_style(bar_mbr_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);2170lv_obj_align(bar_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);21712172// Create GPT bar.2173lv_obj_t *bar_mbr_gpt = lv_bar_create(h1, bar_mbr_hos);2174lv_obj_set_size(bar_mbr_gpt, bar_and_size > 1 ? bar_and_size : 0, LV_DPI / 3);2175lv_bar_set_style(bar_mbr_gpt, LV_BAR_STYLE_INDIC, &bar_and_ind);2176lv_obj_align(bar_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);21772178// Create emuMMC separator.2179lv_obj_t *sep_mbr_emu = lv_cont_create(h1, NULL);2180lv_obj_set_size(sep_mbr_emu, bar_emu_size ? 8 : 0, LV_DPI / 3);2181lv_obj_set_style(sep_mbr_emu, &sep_emu_bg);2182lv_obj_align(sep_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);21832184// Create L4T separator.2185lv_obj_t *sep_mbr_l4t = lv_cont_create(h1, sep_mbr_emu);2186lv_obj_set_size(sep_mbr_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 3);2187lv_obj_set_style(sep_mbr_l4t, &sep_l4t_bg);2188lv_obj_align(sep_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);21892190// Create GPT separator.2191lv_obj_t *sep_mbr_gpt = lv_cont_create(h1, sep_mbr_emu);2192lv_obj_set_size(sep_mbr_gpt, bar_and_size ? (bar_and_size > 1 ? 8 : 0) : 0, LV_DPI / 3);2193lv_obj_set_style(sep_mbr_gpt, &sep_and_bg);2194lv_obj_align(sep_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);21952196// Print partition table info.2197s_printf(txt_buf,2198"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2199"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2200"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2201"Partition 3 - Type: %02x, Start: %08x, Size: %08x",2202mbr.partitions[0].type, mbr.partitions[0].start_sct, mbr.partitions[0].size_sct,2203mbr.partitions[1].type, mbr.partitions[1].start_sct, mbr.partitions[1].size_sct,2204mbr.partitions[2].type, mbr.partitions[2].start_sct, mbr.partitions[2].size_sct,2205mbr.partitions[3].type, mbr.partitions[3].start_sct, mbr.partitions[3].size_sct);22062207lv_obj_t *lbl_table = lv_label_create(h1, NULL);2208lv_label_set_style(lbl_table, &monospace_text);2209lv_label_set_text(lbl_table, txt_buf);2210lv_obj_align(lbl_table, h1, LV_ALIGN_IN_TOP_MID, 0, LV_DPI);22112212if (!part_info.backup_possible)2213lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);2214else2215lv_mbox_add_btns(mbox, mbox_btn_map2, _mbox_check_files_total_size_option);22162217lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);22182219free(txt_buf);2220free(path);2221}22222223static lv_res_t _action_fix_mbr(lv_obj_t *btn)2224{2225lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2226lv_obj_set_style(dark_bg, &mbox_darken);2227lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);22282229static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };2230lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);2231lv_mbox_set_recolor_text(mbox, true);22322233lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);2234lv_mbox_set_text(mbox, "#FF8000 Fix Hybrid MBR#");22352236lv_obj_t *lbl_status = lv_label_create(mbox, NULL);2237lv_label_set_recolor(lbl_status, true);22382239mbr_t mbr[2] = { 0 };2240gpt_t *gpt = zalloc(sizeof(gpt_t));2241gpt_header_t gpt_hdr_backup = { 0 };22422243bool has_mbr_attributes = false;2244bool hybrid_mbr_changed = false;2245bool gpt_partition_exists = false;22462247// Try to init sd card. No need for valid MBR.2248if (!sd_mount() && !sd_get_card_initialized())2249{2250lv_label_set_text(lbl_status, "#FFDD00 Failed to init SD!#");2251goto out;2252}22532254sdmmc_storage_read(&sd_storage, 0, 1, &mbr[0]);2255sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);22562257memcpy(&mbr[1], &mbr[0], sizeof(mbr_t));22582259sd_unmount();22602261// Check for secret MBR attributes.2262if (gpt->entries[0].part_guid[7])2263has_mbr_attributes = true;22642265// Check if there's a GPT Protective partition.2266for (u32 i = 0; i < 4; i++)2267{2268if (mbr[0].partitions[i].type == 0xEE)2269gpt_partition_exists = true;2270}22712272// Check if GPT is valid.2273if (!gpt_partition_exists || memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)2274{2275lv_label_set_text(lbl_status, "#FFDD00 Warning:# No valid GPT was found!");22762277gpt_partition_exists = false;22782279if (has_mbr_attributes)2280goto check_changes;2281else2282goto out;2283}22842285sdmmc_storage_read(&sd_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);22862287// Parse GPT.2288LIST_INIT(gpt_parsed);2289for (u32 i = 0; i < gpt->header.num_part_ents; i++)2290{2291emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t));22922293if (gpt->entries[i].lba_start < gpt->header.first_use_lba)2294continue;22952296part->index = i;2297part->lba_start = gpt->entries[i].lba_start;2298part->lba_end = gpt->entries[i].lba_end;22992300// ASCII conversion. Copy only the LSByte of the UTF-16LE name.2301for (u32 j = 0; j < 36; j++)2302part->name[j] = gpt->entries[i].name[j];2303part->name[35] = 0;23042305list_append(&gpt_parsed, &part->link);2306}23072308// Set FAT and emuMMC partitions.2309u32 mbr_idx = 1;2310bool found_hos_data = false;2311LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link)2312{2313// FatFS simple GPT found a fat partition, set it.2314if (sd_fs.part_type && !part->index)2315{2316mbr[1].partitions[0].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC;2317mbr[1].partitions[0].start_sct = part->lba_start;2318mbr[1].partitions[0].size_sct = (part->lba_end - part->lba_start + 1);2319}23202321// FatFS simple GPT didn't find a fat partition as the first one.2322if (!sd_fs.part_type && !found_hos_data && !strcmp(part->name, "hos_data"))2323{2324mbr[1].partitions[0].type = 0xC;2325mbr[1].partitions[0].start_sct = part->lba_start;2326mbr[1].partitions[0].size_sct = (part->lba_end - part->lba_start + 1);2327found_hos_data = true;2328}23292330// Set up to max 2 emuMMC partitions.2331if (!strcmp(part->name, "emummc") || !strcmp(part->name, "emummc2"))2332{2333mbr[1].partitions[mbr_idx].type = 0xE0;2334mbr[1].partitions[mbr_idx].start_sct = part->lba_start;2335mbr[1].partitions[mbr_idx].size_sct = (part->lba_end - part->lba_start + 1);2336mbr_idx++;2337}23382339// Total reached last slot.2340if (mbr_idx >= 3)2341break;2342}23432344emmc_gpt_free(&gpt_parsed);23452346// Set GPT protective partition.2347mbr[1].partitions[mbr_idx].type = 0xEE;2348mbr[1].partitions[mbr_idx].start_sct = 1;2349mbr[1].partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;23502351// Check for differences.2352for (u32 i = 1; i < 4; i++)2353{2354if ((mbr[0].partitions[i].type != mbr[1].partitions[i].type) ||2355(mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) ||2356(mbr[0].partitions[i].size_sct != mbr[1].partitions[i].size_sct))2357{2358hybrid_mbr_changed = true;2359break;2360}2361}23622363check_changes:2364if (!hybrid_mbr_changed && !has_mbr_attributes)2365{2366lv_label_set_text(lbl_status, "#96FF00 Warning:# The Hybrid MBR needs no change!#");2367goto out;2368}23692370char *txt_buf = malloc(SZ_16K);23712372// Current MBR info.2373s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n");2374s_printf(txt_buf + strlen(txt_buf),2375"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2376"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2377"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2378"Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n",2379mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct,2380mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct,2381mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct,2382mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct);23832384// New MBR info.2385s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n");2386s_printf(txt_buf + strlen(txt_buf),2387"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2388"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2389"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2390"Partition 3 - Type: %02x, Start: %08x, Size: %08x",2391mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct,2392mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct,2393mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct,2394mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct);23952396lv_label_set_text(lbl_status, txt_buf);2397lv_label_set_style(lbl_status, &monospace_text);23982399free(txt_buf);24002401lbl_status = lv_label_create(mbox, NULL);2402lv_label_set_recolor(lbl_status, true);2403lv_label_set_align(lbl_status, LV_LABEL_ALIGN_CENTER);24042405lv_label_set_text(lbl_status,2406"#FF8000 Warning: Do you really want to continue?!#\n\n"2407"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");24082409lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2410lv_obj_set_top(mbox, true);24112412manual_system_maintenance(true);24132414if (btn_wait() & BTN_POWER)2415{2416sd_mount();24172418// Write MBR.2419if (hybrid_mbr_changed)2420sdmmc_storage_write(&sd_storage, 0, 1, &mbr[1]);24212422// Fix MBR secret attributes.2423if (has_mbr_attributes)2424{2425// Clear secret attributes.2426gpt->entries[0].part_guid[7] = 0;24272428if (gpt_partition_exists)2429{2430// Fix CRC32s.2431u32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents;2432gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size);2433gpt->header.crc32 = 0; // Set to 0 for calculation.2434gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);24352436gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32;2437gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.2438gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);24392440// Write main GPT.2441u32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE);2442sdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt);24432444// Write backup GPT partition table.2445sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries);24462447// Write backup GPT header.2448sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);2449}2450else2451{2452// Only write the relevant sector if the only change is MBR attributes.2453sdmmc_storage_write(&sd_storage, 2, 1, &gpt->entries[0]);2454}2455}24562457sd_unmount();24582459lv_label_set_text(lbl_status, "#96FF00 The new Hybrid MBR was written successfully!#");2460}2461else2462lv_label_set_text(lbl_status, "#FFDD00 Warning: The Hybrid MBR Fix was canceled!#");24632464out:2465free(gpt);24662467lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);24682469lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2470lv_obj_set_top(mbox, true);24712472return LV_RES_OK;2473}24742475lv_res_t create_window_partition_manager(lv_obj_t *btn)2476{2477lv_obj_t *win = nyx_create_standard_window(SYMBOL_SD" Partition Manager");24782479lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR", _action_fix_mbr);24802481static lv_style_t bar_hos_bg, bar_emu_bg, bar_l4t_bg, bar_and_bg;2482static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;2483static lv_style_t bar_hos_btn, bar_emu_btn, bar_l4t_btn, bar_and_btn;2484static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;24852486// Set HOS bar styles.2487lv_style_copy(&bar_hos_bg, lv_theme_get_current()->bar.bg);2488bar_hos_bg.body.main_color = LV_COLOR_HEX(0x4A8000);2489bar_hos_bg.body.grad_color = bar_hos_bg.body.main_color;2490lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);2491bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);2492bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;2493lv_style_copy(&bar_hos_btn, lv_theme_get_current()->slider.knob);2494bar_hos_btn.body.main_color = LV_COLOR_HEX(0x77CC00);2495bar_hos_btn.body.grad_color = bar_hos_btn.body.main_color;24962497// Set eMUMMC bar styles.2498lv_style_copy(&bar_emu_bg, lv_theme_get_current()->bar.bg);2499bar_emu_bg.body.main_color = LV_COLOR_HEX(0x940F00);2500bar_emu_bg.body.grad_color = bar_emu_bg.body.main_color;2501lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);2502bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);2503bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;2504lv_style_copy(&bar_emu_btn, lv_theme_get_current()->slider.knob);2505bar_emu_btn.body.main_color = LV_COLOR_HEX(0xB31200);2506bar_emu_btn.body.grad_color = bar_emu_btn.body.main_color;2507lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);2508sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);2509sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;2510sep_emu_bg.body.radius = 0;25112512// Set L4T bar styles.2513lv_style_copy(&bar_l4t_bg, lv_theme_get_current()->bar.bg);2514bar_l4t_bg.body.main_color = LV_COLOR_HEX(0x006E80);2515bar_l4t_bg.body.grad_color = bar_l4t_bg.body.main_color;2516lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);2517bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);2518bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;2519lv_style_copy(&bar_l4t_btn, lv_theme_get_current()->slider.knob);2520bar_l4t_btn.body.main_color = LV_COLOR_HEX(0x00B1CC);2521bar_l4t_btn.body.grad_color = bar_l4t_btn.body.main_color;2522lv_style_copy(&sep_l4t_bg, &sep_emu_bg);2523sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);2524sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;25252526// Set Android bar styles.2527lv_style_copy(&bar_and_bg, lv_theme_get_current()->bar.bg);2528bar_and_bg.body.main_color = LV_COLOR_HEX(0x804000);2529bar_and_bg.body.grad_color = bar_and_bg.body.main_color;2530lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);2531bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000);2532bar_and_ind.body.grad_color = bar_and_ind.body.main_color;2533lv_style_copy(&bar_and_btn, lv_theme_get_current()->slider.knob);2534bar_and_btn.body.main_color = LV_COLOR_HEX(0xCC6600);2535bar_and_btn.body.grad_color = bar_and_btn.body.main_color;2536lv_style_copy(&sep_and_bg, &sep_emu_bg);2537sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000);2538sep_and_bg.body.grad_color = sep_and_bg.body.main_color;25392540lv_obj_t *sep = lv_label_create(win, NULL);2541lv_label_set_static_text(sep, "");2542lv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);25432544// Create container to keep content inside.2545lv_obj_t *h1 = lv_cont_create(win, NULL);2546lv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES - LV_DPI);25472548if (!sd_mount())2549{2550lv_obj_t *lbl = lv_label_create(h1, NULL);2551lv_label_set_recolor(lbl, true);2552lv_label_set_text(lbl, "#FFDD00 Failed to init SD!#");2553return LV_RES_OK;2554}25552556memset(&part_info, 0, sizeof(partition_ctxt_t));2557_create_mbox_check_files_total_size();25582559char *txt_buf = malloc(SZ_8K);25602561part_info.total_sct = sd_storage.sec_cnt;25622563// Align down total size to ensure alignment of all partitions after HOS one.2564part_info.alignment = part_info.total_sct - ALIGN_DOWN(part_info.total_sct, AU_ALIGN_SECTORS);2565part_info.total_sct -= part_info.alignment;25662567u32 extra_sct = AU_ALIGN_SECTORS + 0x400000; // Reserved 16MB alignment for FAT partition + 2GB.25682569// Set initial HOS partition size, so the correct cluster size can be selected.2570part_info.hos_size = (part_info.total_sct >> 11) - 16; // Important if there's no slider change.25712572// Check if eMMC should be 64GB (Aula).2573part_info.emmc_is_64gb = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA;25742575// Read current MBR.2576mbr_t mbr = { 0 };2577sdmmc_storage_read(&sd_storage, 0, 1, &mbr);25782579u32 bar_hos_size = lv_obj_get_width(h1);2580u32 bar_emu_size = 0;2581u32 bar_l4t_size = 0;2582u32 bar_and_size = 0;25832584lv_obj_t *lbl = lv_label_create(h1, NULL);2585lv_label_set_recolor(lbl, true);2586lv_label_set_text(lbl, "Choose #FFDD00 new# partition layout:");25872588// Create disk layout blocks.2589// HOS partition block.2590lv_obj_t *bar_hos = lv_bar_create(h1, NULL);2591lv_obj_set_size(bar_hos, bar_hos_size, LV_DPI / 2);2592lv_bar_set_range(bar_hos, 0, 1);2593lv_bar_set_value(bar_hos, 1);2594lv_bar_set_style(bar_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);2595lv_obj_align(bar_hos, lbl, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);2596part_info.bar_hos = bar_hos;25972598// emuMMC partition block.2599lv_obj_t *bar_emu = lv_bar_create(h1, bar_hos);2600lv_obj_set_size(bar_emu, bar_emu_size, LV_DPI / 2);2601lv_bar_set_style(bar_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);2602lv_obj_align(bar_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);2603part_info.bar_emu = bar_emu;26042605// L4T partition block.2606lv_obj_t *bar_l4t = lv_bar_create(h1, bar_hos);2607lv_obj_set_size(bar_l4t, bar_l4t_size, LV_DPI / 2);2608lv_bar_set_style(bar_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);2609lv_obj_align(bar_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);2610part_info.bar_l4t = bar_l4t;26112612// Android partition block.2613lv_obj_t *bar_and = lv_bar_create(h1, bar_hos);2614lv_obj_set_size(bar_and, bar_and_size, LV_DPI / 2);2615lv_bar_set_style(bar_and, LV_BAR_STYLE_INDIC, &bar_and_ind);2616lv_obj_align(bar_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);2617part_info.bar_and = bar_and;26182619// HOS partition block.2620lv_obj_t *sep_emu = lv_cont_create(h1, NULL);2621lv_cont_set_fit(sep_emu, false, false);2622lv_obj_set_size(sep_emu, 0, LV_DPI / 2); // 8.2623lv_obj_set_style(sep_emu, &sep_emu_bg);2624lv_obj_align(sep_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);2625part_info.sep_emu = sep_emu;26262627// Create disk layout blending separators.2628lv_obj_t *sep_l4t = lv_cont_create(h1, sep_emu);2629lv_obj_set_style(sep_l4t, &sep_l4t_bg);2630lv_obj_align(sep_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);2631part_info.sep_l4t = sep_l4t;26322633lv_obj_t *sep_and = lv_cont_create(h1, sep_emu);2634lv_obj_set_style(sep_and, &sep_and_bg);2635lv_obj_align(sep_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);2636part_info.sep_and = sep_and;26372638// Create slider type labels.2639lv_obj_t *lbl_hos = lv_label_create(h1, NULL);2640lv_label_set_recolor(lbl_hos, true);2641lv_label_set_static_text(lbl_hos, "#96FF00 "SYMBOL_DOT" HOS (FAT32):#");2642lv_obj_align(lbl_hos, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);26432644lv_obj_t *lbl_emu = lv_label_create(h1, lbl_hos);2645lv_label_set_static_text(lbl_emu, "#FF3C28 "SYMBOL_DOT" emuMMC (RAW):#");2646lv_obj_align(lbl_emu, lbl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);26472648lv_obj_t *lbl_l4t = lv_label_create(h1, lbl_hos);2649lv_label_set_static_text(lbl_l4t, "#00DDFF "SYMBOL_DOT" Linux (EXT4):#");2650lv_obj_align(lbl_l4t, lbl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);26512652lv_obj_t *lbl_and = lv_label_create(h1, lbl_hos);2653lv_label_set_static_text(lbl_and, "#FF8000 "SYMBOL_DOT" Android (USER):#");2654lv_obj_align(lbl_and, lbl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);26552656// Create HOS size slider. Non-interactive.2657lv_obj_t *slider_bar_hos = lv_bar_create(h1, NULL);2658lv_obj_set_size(slider_bar_hos, LV_DPI * 7, LV_DPI * 3 / 17);2659lv_bar_set_range(slider_bar_hos, 0, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);2660lv_bar_set_value(slider_bar_hos, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);2661lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_BG, &bar_hos_bg);2662lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_INDIC, &bar_hos_ind);2663lv_obj_align(slider_bar_hos, lbl_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 6 / 4, 0);2664part_info.slider_bar_hos = slider_bar_hos;26652666// Create emuMMC size slider.2667lv_obj_t *slider_emu = lv_slider_create(h1, NULL);2668lv_obj_set_size(slider_emu, LV_DPI * 7, LV_DPI / 3);2669lv_slider_set_range(slider_emu, 0, 20);2670lv_slider_set_value(slider_emu, 0);2671lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_BG, &bar_emu_bg);2672lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_INDIC, &bar_emu_ind);2673lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_KNOB, &bar_emu_btn);2674lv_obj_align(slider_emu, slider_bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 + 5);2675lv_slider_set_action(slider_emu, _action_slider_emu);2676part_info.slider_emu = slider_bar_hos;26772678// Create L4T size slider.2679lv_obj_t *slider_l4t = lv_slider_create(h1, NULL);2680lv_obj_set_size(slider_l4t, LV_DPI * 7, LV_DPI / 3);2681lv_slider_set_range(slider_l4t, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB);2682lv_slider_set_value(slider_l4t, 0);2683lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_BG, &bar_l4t_bg);2684lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_INDIC, &bar_l4t_ind);2685lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_KNOB, &bar_l4t_btn);2686lv_obj_align(slider_l4t, slider_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3);2687lv_slider_set_action(slider_l4t, _action_slider_l4t);2688part_info.slider_l4t = slider_l4t;26892690// Create Android size slider.2691lv_obj_t *slider_and = lv_slider_create(h1, NULL);2692lv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3);2693lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - (ANDROID_SYSTEM_SIZE_MB / 1024)); // Subtract android reserved size.2694lv_slider_set_value(slider_and, 0);2695lv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg);2696lv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind);2697lv_slider_set_style(slider_and, LV_SLIDER_STYLE_KNOB, &bar_and_btn);2698lv_obj_align(slider_and, slider_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3);2699lv_slider_set_action(slider_and, _action_slider_and);2700part_info.slider_and = slider_and;27012702// Create HOS size label.2703lv_obj_t *lbl_sl_hos = lv_label_create(h1, NULL);2704lv_label_set_recolor(lbl_sl_hos, true);2705s_printf(txt_buf, "#96FF00 %d GiB#", (part_info.total_sct - AU_ALIGN_SECTORS) >> 11 >> 10);2706lv_label_set_text(lbl_sl_hos, txt_buf);2707lv_obj_align(lbl_sl_hos, slider_bar_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 4 / 7, 0);2708part_info.lbl_hos = lbl_sl_hos;27092710// Create emuMMC size label.2711lv_obj_t *lbl_sl_emu = lv_label_create(h1, lbl_sl_hos);2712lv_label_set_text(lbl_sl_emu, "#FF3C28 0 GiB#");2713lv_obj_align(lbl_sl_emu, lbl_sl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);2714part_info.lbl_emu = lbl_sl_emu;27152716// Create L4T size label.2717lv_obj_t *lbl_sl_l4t = lv_label_create(h1, lbl_sl_hos);2718lv_label_set_text(lbl_sl_l4t, "#00DDFF 0 GiB#");2719lv_obj_align(lbl_sl_l4t, lbl_sl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);2720part_info.lbl_l4t = lbl_sl_l4t;27212722// Create Android size label.2723lv_obj_t *lbl_sl_and = lv_label_create(h1, lbl_sl_hos);2724lv_label_set_text(lbl_sl_and, "#FF8000 0 GiB#");2725lv_obj_align(lbl_sl_and, lbl_sl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);2726part_info.lbl_and = lbl_sl_and;27272728// Set partition manager notes.2729lv_obj_t *lbl_notes = lv_label_create(h1, NULL);2730lv_label_set_recolor(lbl_notes, true);2731lv_label_set_static_text(lbl_notes,2732"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"2733"Note 2: Resized emuMMC formats the USER partition. A save data manager can be used to move them over.\n"2734"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n");2735lv_label_set_style(lbl_notes, &hint_small_style);2736lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5);27372738// Create UMS button.2739lv_obj_t *btn1 = lv_btn_create(h1, NULL);2740lv_obj_t *label_btn = lv_label_create(btn1, NULL);2741lv_btn_set_fit(btn1, true, true);2742lv_label_set_static_text(label_btn, SYMBOL_USB" SD UMS");2743lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);2744lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_part_manager_ums_sd);27452746// Create Flash Linux button.2747btn_flash_l4t = lv_btn_create(h1, NULL);2748lv_obj_t *label_btn2 = lv_label_create(btn_flash_l4t, NULL);2749lv_btn_set_fit(btn_flash_l4t, true, true);2750lv_label_set_static_text(label_btn2, SYMBOL_DOWNLOAD" Flash Linux");2751lv_obj_align(btn_flash_l4t, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);2752lv_btn_set_action(btn_flash_l4t, LV_BTN_ACTION_CLICK, _action_check_flash_linux);27532754// Disable Flash Linux button if partition not found.2755u32 size_sct = _get_available_l4t_partition();2756if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)2757{2758lv_obj_set_click(btn_flash_l4t, false);2759lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);2760}27612762int part_type_and = _get_available_android_partition();27632764// Create Flash Android button.2765btn_flash_android = lv_btn_create(h1, NULL);2766label_btn = lv_label_create(btn_flash_android, NULL);2767lv_btn_set_fit(btn_flash_android, true, true);2768switch (part_type_and)2769{2770case 0: // Disable Flash Android button if partition not found.2771lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android");2772lv_obj_set_click(btn_flash_android, false);2773lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);2774break;2775case 1: // Android 10/11.2776lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 10/11");2777break;2778case 2: // Android 13+2779lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 13+");2780break;2781}2782lv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);2783lv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android);27842785// Create next step button.2786btn1 = lv_btn_create(h1, NULL);2787label_btn = lv_label_create(btn1, NULL);2788lv_btn_set_fit(btn1, true, true);2789lv_label_set_static_text(label_btn, SYMBOL_SD" Next Step");2790lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_RIGHT, 0, LV_DPI * 5);2791lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _create_mbox_partitioning_next);27922793free(txt_buf);27942795sd_unmount();27962797return LV_RES_OK;2798}279928002801