Path: blob/master/nyx/nyx_gui/frontend/gui_tools_partition_manager.c
2598 views
/*1* Copyright (c) 2019-2026 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 "fe_emummc_tools.h"23#include "gui_tools_partition_manager.h"24#include "../hos/hos.h"25#include <libs/fatfs/diskio.h>26#include <libs/lvgl/lvgl.h>2728#define SECTORS_PER_GB 0x2000002930#define AU_ALIGN_SECTORS 0x8000 // 16MB.31#define AU_ALIGN_BYTES (AU_ALIGN_SECTORS * SD_BLOCKSIZE)3233#define HOS_USER_SECTOR 0x53C00034#define HOS_FAT_MIN_SIZE_MB 204835#define HOS_USER_MIN_SIZE_MB 10243637#define EMU_SLIDER_MIN 038#define EMU_SLIDER_MAX 44 // 24 GB. Always an even number.39#define EMU_SLIDER_1X_MAX (EMU_SLIDER_MAX / 2)40#define EMU_SLIDER_1X_FULL EMU_SLIDER_1X_MAX41#define EMU_SLIDER_2X_MIN (EMU_SLIDER_1X_MAX + 1)42#define EMU_SLIDER_2X_FULL EMU_SLIDER_MAX43#define EMU_SLIDER_OFFSET 3 // Min 4GB.44#define EMU_RSVD_MB (4 + 4 + 16 + 8) // BOOT0 + BOOT1 + 16MB offset + 8MB alignment.4546#define EMU_32GB_FULL 29856 // Actual: 29820 MB.47#define EMU_64GB_FULL 59680 // Actual: 59640 MB.4849#define AND_SYS_SIZE_MB 6144 // 6 GB. Fits both Legacy (4912MB) and Dynamic (6144MB) partition schemes.5051extern volatile boot_cfg_t *b_cfg;52extern volatile nyx_storage_t *nyx_str;5354typedef struct _partition_ctxt_t55{56bool emmc;57sdmmc_storage_t *storage;5859u32 total_sct;60u32 alignment;61u32 emmc_size_mb;62int backup_possible;6364s32 hos_min_size;6566s32 hos_size;67u32 emu_size;68u32 l4t_size;69u32 and_size;7071bool emu_double;72bool emmc_is_64gb;7374bool and_dynamic;7576mbr_t mbr_old;7778lv_obj_t *bar_hos;79lv_obj_t *bar_emu;80lv_obj_t *bar_l4t;81lv_obj_t *bar_and;8283lv_obj_t *sep_emu;84lv_obj_t *sep_l4t;85lv_obj_t *sep_and;8687lv_obj_t *slider_bar_hos;8889lv_obj_t *cont_lbl;9091lv_obj_t *lbl_hos;92lv_obj_t *lbl_emu;93lv_obj_t *lbl_l4t;94lv_obj_t *lbl_and;9596lv_obj_t *partition_button;97} partition_ctxt_t;9899typedef struct _l4t_flasher_ctxt_t100{101u32 offset_sct;102u32 image_size_sct;103} l4t_flasher_ctxt_t;104105partition_ctxt_t part_info;106l4t_flasher_ctxt_t l4t_flash_ctxt;107108lv_obj_t *btn_flash_l4t;109lv_obj_t *btn_flash_android;110111static FRESULT _copy_file(const char *src, const char *dst, const char *path)112{113FIL fp_src;114FIL fp_dst;115FRESULT res;116117// Open file for reading.118f_chdrive(src);119res = f_open(&fp_src, path, FA_READ);120if (res != FR_OK)121return res;122123u32 file_bytes_left = f_size(&fp_src);124125// Open file for writing.126f_chdrive(dst);127f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);128f_lseek(&fp_dst, f_size(&fp_src));129f_lseek(&fp_dst, 0);130131while (file_bytes_left)132{133u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.134file_bytes_left -= chunk_size;135136// Copy file to buffer.137f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);138139// Write file to disk.140f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);141}142143f_close(&fp_dst);144f_chdrive(src);145f_close(&fp_src);146147return FR_OK;148}149150static int _stat_and_copy_files(const char *src, const char *dst, char *path, u32 *total_files, u32 *total_size, lv_obj_t **labels)151{152FRESULT res;153DIR dir;154u32 dirLength = 0;155static FILINFO fno;156157f_chdrive(src);158159// Open directory.160res = f_opendir(&dir, path);161if (res != FR_OK)162return res;163164if (labels)165lv_label_set_text(labels[0], path);166167dirLength = strlen(path);168169// Hard limit path to 1024 characters. Do not result to error.170if (dirLength > 1024)171goto out;172173for (;;)174{175// Clear file path.176path[dirLength] = 0;177178// Read a directory item.179res = f_readdir(&dir, &fno);180181// Break on error or end of dir.182if (res != FR_OK || fno.fname[0] == 0)183break;184185// Set new directory or file.186memcpy(&path[dirLength], "/", 1);187strcpy(&path[dirLength + 1], fno.fname);188189if (labels)190{191lv_label_set_text(labels[1], fno.fname);192manual_system_maintenance(true);193}194195// Copy file to destination disk.196if (!(fno.fattrib & AM_DIR))197{198u64 file_size = fno.fsize > RAMDISK_CLUSTER_SZ ? fno.fsize : RAMDISK_CLUSTER_SZ;199200// Check for FAT32 or total overflow.201if ((file_size + *total_size) > 0xFFFFFFFFu)202{203// Set size to > 1GB, skip next folders and return.204*total_size = SZ_2G;205res = -1;206break;207}208209*total_size += file_size;210*total_files += 1;211212// Create a copy to destination.213if (dst)214{215FIL fp_src;216FIL fp_dst;217u32 file_bytes_left = fno.fsize;218219// Open file for writing.220f_chdrive(dst);221f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);222f_lseek(&fp_dst, fno.fsize);223f_lseek(&fp_dst, 0);224225// Open file for reading.226f_chdrive(src);227f_open(&fp_src, path, FA_READ);228229while (file_bytes_left)230{231u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.232file_bytes_left -= chunk_size;233234// Copy file to buffer.235f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);236manual_system_maintenance(true);237238// Write file to disk.239f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);240}241242// Finalize copied file.243f_close(&fp_dst);244f_chdrive(dst);245f_chmod(path, fno.fattrib, 0xFF);246247f_chdrive(src);248f_close(&fp_src);249}250251// If total is > 1.2GB exit.252if (*total_size > (RAM_DISK_SZ - SZ_16M)) // Account for alignment.253{254// Skip next folders and return.255res = -1;256break;257}258}259else // It's a directory.260{261if (!memcmp("System Volume Information", fno.fname, 25))262continue;263264// Create folder to destination.265if (dst)266{267f_chdrive(dst);268f_mkdir(path);269f_chmod(path, fno.fattrib, 0xFF);270}271272// Enter the directory.273res = _stat_and_copy_files(src, dst, path, total_files, total_size, labels);274if (res != FR_OK)275break;276277if (labels)278{279// Clear folder path.280path[dirLength] = 0;281lv_label_set_text(labels[0], path);282}283}284}285286out:287f_closedir(&dir);288289return res;290}291292static void _create_gpt_partition(gpt_t *gpt, u8 *gpt_idx, u32 *curr_part_lba, u32 size_lba, const char *name, int name_size)293{294static const u8 linux_part_guid[] = { 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 };295296// Reset partition.297memset(&gpt->entries[*gpt_idx], 0, sizeof(gpt_entry_t));298299// Create GPT partition.300memcpy(gpt->entries[*gpt_idx].type_guid, linux_part_guid, 16);301302// Set randomly created GUID.303u8 random_number[SE_RNG_BLOCK_SIZE];304se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);305memcpy(gpt->entries[*gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);306307// Set partition start and end.308gpt->entries[*gpt_idx].lba_start = *curr_part_lba;309gpt->entries[*gpt_idx].lba_end = *curr_part_lba + size_lba - 1;310311// Set name.312u16 name_utf16[36] = {0};313u32 name_lenth = strlen(name);314for (u32 i = 0; i < name_lenth; i++)315name_utf16[i] = name[i];316memcpy(gpt->entries[*gpt_idx].name, name_utf16, name_lenth * sizeof(u16));317318// Wipe the first 1MB to sanitize it as raw-empty partition.319sdmmc_storage_write(part_info.storage, *curr_part_lba, 0x800, (void *)SDMMC_UPPER_BUFFER);320321// Prepare for next.322(*curr_part_lba) += size_lba;323(*gpt_idx)++;324}325326static void _sd_prepare_and_flash_mbr_gpt()327{328mbr_t mbr;329u8 random_number[SE_RNG_BLOCK_SIZE];330331// Read current MBR.332sdmmc_storage_read(&sd_storage, 0, 1, &mbr);333334// Copy over metadata if they exist.335if (*(u32 *)&part_info.mbr_old.bootstrap[0x80])336memcpy(&mbr.bootstrap[0x80], &part_info.mbr_old.bootstrap[0x80], 64);337if (*(u32 *)&part_info.mbr_old.bootstrap[0xE0])338memcpy(&mbr.bootstrap[0xE0], &part_info.mbr_old.bootstrap[0xE0], 208);339340// Clear the first 16MB.341memset((void *)SDMMC_UPPER_BUFFER, 0, AU_ALIGN_BYTES);342sdmmc_storage_write(&sd_storage, 0, AU_ALIGN_SECTORS, (void *)SDMMC_UPPER_BUFFER);343344// Set disk signature.345se_rng_pseudo(random_number, sizeof(u32));346memcpy(&mbr.signature, random_number, sizeof(u32));347348// FAT partition as first.349u8 mbr_idx = 1;350351// Apply L4T Linux second to MBR if no Android.352if (part_info.l4t_size && !part_info.and_size)353{354mbr.partitions[mbr_idx].type = 0x83; // Linux system partition.355mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);356mbr.partitions[mbr_idx].size_sct = part_info.l4t_size << 11;357sdmmc_storage_write(&sd_storage, mbr.partitions[mbr_idx].start_sct, 0x800, (void *)SDMMC_UPPER_BUFFER); // Clear the first 1MB.358mbr_idx++;359}360361// emuMMC goes second or third. Next to L4T if no Android.362if (part_info.emu_size)363{364mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.365mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);366367if (!part_info.emu_double)368mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 11) - 0x800; // Reserve 1MB.369else370{371mbr.partitions[mbr_idx].size_sct = part_info.emu_size << 10;372mbr_idx++;373374// 2nd emuMMC.375mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.376mbr.partitions[mbr_idx].start_sct = mbr.partitions[mbr_idx - 1].start_sct + (part_info.emu_size << 10);377mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 10) - 0x800; // Reserve 1MB.378}379mbr_idx++;380}381382if (part_info.and_size)383{384gpt_t *gpt = zalloc(sizeof(gpt_t));385gpt_header_t gpt_hdr_backup = { 0 };386387// Set GPT protective partition in MBR.388mbr.partitions[mbr_idx].type = 0xEE;389mbr.partitions[mbr_idx].start_sct = 1;390mbr.partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;391mbr_idx++;392393// Set GPT header.394memcpy(&gpt->header.signature, "EFI PART", 8);395gpt->header.revision = 0x10000;396gpt->header.size = 92;397gpt->header.my_lba = 1;398gpt->header.alt_lba = sd_storage.sec_cnt - 1;399gpt->header.first_use_lba = (sizeof(mbr_t) + sizeof(gpt_t)) >> 9;400gpt->header.last_use_lba = sd_storage.sec_cnt - 0x800 - 1; // sd_storage.sec_cnt - 33 is start of backup gpt partition entries.401se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);402memcpy(gpt->header.disk_guid, random_number, 10);403memcpy(gpt->header.disk_guid + 10, "NYXGPT", 6);404gpt->header.part_ent_lba = 2;405gpt->header.part_ent_size = 128;406407// Set FAT GPT partition manually.408const u8 basic_part_guid[] = { 0xA2, 0xA0, 0xD0, 0xEB, 0xE5, 0xB9, 0x33, 0x44, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 };409memcpy(gpt->entries[0].type_guid, basic_part_guid, 16);410se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);411memcpy(gpt->entries[0].part_guid, random_number, SE_RNG_BLOCK_SIZE);412413// Clear non-standard Windows MBR attributes. bit4: Read only, bit5: Shadow copy, bit6: Hidden, bit7: No drive letter.414gpt->entries[0].part_guid[7] = 0;415416gpt->entries[0].lba_start = mbr.partitions[0].start_sct;417gpt->entries[0].lba_end = mbr.partitions[0].start_sct + mbr.partitions[0].size_sct - 1;418memcpy(gpt->entries[0].name, (u16[]) { 'h', 'o', 's', '_', 'd', 'a', 't', 'a' }, 16);419420// Set the rest of GPT partitions.421u8 gpt_idx = 1;422u32 curr_part_lba = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);423424// L4T partition.425if (part_info.l4t_size)426_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, part_info.l4t_size << 11, "l4t", 6);427428if (part_info.and_dynamic)429{430// Android Linux Kernel partition. 64MB.431_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "boot", 8);432433// Android Recovery partition. 64MB.434_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "recovery", 16);435436// Android Device Tree Reference partition. 1MB.437_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "dtb", 6);438439// Android Misc partition. 3MB.440_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "misc", 8);441442// Android Cache partition. 60MB.443_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1E000, "cache", 10);444445// Android Super dynamic partition. 5952MB.446_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xBA0000, "super", 10);447448// Android Userdata partition.449u32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).450if (!part_info.emu_size)451uda_size -= 0x800; // Reserve 1MB.452_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "userdata", 16);453}454else455{456// Android Vendor partition. 1GB457_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, "vendor", 12);458459// Android System partition. 3GB.460_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, "APP", 6);461462// Android Linux Kernel partition. 32MB.463_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x10000, "LNX", 6);464465// Android Recovery partition. 64MB.466_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "SOS", 6);467468// Android Device Tree Reference partition. 1MB.469_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "DTB", 6);470471// Android Encryption partition. 16MB.472// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.473sdmmc_storage_write(&sd_storage, curr_part_lba, 0x8000, (void *)SDMMC_UPPER_BUFFER); // Clear the whole of it.474_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x8000, "MDA", 6);475476// Android Cache partition. 700MB.477_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, "CAC", 6);478479// Android Misc partition. 3MB.480_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "MSC", 6);481482// Android Userdata partition.483u32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).484if (!part_info.emu_size)485uda_size -= 0x800; // Reserve 1MB.486_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "UDA", 6);487}488489// Handle emuMMC partitions manually.490if (part_info.emu_size)491{492// Set 1st emuMMC.493u8 emu_part_guid[] = { 0x00, 0x7E, 0xCA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'e', 'm', 'u', 'M', 'M', 'C' };494memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);495se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);496memcpy(gpt->entries[gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);497gpt->entries[gpt_idx].lba_start = curr_part_lba;498if (!part_info.emu_double)499gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 11) - 0x800 - 1; // Reserve 1MB.500else501gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 1;502memcpy(gpt->entries[gpt_idx].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12);503gpt_idx++;504505// Set 2nd emuMMC.506if (part_info.emu_double)507{508curr_part_lba += (part_info.emu_size << 10);509memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);510se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);511memcpy(gpt->entries[gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);512gpt->entries[gpt_idx].lba_start = curr_part_lba;513gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 0x800 - 1; // Reserve 1MB.514memcpy(gpt->entries[gpt_idx].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c', '2' }, 14);515gpt_idx++;516}517}518519// Set final GPT header parameters.520gpt->header.num_part_ents = gpt_idx;521gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);522gpt->header.crc32 = 0; // Set to 0 for calculation.523gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);524525// Set final backup GPT header parameters.526memcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));527gpt_hdr_backup.my_lba = sd_storage.sec_cnt - 1;528gpt_hdr_backup.alt_lba = 1;529gpt_hdr_backup.part_ent_lba = sd_storage.sec_cnt - 33;530gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.531gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);532533// Write main GPT.534sdmmc_storage_write(&sd_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);535536// Write backup GPT partition table.537sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);538539// Write backup GPT header.540sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);541542free(gpt);543}544545// Write MBR.546sdmmc_storage_write(&sd_storage, 0, 1, &mbr);547}548549static int _emmc_prepare_and_flash_mbr_gpt()550{551gpt_t *gpt = zalloc(sizeof(gpt_t));552gpt_header_t gpt_hdr_backup = { 0 };553554// Read main GPT.555sdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt);556557// Set GPT header.558gpt->header.alt_lba = emmc_storage.sec_cnt - 1;559gpt->header.last_use_lba = emmc_storage.sec_cnt - 0x800 - 1; // emmc_storage.sec_cnt - 33 is start of backup gpt partition entries.560561// Calculate HOS USER partition562u32 part_rsvd_size = (part_info.l4t_size << 11) + (part_info.and_size << 11);563part_rsvd_size += part_rsvd_size ? part_info.alignment : 0x800; // Only reserve 1MB if no extra partitions.564u32 hos_user_size = emmc_storage.sec_cnt - HOS_USER_SECTOR - part_rsvd_size;565566// Get HOS USER partition index.567LIST_INIT(gpt_emmc);568emmc_gpt_parse(&gpt_emmc);569emmc_part_t *user_part = emmc_part_find(&gpt_emmc, "USER");570if (!user_part)571{572emmc_gpt_free(&gpt_emmc);573free(gpt);574575return 1;576}577u8 gpt_idx = user_part->index;578emmc_gpt_free(&gpt_emmc);579580// HOS USER partition.581u32 curr_part_lba = gpt->entries[gpt_idx].lba_start;582gpt->entries[gpt_idx].lba_end = curr_part_lba + hos_user_size - 1;583584curr_part_lba += hos_user_size;585gpt_idx++;586587// L4T partition.588if (part_info.l4t_size)589{590u32 l4t_size = part_info.l4t_size << 11;591if (!part_info.and_size)592l4t_size -= 0x800; // Reserve 1MB.593_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, l4t_size, "l4t", 6);594}595596if (part_info.and_size && part_info.and_dynamic)597{598// Android Linux Kernel partition. 64MB.599_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "boot", 8);600601// Android Recovery partition. 64MB.602_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "recovery", 16);603604// Android Device Tree Reference partition. 1MB.605_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "dtb", 6);606607// Android Misc partition. 3MB.608_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "misc", 8);609610// Android Cache partition. 60MB.611_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1E000, "cache", 10);612613// Android Super dynamic partition. 5952MB.614_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xBA0000, "super", 10);615616// Android Userdata partition.617u32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).618uda_size -= 0x800; // Reserve 1MB.619_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "userdata", 16);620}621else if (part_info.and_size)622{623// Android Vendor partition. 1GB624_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, "vendor", 12);625626// Android System partition. 3GB.627_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, "APP", 6);628629// Android Linux Kernel partition. 32MB.630_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x10000, "LNX", 6);631632// Android Recovery partition. 64MB.633_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "SOS", 6);634635// Android Device Tree Reference partition. 1MB.636_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "DTB", 6);637638// Android Encryption partition. 16MB.639// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.640sdmmc_storage_write(&emmc_storage, curr_part_lba, 0x8000, (void *)SDMMC_UPPER_BUFFER); // Clear the whole of it.641_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x8000, "MDA", 6);642643// Android Cache partition. 700MB.644_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, "CAC", 6);645646// Android Misc partition. 3MB.647_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "MSC", 6);648649// Android Userdata partition.650u32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).651uda_size -= 0x800; // Reserve 1MB.652_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "UDA", 6);653}654655// Clear the rest of GPT partition table.656for (u32 i = gpt_idx; i < 128; i++)657memset(&gpt->entries[i], 0, sizeof(gpt_entry_t));658659// Set final GPT header parameters.660gpt->header.num_part_ents = gpt_idx;661gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);662gpt->header.crc32 = 0; // Set to 0 for calculation.663gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);664665// Set final backup GPT header parameters.666memcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));667gpt_hdr_backup.my_lba = emmc_storage.sec_cnt - 1;668gpt_hdr_backup.alt_lba = 1;669gpt_hdr_backup.part_ent_lba = emmc_storage.sec_cnt - 33;670gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.671gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);672673// Write main GPT.674sdmmc_storage_write(&emmc_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);675676// Write backup GPT partition table.677sdmmc_storage_write(&emmc_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);678679// Write backup GPT header.680sdmmc_storage_write(&emmc_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);681682// Clear nand patrol.683u8 *buf = (u8 *)gpt;684memset(buf, 0, EMMC_BLOCKSIZE);685emmc_set_partition(EMMC_BOOT0);686sdmmc_storage_write(&emmc_storage, NAND_PATROL_SECTOR, 1, buf);687emmc_set_partition(EMMC_GPP);688689free(gpt);690691return 0;692}693694static lv_res_t _action_part_manager_ums_sd(lv_obj_t *btn)695{696action_ums_sd(NULL);697698// Close and reopen partition manager.699lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK);700close_btn_action(close_btn);701lv_obj_del(ums_mbox);702create_window_sd_partition_manager(NULL);703704return LV_RES_INV;705}706707static lv_res_t _action_delete_linux_installer_files(lv_obj_t * btns, const char * txt)708{709710int btn_idx = lv_btnm_get_pressed(btns);711712// Delete parent mbox.713mbox_action(btns, txt);714715// Flash Linux.716if (!btn_idx)717{718char path[128];719720sd_mount();721722strcpy(path, "switchroot/install/l4t.");723724// Delete all l4t.xx files.725u32 idx = 0;726while (true)727{728if (idx < 10)729{730path[23] = '0';731itoa(idx, &path[23 + 1], 10);732}733else734itoa(idx, &path[23], 10);735736if (!f_stat(path, NULL))737{738f_unlink(path);739}740else741break;742743idx++;744}745746sd_unmount();747}748749return LV_RES_INV;750}751752static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt)753{754int btn_idx = lv_btnm_get_pressed(btns);755756// Delete parent mbox.757mbox_action(btns, txt);758759bool succeeded = false;760761if (btn_idx)762return LV_RES_INV;763764// Flash Linux.765lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);766lv_obj_set_style(dark_bg, &mbox_darken);767lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);768769static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };770static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "" };771lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);772lv_mbox_set_recolor_text(mbox, true);773lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);774775lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");776777lv_obj_t *lbl_status = lv_label_create(mbox, NULL);778lv_label_set_recolor(lbl_status, true);779lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux...");780781// Create container to keep content inside.782lv_obj_t *h1 = lv_cont_create(mbox, NULL);783lv_cont_set_fit(h1, true, true);784lv_cont_set_style(h1, &lv_style_transp_tight);785786lv_obj_t *bar = lv_bar_create(h1, NULL);787lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5);788lv_bar_set_range(bar, 0, 100);789lv_bar_set_value(bar, 0);790791lv_obj_t *label_pct = lv_label_create(h1, NULL);792lv_label_set_recolor(label_pct, true);793lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%");794lv_label_set_style(label_pct, lv_theme_get_current()->label.prim);795lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);796797lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);798lv_obj_set_top(mbox, true);799800sd_mount();801if (part_info.emmc)802emmc_initialize(false);803804int res = 0;805char *path = malloc(1024);806char *txt_buf = malloc(SZ_4K);807strcpy(path, "switchroot/install/l4t.00");808u32 path_len = strlen(path) - 2;809810FIL fp;811812res = f_open(&fp, path, FA_READ);813if (res)814{815lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!");816817goto exit;818}819820u64 fileSize = (u64)f_size(&fp);821822u32 num = 0;823u32 pct = 0;824u32 lba_curr = 0;825u32 bytesWritten = 0;826u32 currPartIdx = 0;827u32 prevPct = 200;828int retryCount = 0;829u32 total_size_sct = l4t_flash_ctxt.image_size_sct;830831u8 *buf = (u8 *)MIXD_BUF_ALIGNED;832DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);833834// Start flashing L4T.835while (total_size_sct > 0)836{837// 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.838if (bytesWritten >= fileSize)839{840// If we have more bytes written then close the file pointer and increase the part index we are using841f_close(&fp);842free(clmt);843memset(&fp, 0, sizeof(fp));844currPartIdx++;845846if (currPartIdx < 10)847{848path[path_len] = '0';849itoa(currPartIdx, &path[path_len + 1], 10);850}851else852itoa(currPartIdx, &path[path_len], 10);853854// Try to open the next file part855res = f_open(&fp, path, FA_READ);856if (res)857{858s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx);859lv_label_set_text(lbl_status, txt_buf);860manual_system_maintenance(true);861862goto exit;863}864fileSize = (u64)f_size(&fp);865bytesWritten = 0;866clmt = f_expand_cltbl(&fp, SZ_4M, 0);867}868869retryCount = 0;870num = MIN(total_size_sct, 8192);871872// Read next data block from SD.873res = f_read_fast(&fp, buf, num << 9);874manual_system_maintenance(false);875876if (res)877{878lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!");879manual_system_maintenance(true);880881f_close(&fp);882free(clmt);883goto exit;884}885886// Write data block to L4T partition.887res = !sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);888889manual_system_maintenance(false);890891// If failed, retry 3 more times.892while (res)893{894msleep(150);895manual_system_maintenance(true);896897if (retryCount >= 3)898{899lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!");900manual_system_maintenance(true);901902f_close(&fp);903free(clmt);904goto exit;905}906907res = !sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);908manual_system_maintenance(false);909}910911// Update completion percentage.912pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct;913if (pct != prevPct)914{915lv_bar_set_value(bar, pct);916s_printf(txt_buf, " #DDDDDD "SYMBOL_DOT"# %d%%", pct);917lv_label_set_text(label_pct, txt_buf);918manual_system_maintenance(true);919prevPct = pct;920}921922lba_curr += num;923total_size_sct -= num;924bytesWritten += num * EMMC_BLOCKSIZE;925}926lv_bar_set_value(bar, 100);927lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%");928manual_system_maintenance(true);929930// Restore operation ended successfully.931f_close(&fp);932free(clmt);933934succeeded = true;935936exit:937free(path);938free(txt_buf);939940if (!succeeded)941lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);942else943lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files);944lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);945946sd_unmount();947if (part_info.emmc)948emmc_end();949950return LV_RES_INV;951}952953static u32 _get_available_l4t_partition()954{955mbr_t mbr = { 0 };956gpt_t *gpt = zalloc(sizeof(gpt_t));957958memset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t));959960// Read MBR.961sdmmc_storage_read(part_info.storage, 0, 1, &mbr);962963// Read main GPT.964sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);965966// Search for a suitable partition.967u32 size_sct = 0;968if (!memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)969{970for (u32 i = 0; i < gpt->header.num_part_ents; i++)971{972if (!memcmp(gpt->entries[i].name, (u16[]) { 'l', '4', 't' }, 6))973{974l4t_flash_ctxt.offset_sct = gpt->entries[i].lba_start;975size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;976break;977}978}979}980else981{982for (u32 i = 1; i < 4; i++)983{984if (mbr.partitions[i].type == 0x83)985{986l4t_flash_ctxt.offset_sct = mbr.partitions[i].start_sct;987size_sct = mbr.partitions[i].size_sct;988break;989}990}991}992993free(gpt);994995return size_sct;996}997998static int _get_available_android_partition()999{1000gpt_t *gpt = zalloc(sizeof(gpt_t));10011002// Read main GPT.1003sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);10041005// Check if GPT.1006if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)1007goto out;10081009// Find kernel partition.1010for (u32 i = 0; i < gpt->header.num_part_ents; i++)1011{1012if (gpt->entries[i].lba_start)1013{1014int found = !memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8) ? 2 : 0;1015found |= !memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' }, 6) ? 1 : 0;10161017if (found)1018{1019free(gpt);10201021return found;1022}1023}1024}10251026out:1027free(gpt);10281029return false;1030}10311032static lv_res_t _action_check_flash_linux(lv_obj_t *btn)1033{1034FILINFO fno;1035char path[128];10361037lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1038lv_obj_set_style(dark_bg, &mbox_darken);1039lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);10401041static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1042static const char *mbox_btn_map2[] = { "\222Continue", "\222Cancel", "" };1043lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1044lv_mbox_set_recolor_text(mbox, true);1045lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);10461047lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");10481049lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1050lv_label_set_recolor(lbl_status, true);1051lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");10521053lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1054lv_obj_set_top(mbox, true);10551056manual_system_maintenance(true);10571058sd_mount();1059if (part_info.emmc)1060emmc_initialize(false);10611062// Check if L4T image exists.1063strcpy(path, "switchroot/install/l4t.00");1064if (f_stat(path, NULL))1065{1066lv_label_set_text(lbl_status, "#FFDD00 Error:# Installation files not found!");1067goto error;1068}10691070// Find an applicable partition for L4T.1071u32 size_sct = _get_available_l4t_partition();1072if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)1073{1074lv_label_set_text(lbl_status, "#FFDD00 Error:# No partition found!");1075goto error;1076}10771078u32 idx = 0;1079path[23] = 0;10801081// Validate L4T images and consolidate their info.1082while (true)1083{1084if (idx < 10)1085{1086path[23] = '0';1087itoa(idx, &path[23 + 1], 10);1088}1089else1090itoa(idx, &path[23], 10);10911092// Check for alignment.1093if (f_stat(path, &fno))1094break;10951096// Check if current part is unaligned.1097if ((u64)fno.fsize % SZ_4M)1098{1099// Get next part filename.1100idx++;1101if (idx < 10)1102{1103path[23] = '0';1104itoa(idx, &path[23 + 1], 10);1105}1106else1107itoa(idx, &path[23], 10);11081109// If it exists, unaligned size for current part is not permitted.1110if (!f_stat(path, NULL)) // NULL: Don't override current part fs info.1111{1112lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!");1113goto error;1114}11151116// Last part. Align size to LBA (SD_BLOCKSIZE).1117fno.fsize = ALIGN((u64)fno.fsize, SD_BLOCKSIZE);1118idx--;1119}1120l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9;11211122idx++;1123}11241125// Check if image size is bigger than the partition available.1126if (l4t_flash_ctxt.image_size_sct > size_sct)1127{1128lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is bigger than the partition!");1129goto error;1130}11311132char *txt_buf = malloc(SZ_4K);1133s_printf(txt_buf,1134"#C7EA46 Status:# Found installation files and partition.\n"1135"#00DDFF Offset:# %08x, #00DDFF Size:# %X, #00DDFF Image size:# %d MiB\n"1136"\nDo you want to continue?", l4t_flash_ctxt.offset_sct, size_sct, l4t_flash_ctxt.image_size_sct >> 11);1137lv_label_set_text(lbl_status, txt_buf);1138free(txt_buf);1139lv_mbox_add_btns(mbox, mbox_btn_map2, _action_flash_linux_data);1140goto exit;11411142error:1143lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);11441145exit:1146lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);11471148sd_unmount();1149if (part_info.emmc)1150emmc_end();11511152return LV_RES_OK;1153}11541155static lv_res_t _action_reboot_recovery(lv_obj_t * btns, const char * txt)1156{1157int btn_idx = lv_btnm_get_pressed(btns);11581159// Delete parent mbox.1160mbox_action(btns, txt);11611162if (!btn_idx)1163{1164// Set custom reboot type to Android Recovery.1165PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY;11661167// Enable hekate boot configuration.1168b_cfg->boot_cfg = BOOT_CFG_FROM_ID | BOOT_CFG_AUTOBOOT_EN;11691170// Set id to Android.1171strcpy((char *)b_cfg->id, "SWANDR");11721173void (*main_ptr)() = (void *)nyx_str->hekate;11741175// Deinit hardware.1176sd_end();1177hw_deinit(false);11781179// Chainload to hekate main.1180(*main_ptr)();1181}11821183return LV_RES_INV;1184}11851186static lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt)1187{1188int btn_idx = lv_btnm_get_pressed(btns);1189bool boot_recovery = false;11901191// Delete parent mbox.1192mbox_action(btns, txt);11931194if (btn_idx)1195return LV_RES_INV;11961197// Flash Android components.1198char path[128];1199gpt_t *gpt = zalloc(sizeof(gpt_t));1200char *txt_buf = malloc(SZ_4K);12011202lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1203lv_obj_set_style(dark_bg, &mbox_darken);1204lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);12051206static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1207static const char *mbox_btn_map2[] = { "\222Continue", "\222No", "" };1208lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1209lv_mbox_set_recolor_text(mbox, true);1210lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);12111212lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");12131214lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1215lv_label_set_recolor(lbl_status, true);1216lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");12171218lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1219lv_obj_set_top(mbox, true);12201221manual_system_maintenance(true);12221223sd_mount();1224if (part_info.emmc)1225emmc_initialize(false);12261227// Read main GPT.1228sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);12291230// Validate GPT header.1231if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)1232{1233lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!");1234goto error;1235}12361237u32 offset_sct = 0;1238u32 size_sct = 0;12391240// Check if Kernel image should be flashed.1241strcpy(path, "switchroot/install/boot.img");1242if (f_stat(path, NULL))1243{1244s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n");1245goto boot_img_not_found;1246}12471248// Find Kernel partition.1249for (u32 i = 0; i < gpt->header.num_part_ents; i++)1250{1251if (!memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' }, 6) ||1252!memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8))1253{1254offset_sct = gpt->entries[i].lba_start;1255size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1256break;1257}1258}12591260// Flash Kernel.1261if (offset_sct && size_sct)1262{1263u32 file_size = 0;1264u8 *buf = sd_file_read(path, &file_size);12651266if (file_size % 0x200)1267{1268file_size = ALIGN(file_size, 0x200);1269u8 *buf_tmp = zalloc(file_size);1270memcpy(buf_tmp, buf, file_size);1271free(buf);1272buf = buf_tmp;1273}12741275if ((file_size >> 9) > size_sct)1276s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n");1277else1278{1279sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);12801281s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n");1282f_unlink(path);1283}12841285free(buf);1286}1287else1288s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n");12891290boot_img_not_found:1291lv_label_set_text(lbl_status, txt_buf);1292manual_system_maintenance(true);12931294// Check if Recovery should be flashed.1295strcpy(path, "switchroot/install/recovery.img");1296if (f_stat(path, NULL))1297{1298// Not found, try twrp.img instead.1299strcpy(path, "switchroot/install/twrp.img");1300if (f_stat(path, NULL))1301{1302strcat(txt_buf, "#FF8000 Warning:# Recovery image not found!\n");1303goto recovery_not_found;1304}1305}13061307offset_sct = 0;1308size_sct = 0;13091310// Find Recovery partition.1311for (u32 i = 0; i < gpt->header.num_part_ents; i++)1312{1313if (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' }, 6) ||1314!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))1315{1316offset_sct = gpt->entries[i].lba_start;1317size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1318break;1319}1320}13211322// Flash Recovery.1323if (offset_sct && size_sct)1324{1325u32 file_size = 0;1326u8 *buf = sd_file_read(path, &file_size);13271328if (file_size % 0x200)1329{1330file_size = ALIGN(file_size, 0x200);1331u8 *buf_tmp = zalloc(file_size);1332memcpy(buf_tmp, buf, file_size);1333free(buf);1334buf = buf_tmp;1335}13361337if ((file_size >> 9) > size_sct)1338strcat(txt_buf, "#FF8000 Warning:# Recovery image too big!\n");1339else1340{1341sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);1342strcat(txt_buf, "#C7EA46 Success:# Recovery image flashed!\n");1343f_unlink(path);1344}13451346free(buf);1347}1348else1349strcat(txt_buf, "#FF8000 Warning:# Recovery partition not found!\n");13501351recovery_not_found:1352lv_label_set_text(lbl_status, txt_buf);1353manual_system_maintenance(true);13541355// Check if Device Tree should be flashed.1356strcpy(path, "switchroot/install/nx-plat.dtimg");1357if (f_stat(path, NULL))1358{1359strcpy(path, "switchroot/install/tegra210-icosa.dtb");1360if (f_stat(path, NULL))1361{1362strcat(txt_buf, "#FF8000 Warning:# DTB image not found!");1363goto dtb_not_found;1364}1365}13661367offset_sct = 0;1368size_sct = 0;13691370// Find Device Tree partition.1371for (u32 i = 0; i < gpt->header.num_part_ents; i++)1372{1373if (!memcmp(gpt->entries[i].name, (u16[]) { 'D', 'T', 'B' }, 6) ||1374!memcmp(gpt->entries[i].name, (u16[]) { 'd', 't', 'b' }, 6))1375{1376offset_sct = gpt->entries[i].lba_start;1377size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1378break;1379}1380}13811382// Flash Device Tree.1383if (offset_sct && size_sct)1384{1385u32 file_size = 0;1386u8 *buf = sd_file_read(path, &file_size);13871388if (file_size % 0x200)1389{1390file_size = ALIGN(file_size, 0x200);1391u8 *buf_tmp = zalloc(file_size);1392memcpy(buf_tmp, buf, file_size);1393free(buf);1394buf = buf_tmp;1395}13961397if ((file_size >> 9) > size_sct)1398strcat(txt_buf, "#FF8000 Warning:# DTB image too big!");1399else1400{1401sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);1402strcat(txt_buf, "#C7EA46 Success:# DTB image flashed!");1403f_unlink(path);1404}14051406free(buf);1407}1408else1409strcat(txt_buf, "#FF8000 Warning:# DTB partition not found!");14101411dtb_not_found:1412lv_label_set_text(lbl_status, txt_buf);14131414// Check if Recovery is flashed unconditionally.1415u8 *rec = malloc(SD_BLOCKSIZE);1416for (u32 i = 0; i < gpt->header.num_part_ents; i++)1417{1418if (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' }, 6) ||1419!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))1420{1421sdmmc_storage_read(part_info.storage, gpt->entries[i].lba_start, 1, rec);1422if (!memcmp(rec, "ANDROID", 7))1423boot_recovery = true;1424break;1425}1426}1427free(rec);14281429error:1430if (boot_recovery)1431{1432// If a Recovery partition was found, ask user if rebooting into it is wanted.1433strcat(txt_buf,"\n\nDo you want to reboot into Recovery\nto finish Android installation?");1434lv_label_set_text(lbl_status, txt_buf);1435lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_recovery);1436}1437else1438lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);14391440lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);14411442free(txt_buf);1443free(gpt);14441445sd_unmount();1446if (part_info.emmc)1447emmc_end();14481449return LV_RES_INV;1450}14511452static lv_res_t _action_flash_android(lv_obj_t *btn)1453{1454lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1455lv_obj_set_style(dark_bg, &mbox_darken);1456lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);14571458static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" };1459lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1460lv_mbox_set_recolor_text(mbox, true);1461lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);14621463lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");14641465lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1466lv_label_set_recolor(lbl_status, true);1467lv_label_set_text(lbl_status,1468"This will flash #C7EA46 Kernel#, #C7EA46 DTB# and #C7EA46 Recovery# if found.\n"1469"These will be deleted after a successful flash.\n"1470"Do you want to continue?");14711472lv_mbox_add_btns(mbox, mbox_btn_map, _action_flash_android_data);1473lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1474lv_obj_set_top(mbox, true);14751476return LV_RES_OK;1477}14781479static lv_res_t _action_part_manager_flash_options0(lv_obj_t *btns, const char *txt)1480{1481int btn_idx = lv_btnm_get_pressed(btns);14821483switch (btn_idx)1484{1485case 0:1486action_ums_sd(NULL);1487lv_obj_del(ums_mbox);1488break;1489case 1:1490_action_check_flash_linux(NULL);1491break;1492case 2:1493_action_flash_android(NULL);1494break;1495case 3:1496mbox_action(btns, txt);1497return LV_RES_INV;1498}14991500return LV_RES_OK;1501}15021503static lv_res_t _action_part_manager_flash_options1(lv_obj_t *btns, const char *txt)1504{1505int btn_idx = lv_btnm_get_pressed(btns);15061507switch (btn_idx)1508{1509case 0:1510action_ums_sd(NULL);1511lv_obj_del(ums_mbox);1512break;1513case 1:1514mbox_action(btns, txt);1515_action_check_flash_linux(NULL);1516return LV_RES_INV;1517case 2:1518mbox_action(btns, txt);1519return LV_RES_INV;1520}15211522return LV_RES_OK;1523}15241525static lv_res_t _action_part_manager_flash_options2(lv_obj_t *btns, const char *txt)1526{1527int btn_idx = lv_btnm_get_pressed(btns);15281529switch (btn_idx)1530{1531case 0:1532action_ums_sd(NULL);1533lv_obj_del(ums_mbox);1534break;1535case 1:1536mbox_action(btns, txt);1537_action_flash_android(NULL);1538return LV_RES_INV;1539case 2:1540mbox_action(btns, txt);1541return LV_RES_INV;1542}15431544return LV_RES_OK;1545}15461547static int _backup_and_restore_files(bool backup, lv_obj_t **labels)1548{1549const char *src_drv = backup ? "sd:" : "ram:";1550const char *dst_drv = backup ? "ram:" : "sd:";15511552int res = 0;1553u32 total_size = 0;1554u32 total_files = 0;1555char *path = malloc(0x1000);1556path[0] = 0; // Set default as root folder.15571558// Check if Mariko Warmboot Storage exists in source drive.1559f_chdrive(src_drv);1560bool backup_pld = !part_info.backup_possible && !f_stat("payload.bin", NULL);15611562if (!part_info.backup_possible)1563{1564// Change path to hekate/Nyx.1565strcpy(path, "bootloader");15661567// Create hekate/Nyx/MWS folders in destination drive.1568f_chdrive(dst_drv);1569f_mkdir("bootloader");1570}15711572// Copy all or hekate/Nyx files.1573res = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels);15741575// If incomplete backup mode, copy MWS and payload.bin also.1576if (!res)1577{1578if (!res && backup_pld)1579{1580strcpy(path, "payload.bin");1581res = _copy_file(src_drv, dst_drv, path);1582}1583}15841585free(path);15861587return res;1588}15891590static lv_res_t _sd_create_mbox_start_partitioning()1591{1592lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1593lv_obj_set_style(dark_bg, &mbox_darken);1594lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);15951596static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1597static const char *mbox_btn_map1[] = { "\222SD UMS", "\222Flash Linux", "\222Flash Android", "\221OK", "" };1598static const char *mbox_btn_map2[] = { "\222SD UMS", "\222Flash Linux", "\221OK", "" };1599static const char *mbox_btn_map3[] = { "\222SD UMS", "\222Flash Android", "\221OK", "" };1600lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1601lv_mbox_set_recolor_text(mbox, true);1602lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);16031604lv_mbox_set_text(mbox, "#FF8000 SD Partition Manager#");1605lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1606lv_obj_set_top(mbox, true);16071608bool buttons_set = false;16091610// Use safety wait if backup is not possible.1611char *txt_buf = malloc(SZ_4K);1612strcpy(txt_buf, "#FF8000 SD Partition Manager#\n\nSafety wait ends in ");1613lv_mbox_set_text(mbox, txt_buf);16141615u32 seconds = 5;1616u32 text_idx = strlen(txt_buf);1617while (seconds)1618{1619s_printf(txt_buf + text_idx, "%d seconds...", seconds);1620lv_mbox_set_text(mbox, txt_buf);1621manual_system_maintenance(true);1622msleep(1000);1623seconds--;1624}16251626lv_mbox_set_text(mbox,1627"#FF8000 SD Partition Manager#\n\n"1628"#FFDD00 Warning: Do you really want to continue?!#\n\n"1629"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");1630lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1631manual_system_maintenance(true);16321633free(txt_buf);16341635if (!(btn_wait() & BTN_POWER))1636goto exit;16371638// Start partitioning.1639lv_mbox_set_text(mbox, "#FF8000 SD Partition Manager#");1640lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1641manual_system_maintenance(true);16421643lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1644lv_label_set_recolor(lbl_status, true);16451646lv_obj_t *lbl_paths[2];16471648// Create backup/restore paths labels.1649lbl_paths[0] = lv_label_create(mbox, NULL);1650lv_label_set_text(lbl_paths[0], "/");1651lv_label_set_long_mode(lbl_paths[0], LV_LABEL_LONG_DOT);1652lv_cont_set_fit(lbl_paths[0], false, true);1653lv_obj_set_width(lbl_paths[0], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1654lv_label_set_align(lbl_paths[0], LV_LABEL_ALIGN_CENTER);1655lbl_paths[1] = lv_label_create(mbox, NULL);1656lv_label_set_text(lbl_paths[1], " ");1657lv_label_set_long_mode(lbl_paths[1], LV_LABEL_LONG_DOT);1658lv_cont_set_fit(lbl_paths[1], false, true);1659lv_obj_set_width(lbl_paths[1], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1660lv_label_set_align(lbl_paths[1], LV_LABEL_ALIGN_CENTER);16611662sd_mount();16631664FATFS ram_fs;16651666// Read current MBR.1667sdmmc_storage_read(part_info.storage, 0, 1, &part_info.mbr_old);16681669lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing Ramdisk...");1670lv_label_set_text(lbl_paths[0], "Please wait...");1671lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1672manual_system_maintenance(true);16731674// Initialize RAM disk.1675if (ram_disk_init(&ram_fs, RAM_DISK_SZ))1676{1677lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to initialize Ramdisk!");1678goto error;1679}16801681lv_label_set_text(lbl_status, "#00DDFF Status:# Backing up files...");1682manual_system_maintenance(true);16831684// Do full or hekate/Nyx backup.1685if (_backup_and_restore_files(true, lbl_paths))1686{1687if (part_info.backup_possible)1688lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!");1689else1690lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!\nBootloader folder exceeds 1.2GB or corrupt!");16911692goto error;1693}16941695f_unmount("sd:"); // Unmount SD card.16961697lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting FAT32 partition...");1698lv_label_set_text(lbl_paths[0], "Please wait...");1699lv_label_set_text(lbl_paths[1], " ");1700manual_system_maintenance(true);17011702// Set reserved size.1703u32 part_rsvd_size = (part_info.emu_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);1704part_rsvd_size += part_rsvd_size ? part_info.alignment : 0; // Do not reserve alignment space if no extra partitions.1705disk_set_info(DRIVE_SD, SET_SECTOR_COUNT, &part_rsvd_size);1706u8 *buf = malloc(SZ_4M);17071708// Set cluster size to 64KB and try to format.1709u32 cluster_size = 65536;1710u32 mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);17111712if (!mkfs_error)1713goto mkfs_no_error;17141715// Retry formatting by halving cluster size, until one succeeds.1716while (cluster_size > 4096)1717{1718cluster_size /= 2;1719mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);17201721if (!mkfs_error)1722break;1723}17241725if (mkfs_error)1726{1727// Failed to format.1728s_printf((char *)buf, "#FFDD00 Error:# Failed to format disk (%d)!\n\n"1729"Remove the SD card and check that is OK.\nIf not, format it, reinsert it and\npress #FF8000 POWER#!", mkfs_error);17301731lv_label_set_text(lbl_status, (char *)buf);1732lv_label_set_text(lbl_paths[0], " ");1733manual_system_maintenance(true);17341735sd_end();17361737while (!(btn_wait() & BTN_POWER));17381739sd_mount();17401741lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");1742manual_system_maintenance(true);17431744// Restore backed up files back to SD.1745if (_backup_and_restore_files(false, lbl_paths))1746{1747// Failed to restore files. Try again once more.1748if (_backup_and_restore_files(false, lbl_paths))1749{1750lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");1751free(buf);1752goto error;1753}1754}17551756lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!");1757f_unmount("ram:");1758free(buf);1759goto error;1760}17611762mkfs_no_error:1763free(buf);17641765// Remount sd card as it was unmounted from formatting it.1766f_mount(&sd_fs, "sd:", 1); // Mount SD card.17671768lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");1769manual_system_maintenance(true);17701771// Restore backed up files back to SD.1772if (_backup_and_restore_files(false, lbl_paths))1773{1774// Failed to restore files. Try again once more.1775if (_backup_and_restore_files(false, lbl_paths))1776{1777lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");1778goto error;1779}1780}17811782// Unmount ramdisk.1783f_unmount("ram:");1784f_chdrive("sd:");17851786// Set Volume label.1787f_setlabel("0:SWITCH SD");17881789lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table...");1790lv_label_set_text(lbl_paths[0], "Please wait...");1791lv_label_set_text(lbl_paths[1], " ");1792manual_system_maintenance(true);17931794// Prepare MBR and GPT header and partition entries and flash them.1795_sd_prepare_and_flash_mbr_gpt();17961797// Enable/Disable buttons depending on partition layout.1798if (part_info.l4t_size)1799{1800lv_obj_set_click(btn_flash_l4t, true);1801lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);1802}1803else1804{1805lv_obj_set_click(btn_flash_l4t, false);1806lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);1807}18081809// Enable/Disable buttons depending on partition layout.1810if (part_info.and_size)1811{1812lv_obj_set_click(btn_flash_android, true);1813lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);1814}1815else1816{1817lv_obj_set_click(btn_flash_android, false);1818lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);1819}18201821sd_unmount();1822lv_label_set_text(lbl_status, "#00DDFF Status:# Done!");1823manual_system_maintenance(true);18241825// Set buttons depending on what user chose to create.1826if (part_info.l4t_size && part_info.and_size)1827lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);1828else if (part_info.l4t_size)1829lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);1830else if (part_info.and_size)1831lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);18321833if (part_info.l4t_size || part_info.and_size)1834buttons_set = true;18351836goto out;18371838error:1839f_chdrive("sd:");18401841out:1842lv_obj_del(lbl_paths[0]);1843lv_obj_del(lbl_paths[1]);1844exit:1845if (!buttons_set)1846lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);1847lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1848lv_obj_set_top(mbox, true);18491850// Disable partitioning button.1851if (part_info.partition_button)1852lv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);18531854return LV_RES_OK;1855}18561857static lv_res_t _emmc_create_mbox_start_partitioning()1858{1859lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1860lv_obj_set_style(dark_bg, &mbox_darken);1861lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);18621863static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1864static const char *mbox_btn_map1[] = { "\222Flash Linux", "\222Flash Android", "\221OK", "" };1865static const char *mbox_btn_map2[] = { "\222Flash Linux", "\221OK", "" };1866static const char *mbox_btn_map3[] = { "\222Flash Android", "\221OK", "" };1867lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1868lv_mbox_set_recolor_text(mbox, true);1869lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);18701871lv_mbox_set_text(mbox, "#FF8000 eMMC Partition Manager#");1872lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1873lv_obj_set_top(mbox, true);18741875bool buttons_set = false;18761877// Use safety wait if backup is not possible.1878char *txt_buf = malloc(SZ_4K);1879strcpy(txt_buf, "#FF8000 eMMC Partition Manager#\n\nSafety wait ends in ");1880lv_mbox_set_text(mbox, txt_buf);18811882u32 seconds = 5;1883u32 text_idx = strlen(txt_buf);1884while (seconds)1885{1886s_printf(txt_buf + text_idx, "%d seconds...", seconds);1887lv_mbox_set_text(mbox, txt_buf);1888manual_system_maintenance(true);1889msleep(1000);1890seconds--;1891}18921893lv_mbox_set_text(mbox,1894"#FF8000 eMMC Partition Manager#\n\n"1895"#FFDD00 Warning: Do you really want to continue?!#\n\n"1896"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");1897lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1898manual_system_maintenance(true);18991900if (!(btn_wait() & BTN_POWER))1901goto exit;19021903// Start partitioning.1904lv_mbox_set_text(mbox, "#FF8000 eMMC Partition Manager#");1905lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1906manual_system_maintenance(true);19071908lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1909lv_label_set_recolor(lbl_status, true);19101911lv_obj_t *lbl_extra = lv_label_create(mbox, NULL);1912lv_label_set_long_mode(lbl_extra, LV_LABEL_LONG_DOT);1913lv_cont_set_fit(lbl_extra, false, true);1914lv_obj_set_width(lbl_extra, (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1915lv_label_set_align(lbl_extra, LV_LABEL_ALIGN_CENTER);19161917lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing...");1918lv_label_set_text(lbl_extra, "Please wait...");1919lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1920manual_system_maintenance(true);19211922if (!emmc_initialize(false))1923{1924lv_label_set_text(lbl_extra, "#FFDD00 Failed to init eMMC!#");1925goto exit;1926}19271928emmc_set_partition(EMMC_GPP);19291930if (!emummc_raw_derive_bis_keys())1931{1932lv_label_set_text(lbl_extra, "#FFDD00 For formatting USER partition,#\n#FFDD00 BIS keys are needed!#");1933emmc_end();1934goto exit;1935}19361937lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table...");1938lv_label_set_text(lbl_extra, "Please wait...");1939manual_system_maintenance(true);19401941// Prepare MBR and GPT header and partition entries and flash them.1942if (_emmc_prepare_and_flash_mbr_gpt())1943goto no_hos_user_part;19441945lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting USER partition...");1946lv_label_set_text(lbl_extra, "Please wait...");1947manual_system_maintenance(true);19481949// Get USER partition and configure BIS and FatFS.1950LIST_INIT(gpt);1951emmc_gpt_parse(&gpt);1952emmc_part_t *user_part = emmc_part_find(&gpt, "USER");19531954if (!user_part)1955{1956no_hos_user_part:1957s_printf(txt_buf, "#FF0000 HOS USER partition doesn't exist!#\nRestore HOS backup first...");1958lv_label_set_text(lbl_extra, txt_buf);19591960emmc_gpt_free(&gpt);1961emmc_end();19621963goto exit;1964}19651966// Initialize BIS for eMMC. BIS keys should be already in place.1967nx_emmc_bis_init(user_part, true, 0);19681969// Set BIS size for FatFS.1970u32 user_sectors = user_part->lba_end - user_part->lba_start + 1;1971disk_set_info(DRIVE_BIS, SET_SECTOR_COUNT, &user_sectors);19721973// Enable writing.1974bool allow_writes = true;1975disk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);19761977// Format USER partition as FAT32 with 16KB cluster and PRF2SAFE.1978u8 *buff = malloc(SZ_4M);1979int mkfs_error = f_mkfs("bis:", FM_FAT32 | FM_SFD | FM_PRF2, 16384, buff, SZ_4M);19801981if (mkfs_error)1982{1983s_printf(txt_buf, "#FF0000 Failed (%d)!#\nPlease try again...\n", mkfs_error);1984lv_label_set_text(lbl_extra, txt_buf);19851986free(buff);1987emmc_end();19881989goto exit;1990}19911992// Disable writes to BIS.1993allow_writes = false;1994disk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);19951996// Flush BIS cache, deinit, clear BIS keys slots and reinstate SBK.1997nx_emmc_bis_end();1998hos_bis_keys_clear();1999emmc_gpt_free(&gpt);2000emmc_end();20012002// Enable/Disable buttons depending on partition layout.2003if (part_info.l4t_size)2004{2005lv_obj_set_click(btn_flash_l4t, true);2006lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);2007}2008else2009{2010lv_obj_set_click(btn_flash_l4t, false);2011lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);2012}20132014// Enable/Disable buttons depending on partition layout.2015if (part_info.and_size)2016{2017lv_obj_set_click(btn_flash_android, true);2018lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);2019}2020else2021{2022lv_obj_set_click(btn_flash_android, false);2023lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);2024}20252026lv_label_set_text(lbl_status, "#00DDFF Status:# Done!");2027manual_system_maintenance(true);20282029// Set buttons depending on what user chose to create.2030if (part_info.l4t_size && part_info.and_size)2031lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);2032else if (part_info.l4t_size)2033lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);2034else if (part_info.and_size)2035lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);20362037if (part_info.l4t_size || part_info.and_size)2038buttons_set = true;20392040lv_obj_del(lbl_extra);20412042exit:2043free(txt_buf);20442045if (!buttons_set)2046lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);2047lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2048lv_obj_set_top(mbox, true);20492050// Disable partitioning button.2051if (part_info.partition_button)2052lv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);20532054return LV_RES_OK;2055}20562057static lv_res_t _create_mbox_partitioning_option0(lv_obj_t *btns, const char *txt)2058{2059int btn_idx = lv_btnm_get_pressed(btns);20602061switch (btn_idx)2062{2063case 0:2064action_ums_sd(NULL);2065return LV_RES_OK;2066case 1:2067mbox_action(btns, txt);2068_sd_create_mbox_start_partitioning();2069break;2070case 2:2071mbox_action(btns, txt);2072break;2073}20742075return LV_RES_INV;2076}20772078static lv_res_t _create_mbox_partitioning_option1(lv_obj_t *btns, const char *txt)2079{2080int btn_idx = lv_btnm_get_pressed(btns);20812082mbox_action(btns, txt);20832084if (!btn_idx)2085{2086mbox_action(btns, txt);2087if (!part_info.emmc)2088_sd_create_mbox_start_partitioning();2089else2090_emmc_create_mbox_start_partitioning();2091return LV_RES_INV;2092}20932094return LV_RES_OK;2095}20962097static lv_res_t _create_mbox_partitioning_warn()2098{2099lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2100lv_obj_set_style(dark_bg, &mbox_darken);2101lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);21022103static const char *mbox_btn_map[] = { "\222SD UMS", "\222Start", "\222Cancel", "" };2104static const char *mbox_btn_map2[] = { "\222Start", "\222Cancel", "" };2105lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);2106lv_mbox_set_recolor_text(mbox, true);21072108char *txt_buf = malloc(SZ_4K);2109lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);2110lv_mbox_set_text(mbox, "#FF8000 Partition Manager#");21112112lv_obj_t *lbl_status = lv_label_create(mbox, NULL);2113lv_label_set_recolor(lbl_status, true);21142115if (!part_info.emmc)2116{2117s_printf(txt_buf, "#FFDD00 Warning: This will partition the SD Card!#\n\n");21182119if (part_info.backup_possible)2120{2121strcat(txt_buf, "#C7EA46 Your files will be backed up and restored!#\n"2122"#FFDD00 Any other partition will be wiped!#");2123}2124else2125{2126strcat(txt_buf, "#FFDD00 Your files will be wiped!#\n"2127"#FFDD00 Any other partition will be also wiped!#\n"2128"#FFDD00 Use USB UMS to copy them over!#");2129}21302131lv_label_set_text(lbl_status, txt_buf);21322133if (part_info.backup_possible)2134lv_mbox_add_btns(mbox, mbox_btn_map2, _create_mbox_partitioning_option1);2135else2136lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_option0);2137}2138else2139{2140s_printf(txt_buf, "#FFDD00 Warning: This will partition the eMMC!#\n\n"2141"#FFDD00 The USER partition will also be formatted!#");2142lv_label_set_text(lbl_status, txt_buf);2143lv_mbox_add_btns(mbox, mbox_btn_map2, _create_mbox_partitioning_option1);2144}21452146lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2147lv_obj_set_top(mbox, true);21482149free(txt_buf);21502151return LV_RES_OK;2152}21532154static lv_res_t _create_mbox_partitioning_android(lv_obj_t *btns, const char *txt)2155{2156int btn_idx = lv_btnm_get_pressed(btns);21572158mbox_action(btns, txt);21592160part_info.and_dynamic = !btn_idx;2161_create_mbox_partitioning_warn();21622163return LV_RES_INV;2164}21652166static lv_res_t _create_mbox_partitioning_andr_part()2167{2168lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2169lv_obj_set_style(dark_bg, &mbox_darken);2170lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);21712172static const char *mbox_btn_map[] = { "\222Dynamic", "\222Legacy", "" };2173lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);2174lv_mbox_set_recolor_text(mbox, true);21752176lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);2177lv_mbox_set_text(mbox, "#FF8000 Android Partitioning#");21782179lv_obj_t *lbl_status = lv_label_create(mbox, NULL);2180lv_label_set_recolor(lbl_status, true);21812182lv_label_set_text(lbl_status,2183"Please select a partition scheme:\n\n"2184"#C7EA46 Dynamic:# Android 13+\n"2185"#C7EA46 Legacy:# Android 10-11\n");21862187lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_android);2188lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2189lv_obj_set_top(mbox, true);21902191return LV_RES_OK;2192}21932194static lv_res_t _create_mbox_partitioning_next(lv_obj_t *btn) {2195if (part_info.and_size)2196return _create_mbox_partitioning_andr_part();2197else2198return _create_mbox_partitioning_warn();2199}22002201static void _update_partition_bar()2202{2203lv_obj_t *h1 = lv_obj_get_parent(part_info.bar_hos);22042205// Set widths based on max bar width.2206u32 total_size = (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB;2207u32 bar_hos_size = lv_obj_get_width(h1) * (part_info.hos_size >> 10) / total_size;2208u32 bar_emu_size = lv_obj_get_width(h1) * (part_info.emu_size >> 10) / total_size;2209u32 bar_l4t_size = lv_obj_get_width(h1) * (part_info.l4t_size >> 10) / total_size;2210u32 bar_and_size = lv_obj_get_width(h1) * (part_info.and_size >> 10) / total_size;22112212// Update bar widths.2213lv_obj_set_width(part_info.bar_hos, bar_hos_size);2214lv_obj_set_width(part_info.bar_emu, bar_emu_size);2215lv_obj_set_width(part_info.bar_l4t, bar_l4t_size);2216lv_obj_set_width(part_info.bar_and, bar_and_size);22172218// Re-align bars.2219lv_obj_realign(part_info.bar_emu);2220lv_obj_realign(part_info.bar_l4t);2221lv_obj_realign(part_info.bar_and);22222223// Set emuMMC blending separator sizes and realign.2224lv_obj_set_width(part_info.sep_emu, bar_emu_size ? 8 : 0);2225lv_obj_realign(part_info.sep_emu);22262227// Set L4T blending separator sizes and realign.2228lv_obj_set_width(part_info.sep_l4t, bar_l4t_size ? 8 : 0);2229lv_obj_realign(part_info.sep_l4t);22302231// Set Android blending separator sizes and realign.2232lv_obj_set_width(part_info.sep_and, bar_and_size ? 8 : 0);2233lv_obj_realign(part_info.sep_and);22342235// Re-align size labels.2236lv_obj_realign(part_info.lbl_hos);2237lv_obj_realign(part_info.lbl_emu);2238lv_obj_realign(part_info.lbl_l4t);2239lv_obj_realign(part_info.lbl_and);2240lv_obj_align(part_info.cont_lbl, part_info.bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 11 - LV_DPI / 2, LV_DPI * 9 / 23);2241}22422243static lv_res_t _action_slider_emu(lv_obj_t *slider)2244{2245u32 size;2246char lbl_text[64];2247bool prev_emu_double = part_info.emu_double;2248int slide_val = lv_slider_get_value(slider);2249u32 max_emmc_size = !part_info.emmc_is_64gb ? EMU_32GB_FULL : EMU_64GB_FULL;22502251part_info.emu_double = false;22522253// Check that eMMC exists.2254if (!part_info.emmc_size_mb)2255{2256lv_slider_set_value(slider, 0);2257return LV_RES_OK;2258}22592260// In case of upgraded eMMC, do not allow FULL sizes. Max size is always bigger than official eMMCs.2261if (max_emmc_size < part_info.emmc_size_mb)2262{2263if (slide_val == EMU_SLIDER_1X_FULL)2264{2265if (prev_emu_double)2266slide_val--;2267else2268slide_val++;2269lv_slider_set_value(slider, slide_val);2270}2271else if (slide_val == EMU_SLIDER_2X_FULL)2272{2273slide_val--;2274lv_slider_set_value(slider, slide_val);2275}2276}22772278size = (slide_val > EMU_SLIDER_1X_MAX ? (slide_val - EMU_SLIDER_1X_MAX) : slide_val) + EMU_SLIDER_OFFSET;2279size *= 1024; // Convert to GB.2280size += EMU_RSVD_MB; // Add reserved size.22812282if (slide_val == EMU_SLIDER_MIN)2283size = 0; // Reset if 0.2284else if (slide_val >= EMU_SLIDER_2X_MIN)2285{2286size *= 2;2287part_info.emu_double = true;2288}22892290// Handle special cases. 2nd value is for 64GB Aula. Values already include reserved space.2291if (slide_val == EMU_SLIDER_1X_FULL)2292size = max_emmc_size;2293else if (slide_val == EMU_SLIDER_2X_FULL)2294size = 2 * max_emmc_size;22952296// Sanitize sizes based on new HOS size.2297s32 hos_size = (part_info.total_sct >> 11) - 16 - size - part_info.l4t_size - part_info.and_size;2298if (hos_size > part_info.hos_min_size)2299{2300part_info.emu_size = size;2301part_info.hos_size = hos_size;23022303s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);2304lv_label_set_text(part_info.lbl_hos, lbl_text);2305lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);23062307if (!part_info.emu_double)2308{2309if (slide_val != EMU_SLIDER_1X_FULL)2310s_printf(lbl_text, "#FF3C28 %4d GiB#", size >> 10);2311else2312s_printf(lbl_text, "#FF3C28 %d FULL#", size >> 10);2313}2314else2315s_printf(lbl_text, "#FFDD00 2x##FF3C28 %d GiB#", size >> 11);2316lv_label_set_text(part_info.lbl_emu, lbl_text);2317}2318else2319{2320u32 emu_size = part_info.emu_size;23212322if (emu_size == max_emmc_size)2323emu_size = EMU_SLIDER_1X_FULL;2324else if (emu_size == 2 * max_emmc_size)2325emu_size = EMU_SLIDER_2X_FULL;2326else if (emu_size)2327{2328if (prev_emu_double)2329emu_size /= 2;2330emu_size -= EMU_RSVD_MB;2331emu_size /= 1024;2332emu_size -= EMU_SLIDER_OFFSET;23332334if (prev_emu_double)2335emu_size += EMU_SLIDER_2X_MIN;2336}23372338int new_slider_val = emu_size;2339part_info.emu_double = prev_emu_double ? true : false;23402341lv_slider_set_value(slider, new_slider_val);2342}23432344_update_partition_bar();23452346return LV_RES_OK;2347}23482349static lv_res_t _action_slider_l4t(lv_obj_t *slider)2350{2351char lbl_text[64];23522353u32 size = (u32)lv_slider_get_value(slider) << 10;2354if (size < 4096)2355size = 0;2356else if (size < 8192)2357size = 8192;23582359s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - size - part_info.and_size;23602361// Sanitize sizes based on new HOS size.2362if (hos_size > part_info.hos_min_size)2363{2364if (size <= 8192)2365lv_slider_set_value(slider, size >> 10);2366}2367else2368{2369size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - 2048;2370hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - size;2371if (hos_size < part_info.hos_min_size || size < 8192)2372{2373lv_slider_set_value(slider, part_info.l4t_size >> 10);2374goto out;2375}2376lv_slider_set_value(slider, size >> 10);2377}23782379part_info.l4t_size = size;2380part_info.hos_size = hos_size;23812382s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);2383lv_label_set_text(part_info.lbl_hos, lbl_text);2384lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);2385s_printf(lbl_text, "#00DDFF %4d GiB#", size >> 10);2386lv_label_set_text(part_info.lbl_l4t, lbl_text);23872388_update_partition_bar();23892390out:2391return LV_RES_OK;2392}23932394static lv_res_t _action_slider_and(lv_obj_t *slider)2395{2396char lbl_text[64];23972398u32 user_size = (u32)lv_slider_get_value(slider) << 10;2399if (user_size < 2048)2400user_size = 0;2401else if (user_size < 4096)2402user_size = 4096;24032404u32 and_size = user_size ? (user_size + AND_SYS_SIZE_MB) : 0;2405s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;24062407// Sanitize sizes based on new HOS size.2408if (hos_size > part_info.hos_min_size)2409{2410if (user_size <= 4096)2411lv_slider_set_value(slider, user_size >> 10);2412}2413else2414{2415and_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - 2048;2416hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;2417if (hos_size < part_info.hos_min_size || and_size < 8192)2418{2419lv_slider_set_value(slider, part_info.and_size >> 10);2420goto out;2421}2422user_size = and_size - AND_SYS_SIZE_MB;2423lv_slider_set_value(slider, user_size >> 10);2424}24252426part_info.and_size = and_size;2427part_info.hos_size = hos_size;24282429s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);2430lv_label_set_text(part_info.lbl_hos, lbl_text);2431lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);2432s_printf(lbl_text, "#FF8000 %4d GiB#", user_size >> 10);2433lv_label_set_text(part_info.lbl_and, lbl_text);24342435_update_partition_bar();24362437out:2438return LV_RES_OK;2439}24402441static lv_res_t _mbox_check_files_total_size_option(lv_obj_t *btns, const char *txt)2442{2443// If "don't backup" button was pressed, disable backup/restore of files.2444if (!lv_btnm_get_pressed(btns))2445part_info.backup_possible = false;24462447mbox_action(btns, txt);24482449return LV_RES_INV;2450}24512452static void _create_mbox_check_files_total_size()2453{2454static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;2455static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;24562457// Set HOS bar style.2458lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);2459bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);2460bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;24612462// Set emuMMC bar style.2463lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);2464bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);2465bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;24662467// Set L4T bar style.2468lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);2469bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);2470bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;24712472// Set GPT bar style.2473lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);2474bar_and_ind.body.main_color = LV_COLOR_HEX(0xC000FF);2475bar_and_ind.body.grad_color = bar_and_ind.body.main_color;24762477// Set separator styles.2478lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);2479sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);2480sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;2481sep_emu_bg.body.radius = 0;2482lv_style_copy(&sep_l4t_bg, &sep_emu_bg);2483sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);2484sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;2485lv_style_copy(&sep_and_bg, &sep_emu_bg);2486sep_and_bg.body.main_color = LV_COLOR_HEX(0xC000FF);2487sep_and_bg.body.grad_color = sep_and_bg.body.main_color;24882489char *txt_buf = malloc(SZ_8K);24902491lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2492lv_obj_set_style(dark_bg, &mbox_darken);2493lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);24942495static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };2496static const char *mbox_btn_map2[] = { "\222Don't Backup", "\222OK", "" };2497lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);2498lv_mbox_set_recolor_text(mbox, true);2499lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);25002501lv_mbox_set_text(mbox, "Analyzing SD card usage. This might take a while...");25022503lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2504lv_obj_set_top(mbox, true);2505manual_system_maintenance(true);25062507char *path = malloc(0x1000);2508u32 total_files = 0;2509u32 total_size = 0;2510path[0] = 0;25112512// Check total size of files.2513int res = _stat_and_copy_files("sd:", NULL, path, &total_files, &total_size, NULL);25142515// Not more than 1.2GB.2516part_info.backup_possible = !res && !(total_size > (RAM_DISK_SZ - SZ_16M)); // Account for alignment.25172518if (part_info.backup_possible)2519{2520s_printf(txt_buf,2521"#96FF00 The SD Card files will be backed up automatically!#\n"2522"#FFDD00 Any other partition will be wiped!#\n"2523"#00DDFF Total files:# %d, #00DDFF Total size:# %d MiB", total_files, total_size >> 20);2524lv_mbox_set_text(mbox, txt_buf);2525}2526else2527{2528lv_mbox_set_text(mbox,2529"#FFDD00 The SD Card cannot be backed up automatically!#\n"2530"#FFDD00 Any other partition will be also wiped!#\n\n"2531"You will be asked to back up your files later via UMS.");2532}25332534// Create container to keep content inside.2535lv_obj_t *h1 = lv_cont_create(mbox, NULL);2536lv_cont_set_fit(h1, false, true);2537lv_cont_set_style(h1, &lv_style_transp_tight);2538lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI * 3);25392540lv_obj_t *lbl_part = lv_label_create(h1, NULL);2541lv_label_set_recolor(lbl_part, true);2542lv_label_set_text(lbl_part, "#00DDFF Current MBR partition layout:#");25432544// Read current MBR.2545mbr_t mbr = { 0 };2546sdmmc_storage_read(&sd_storage, 0, 1, &mbr);25472548// Calculate MBR partitions size.2549total_size = (sd_storage.sec_cnt - AU_ALIGN_SECTORS) / SECTORS_PER_GB;2550u32 bar_hos_size = lv_obj_get_width(h1) * (mbr.partitions[0].size_sct / SECTORS_PER_GB) / total_size;2551u32 bar_emu_size = 0;2552for (u32 i = 1; i < 4; i++)2553if (mbr.partitions[i].type == 0xE0)2554bar_emu_size += mbr.partitions[i].size_sct;2555bar_emu_size = lv_obj_get_width(h1) * (bar_emu_size / SECTORS_PER_GB) / total_size;25562557u32 bar_l4t_size = 0;2558for (u32 i = 1; i < 4; i++)2559if (mbr.partitions[i].type == 0x83)2560bar_l4t_size += mbr.partitions[i].size_sct;2561bar_l4t_size = lv_obj_get_width(h1) * (bar_l4t_size / SECTORS_PER_GB) / total_size;25622563u32 bar_and_size = lv_obj_get_width(h1) - bar_hos_size - bar_emu_size - bar_l4t_size;25642565// Create HOS bar.2566lv_obj_t *bar_mbr_hos = lv_bar_create(h1, NULL);2567lv_obj_set_size(bar_mbr_hos, bar_hos_size, LV_DPI / 3);2568lv_bar_set_range(bar_mbr_hos, 0, 1);2569lv_bar_set_value(bar_mbr_hos, 1);2570lv_bar_set_style(bar_mbr_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);2571lv_obj_align(bar_mbr_hos, lbl_part, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);25722573// Create emuMMC bar.2574lv_obj_t *bar_mbr_emu = lv_bar_create(h1, bar_mbr_hos);2575lv_obj_set_size(bar_mbr_emu, bar_emu_size, LV_DPI / 3);2576lv_bar_set_style(bar_mbr_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);2577lv_obj_align(bar_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);25782579// Create L4T bar.2580lv_obj_t *bar_mbr_l4t = lv_bar_create(h1, bar_mbr_hos);2581lv_obj_set_size(bar_mbr_l4t, bar_l4t_size, LV_DPI / 3);2582lv_bar_set_style(bar_mbr_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);2583lv_obj_align(bar_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);25842585// Create GPT bar.2586lv_obj_t *bar_mbr_gpt = lv_bar_create(h1, bar_mbr_hos);2587lv_obj_set_size(bar_mbr_gpt, bar_and_size > 1 ? bar_and_size : 0, LV_DPI / 3);2588lv_bar_set_style(bar_mbr_gpt, LV_BAR_STYLE_INDIC, &bar_and_ind);2589lv_obj_align(bar_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);25902591// Create emuMMC separator.2592lv_obj_t *sep_mbr_emu = lv_cont_create(h1, NULL);2593lv_obj_set_size(sep_mbr_emu, bar_emu_size ? 8 : 0, LV_DPI / 3);2594lv_obj_set_style(sep_mbr_emu, &sep_emu_bg);2595lv_obj_align(sep_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);25962597// Create L4T separator.2598lv_obj_t *sep_mbr_l4t = lv_cont_create(h1, sep_mbr_emu);2599lv_obj_set_size(sep_mbr_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 3);2600lv_obj_set_style(sep_mbr_l4t, &sep_l4t_bg);2601lv_obj_align(sep_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);26022603// Create GPT separator.2604lv_obj_t *sep_mbr_gpt = lv_cont_create(h1, sep_mbr_emu);2605lv_obj_set_size(sep_mbr_gpt, bar_and_size ? (bar_and_size > 1 ? 8 : 0) : 0, LV_DPI / 3);2606lv_obj_set_style(sep_mbr_gpt, &sep_and_bg);2607lv_obj_align(sep_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);26082609// Print partition table info.2610s_printf(txt_buf,2611"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2612"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2613"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2614"Partition 3 - Type: %02x, Start: %08x, Size: %08x",2615mbr.partitions[0].type, mbr.partitions[0].start_sct, mbr.partitions[0].size_sct,2616mbr.partitions[1].type, mbr.partitions[1].start_sct, mbr.partitions[1].size_sct,2617mbr.partitions[2].type, mbr.partitions[2].start_sct, mbr.partitions[2].size_sct,2618mbr.partitions[3].type, mbr.partitions[3].start_sct, mbr.partitions[3].size_sct);26192620lv_obj_t *lbl_table = lv_label_create(h1, NULL);2621lv_label_set_style(lbl_table, &monospace_text);2622lv_label_set_text(lbl_table, txt_buf);2623lv_obj_align(lbl_table, h1, LV_ALIGN_IN_TOP_MID, 0, LV_DPI);26242625if (!part_info.backup_possible)2626lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);2627else2628lv_mbox_add_btns(mbox, mbox_btn_map2, _mbox_check_files_total_size_option);26292630lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);26312632free(txt_buf);2633free(path);2634}26352636static lv_res_t _action_fix_mbr_gpt(lv_obj_t *btn)2637{2638lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2639lv_obj_set_style(dark_bg, &mbox_darken);2640lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);26412642static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };2643lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);2644lv_mbox_set_recolor_text(mbox, true);26452646lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);2647lv_mbox_set_text(mbox, "#FF8000 Fix Hybrid MBR#");26482649lv_obj_t *lbl_status = lv_label_create(mbox, NULL);2650lv_label_set_recolor(lbl_status, true);26512652mbr_t mbr[2] = { 0 };2653gpt_t *gpt = zalloc(sizeof(gpt_t));2654gpt_header_t gpt_hdr_backup = { 0 };26552656bool has_mbr_attributes = false;2657bool hybrid_mbr_changed = false;2658bool gpt_partition_exists = false;2659int gpt_oob_empty_part_no = 0;2660int gpt_emummc_migrate_no = 0;26612662// Try to init sd card. No need for valid MBR.2663if (!sd_mount() && !sd_get_card_initialized())2664{2665lv_label_set_text(lbl_status, "#FFDD00 Failed to init SD!#");2666goto out;2667}26682669sdmmc_storage_read(&sd_storage, 0, 1, &mbr[0]);2670sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);26712672memcpy(&mbr[1], &mbr[0], sizeof(mbr_t));26732674sd_unmount();26752676// Check for secret MBR attributes.2677if (gpt->entries[0].part_guid[7])2678has_mbr_attributes = true;26792680// Check if there's a GPT Protective partition.2681for (u32 i = 0; i < 4; i++)2682{2683if (mbr[0].partitions[i].type == 0xEE)2684gpt_partition_exists = true;2685}26862687// Check if GPT is valid.2688if (!gpt_partition_exists || memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)2689{2690lv_label_set_text(lbl_status, "#FFDD00 Warning:# No valid GPT was found!");26912692gpt_partition_exists = false;26932694if (has_mbr_attributes)2695goto check_changes;2696else2697goto out;2698}26992700sdmmc_storage_read(&sd_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);27012702// Parse GPT.2703LIST_INIT(gpt_parsed);2704for (u32 i = 0; i < gpt->header.num_part_ents; i++)2705{2706// Check if partition is out of bounds or empty.2707if ( gpt->entries[i].lba_start < gpt->header.first_use_lba ||2708gpt->entries[i].lba_start >= gpt->entries[i].lba_end ||2709!gpt->entries[i].lba_end)2710{2711gpt_oob_empty_part_no++;2712continue;2713}27142715emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t));27162717part->index = i;2718part->lba_start = gpt->entries[i].lba_start;2719part->lba_end = gpt->entries[i].lba_end;27202721// ASCII conversion. Copy only the LSByte of the UTF-16LE name.2722for (u32 j = 0; j < 36; j++)2723part->name[j] = gpt->entries[i].name[j];2724part->name[35] = 0;27252726list_append(&gpt_parsed, &part->link);2727}27282729// Set FAT and emuMMC partitions.2730u32 mbr_idx = 1;2731bool found_hos_data = false;2732u32 emummc_mbr_part_idx[2] = {0};2733LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link)2734{2735// FatFS simple GPT found a fat partition, set it.2736if (sd_fs.part_type && !part->index)2737{2738mbr[1].partitions[0].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC;2739mbr[1].partitions[0].start_sct = part->lba_start;2740mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1;2741}27422743// FatFS simple GPT didn't find a fat partition as the first one.2744if (!sd_fs.part_type && !found_hos_data && !strcmp(part->name, "hos_data"))2745{2746mbr[1].partitions[0].type = 0xC;2747mbr[1].partitions[0].start_sct = part->lba_start;2748mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1;2749found_hos_data = true;2750}27512752// Set up to max 2 emuMMC partitions.2753if (!strcmp(part->name, "emummc") || !strcmp(part->name, "emummc2"))2754{2755mbr[1].partitions[mbr_idx].type = 0xE0;2756mbr[1].partitions[mbr_idx].start_sct = part->lba_start;2757mbr[1].partitions[mbr_idx].size_sct = part->lba_end - part->lba_start + 1;2758if (!strcmp(part->name, "emummc"))2759emummc_mbr_part_idx[0] = mbr_idx;2760else2761emummc_mbr_part_idx[1] = mbr_idx;2762mbr_idx++;2763}27642765// Total reached last slot.2766if (mbr_idx >= 3)2767break;2768}27692770emmc_gpt_free(&gpt_parsed);27712772// Set GPT protective partition.2773mbr[1].partitions[mbr_idx].type = 0xEE;2774mbr[1].partitions[mbr_idx].start_sct = 1;2775mbr[1].partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;27762777// Check for differences.2778for (u32 i = 1; i < 4; i++)2779{2780if ((mbr[0].partitions[i].type != mbr[1].partitions[i].type) ||2781(mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) ||2782(mbr[0].partitions[i].size_sct != mbr[1].partitions[i].size_sct))2783{2784// Check if original MBR already has an emuMMC and use it as source of truth.2785if (mbr[0].partitions[i].type == 0xE0)2786{2787memcpy(&mbr[1].partitions[i], &mbr[0].partitions[i], sizeof(mbr_part_t));2788gpt_emummc_migrate_no++;2789continue;2790}2791else2792hybrid_mbr_changed = true;2793break;2794}2795}27962797check_changes:2798if (!hybrid_mbr_changed && !has_mbr_attributes && !gpt_emummc_migrate_no)2799{2800lv_label_set_text(lbl_status, "#96FF00 Warning:# The Hybrid MBR needs no change!#");2801goto out;2802}28032804char *txt_buf = malloc(SZ_16K);28052806if (hybrid_mbr_changed)2807{2808// Current MBR info.2809s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n");2810s_printf(txt_buf + strlen(txt_buf),2811"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2812"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2813"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2814"Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n",2815mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct,2816mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct,2817mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct,2818mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct);28192820// New MBR info.2821s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n");2822s_printf(txt_buf + strlen(txt_buf),2823"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2824"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2825"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2826"Partition 3 - Type: %02x, Start: %08x, Size: %08x",2827mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct,2828mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct,2829mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct,2830mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct);2831}2832else if (has_mbr_attributes || gpt_emummc_migrate_no || gpt_oob_empty_part_no)2833{2834s_printf(txt_buf, "#00DDFF The following need to be corrected:#\n");2835if (has_mbr_attributes)2836s_printf(txt_buf + strlen(txt_buf), "- MBR attributes\n");2837if (gpt_emummc_migrate_no)2838s_printf(txt_buf + strlen(txt_buf), "- emuMMC GPT Partition address and size\n");2839if (gpt_oob_empty_part_no)2840s_printf(txt_buf + strlen(txt_buf), "- GPT OOB/Empty Partitions (removal)\n");2841}28422843lv_label_set_text(lbl_status, txt_buf);2844lv_label_set_style(lbl_status, &monospace_text);28452846free(txt_buf);28472848lbl_status = lv_label_create(mbox, NULL);2849lv_label_set_recolor(lbl_status, true);2850lv_label_set_align(lbl_status, LV_LABEL_ALIGN_CENTER);28512852lv_label_set_text(lbl_status,2853"#FF8000 Warning: Do you really want to continue?!#\n\n"2854"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");28552856lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2857lv_obj_set_top(mbox, true);28582859manual_system_maintenance(true);28602861if (btn_wait() & BTN_POWER)2862{2863bool has_gpt_changes = false;28642865sd_mount();28662867// Write MBR.2868if (hybrid_mbr_changed)2869sdmmc_storage_write(&sd_storage, 0, 1, &mbr[1]);28702871// Fix MBR secret attributes.2872if (has_mbr_attributes)2873{2874// Clear secret attributes.2875gpt->entries[0].part_guid[7] = 0;2876has_gpt_changes = gpt_partition_exists;28772878if (!has_gpt_changes)2879{2880// Only write the relevant sector if the only change is MBR attributes.2881sdmmc_storage_write(&sd_storage, 2, 1, &gpt->entries[0]);2882}2883}28842885if (gpt_emummc_migrate_no)2886{2887u32 emu_idx = 0;2888for (u32 i = 0; i < gpt->header.num_part_ents; i++)2889{2890if (!memcmp(gpt->entries[i].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12))2891{2892u32 idx = emummc_mbr_part_idx[emu_idx];2893gpt->entries[i].lba_start = mbr[0].partitions[idx].start_sct;2894gpt->entries[i].lba_end = mbr[0].partitions[idx].start_sct + mbr[0].partitions[idx].size_sct - 1;2895gpt_emummc_migrate_no--;2896emu_idx++;28972898has_gpt_changes = true;2899}29002901if (i > 126 || !gpt_emummc_migrate_no)2902break;2903}2904}29052906if (gpt_oob_empty_part_no)2907{2908u32 part_idx = 0;2909for (u32 i = 0; i < gpt->header.num_part_ents; i++)2910{2911if ( gpt->entries[i].lba_start < gpt->header.first_use_lba ||2912gpt->entries[i].lba_start >= gpt->entries[i].lba_end ||2913!gpt->entries[i].lba_end)2914{2915continue;2916}29172918if (part_idx != i)2919memcpy(&gpt->entries[part_idx], &gpt->entries[i], sizeof(gpt_entry_t));2920part_idx++;2921}2922gpt->header.num_part_ents -= gpt_oob_empty_part_no;2923has_gpt_changes = true;2924}29252926if (has_gpt_changes)2927{2928// Fix GPT CRC32s.2929u32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents;2930gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size);2931gpt->header.crc32 = 0; // Set to 0 for calculation.2932gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);29332934gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32;2935gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.2936gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);29372938// Write main GPT.2939u32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE);2940sdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt);29412942// Write backup GPT partition table.2943sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries);29442945// Write backup GPT header.2946sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);2947}29482949sd_unmount();29502951lv_label_set_text(lbl_status, "#96FF00 The new Hybrid MBR was written successfully!#");2952}2953else2954lv_label_set_text(lbl_status, "#FFDD00 Warning: The Hybrid MBR Fix was canceled!#");29552956out:2957free(gpt);29582959lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);29602961lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2962lv_obj_set_top(mbox, true);29632964return LV_RES_OK;2965}29662967lv_res_t create_window_partition_manager(bool emmc)2968{2969lv_obj_t *win;29702971if (!emmc)2972{2973win = nyx_create_standard_window(SYMBOL_SD" SD Partition Manager");2974lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR/GPT", _action_fix_mbr_gpt);2975}2976else2977win = nyx_create_standard_window(SYMBOL_CHIP" eMMC Partition Manager");29782979static lv_style_t bar_hos_bg, bar_emu_bg, bar_l4t_bg, bar_and_bg;2980static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;2981static lv_style_t bar_emu_btn, bar_l4t_btn, bar_and_btn;2982static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;29832984// Set HOS bar styles.2985lv_style_copy(&bar_hos_bg, lv_theme_get_current()->bar.bg);2986bar_hos_bg.body.main_color = LV_COLOR_HEX(0x4A8000);2987bar_hos_bg.body.grad_color = bar_hos_bg.body.main_color;2988lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);2989bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);2990bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;29912992// Set eMUMMC bar styles.2993lv_style_copy(&bar_emu_bg, lv_theme_get_current()->bar.bg);2994bar_emu_bg.body.main_color = LV_COLOR_HEX(0x940F00);2995bar_emu_bg.body.grad_color = bar_emu_bg.body.main_color;2996lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);2997bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);2998bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;2999lv_style_copy(&bar_emu_btn, lv_theme_get_current()->slider.knob);3000bar_emu_btn.body.main_color = LV_COLOR_HEX(0xB31200);3001bar_emu_btn.body.grad_color = bar_emu_btn.body.main_color;3002lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);3003sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);3004sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;3005sep_emu_bg.body.radius = 0;30063007// Set L4T bar styles.3008lv_style_copy(&bar_l4t_bg, lv_theme_get_current()->bar.bg);3009bar_l4t_bg.body.main_color = LV_COLOR_HEX(0x006E80);3010bar_l4t_bg.body.grad_color = bar_l4t_bg.body.main_color;3011lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);3012bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);3013bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;3014lv_style_copy(&bar_l4t_btn, lv_theme_get_current()->slider.knob);3015bar_l4t_btn.body.main_color = LV_COLOR_HEX(0x00B1CC);3016bar_l4t_btn.body.grad_color = bar_l4t_btn.body.main_color;3017lv_style_copy(&sep_l4t_bg, &sep_emu_bg);3018sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);3019sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;30203021// Set Android bar styles.3022lv_style_copy(&bar_and_bg, lv_theme_get_current()->bar.bg);3023bar_and_bg.body.main_color = LV_COLOR_HEX(0x804000);3024bar_and_bg.body.grad_color = bar_and_bg.body.main_color;3025lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);3026bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000);3027bar_and_ind.body.grad_color = bar_and_ind.body.main_color;3028lv_style_copy(&bar_and_btn, lv_theme_get_current()->slider.knob);3029bar_and_btn.body.main_color = LV_COLOR_HEX(0xCC6600);3030bar_and_btn.body.grad_color = bar_and_btn.body.main_color;3031lv_style_copy(&sep_and_bg, &sep_emu_bg);3032sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000);3033sep_and_bg.body.grad_color = sep_and_bg.body.main_color;30343035lv_obj_t *sep = lv_label_create(win, NULL);3036lv_label_set_static_text(sep, "");3037lv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);30383039// Create container to keep content inside.3040lv_obj_t *h1 = lv_cont_create(win, NULL);3041lv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES - LV_DPI);30423043u32 emmc_size = 0;3044if (!emmc)3045{3046if (!sd_mount())3047{3048lv_obj_t *lbl = lv_label_create(h1, NULL);3049lv_label_set_recolor(lbl, true);3050lv_label_set_text(lbl, "#FFDD00 Failed to init SD!#");3051return LV_RES_OK;3052}30533054if (emmc_initialize(false))3055{3056emmc_set_partition(EMMC_GPP);3057emmc_size = emmc_storage.sec_cnt >> 11;3058emmc_end();3059}3060}3061else3062{3063if (!emmc_initialize(false))3064{3065lv_obj_t *lbl = lv_label_create(h1, NULL);3066lv_label_set_recolor(lbl, true);3067lv_label_set_text(lbl, "#FFDD00 Failed to init eMMC!#");3068return LV_RES_OK;3069}3070emmc_set_partition(EMMC_GPP);3071}30723073memset(&part_info, 0, sizeof(partition_ctxt_t));3074if (!emmc)3075_create_mbox_check_files_total_size();30763077char *txt_buf = malloc(SZ_8K);30783079part_info.emmc = emmc;3080part_info.storage = !emmc ? &sd_storage : &emmc_storage;3081part_info.total_sct = part_info.storage->sec_cnt;3082if (emmc)3083part_info.total_sct -= HOS_USER_SECTOR; // Reserved HOS partitions.30843085// Align down total size to ensure alignment of all partitions after HOS one.3086part_info.alignment = part_info.total_sct - ALIGN_DOWN(part_info.total_sct, AU_ALIGN_SECTORS);3087part_info.total_sct -= part_info.alignment;30883089u32 extra_sct = AU_ALIGN_SECTORS + 0x400000; // Reserved 16MB alignment for FAT partition + 2GB.30903091// Set initial HOS partition size, so the correct cluster size can be selected.3092part_info.hos_size = (part_info.total_sct >> 11) - 16; // Important if there's no slider change.30933094// Check if eMMC should be 64GB (Aula).3095part_info.emmc_is_64gb = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA;30963097// Set actual eMMC size.3098part_info.emmc_size_mb = emmc_size;30993100// Set HOS FAT or USER minimum size.3101part_info.hos_min_size = !emmc? HOS_FAT_MIN_SIZE_MB : HOS_USER_MIN_SIZE_MB;31023103// Read current MBR.3104mbr_t mbr = { 0 };3105sdmmc_storage_read(part_info.storage, 0, 1, &mbr);31063107u32 bar_hos_size = lv_obj_get_width(h1);3108u32 bar_emu_size = 0;3109u32 bar_l4t_size = 0;3110u32 bar_and_size = 0;31113112lv_obj_t *lbl = lv_label_create(h1, NULL);3113lv_label_set_recolor(lbl, true);3114lv_label_set_text(lbl, "Choose #FFDD00 new# partition layout:");31153116// Create disk layout blocks.3117// HOS partition block.3118lv_obj_t *bar_hos = lv_bar_create(h1, NULL);3119lv_obj_set_size(bar_hos, bar_hos_size, LV_DPI / 2);3120lv_bar_set_range(bar_hos, 0, 1);3121lv_bar_set_value(bar_hos, 1);3122lv_bar_set_style(bar_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);3123lv_obj_align(bar_hos, lbl, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);3124part_info.bar_hos = bar_hos;31253126// emuMMC partition block.3127lv_obj_t *bar_emu = lv_bar_create(h1, bar_hos);3128lv_obj_set_size(bar_emu, bar_emu_size, LV_DPI / 2);3129lv_bar_set_style(bar_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);3130lv_obj_align(bar_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);3131part_info.bar_emu = bar_emu;31323133// L4T partition block.3134lv_obj_t *bar_l4t = lv_bar_create(h1, bar_hos);3135lv_obj_set_size(bar_l4t, bar_l4t_size, LV_DPI / 2);3136lv_bar_set_style(bar_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);3137lv_obj_align(bar_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);3138part_info.bar_l4t = bar_l4t;31393140// Android partition block.3141lv_obj_t *bar_and = lv_bar_create(h1, bar_hos);3142lv_obj_set_size(bar_and, bar_and_size, LV_DPI / 2);3143lv_bar_set_style(bar_and, LV_BAR_STYLE_INDIC, &bar_and_ind);3144lv_obj_align(bar_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);3145part_info.bar_and = bar_and;31463147// HOS partition block.3148lv_obj_t *sep_emu = lv_cont_create(h1, NULL);3149lv_cont_set_fit(sep_emu, false, false);3150lv_obj_set_size(sep_emu, 0, LV_DPI / 2); // 8.3151lv_obj_set_style(sep_emu, &sep_emu_bg);3152lv_obj_align(sep_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);3153part_info.sep_emu = sep_emu;31543155// Create disk layout blending separators.3156lv_obj_t *sep_l4t = lv_cont_create(h1, sep_emu);3157lv_obj_set_style(sep_l4t, &sep_l4t_bg);3158lv_obj_align(sep_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);3159part_info.sep_l4t = sep_l4t;31603161lv_obj_t *sep_and = lv_cont_create(h1, sep_emu);3162lv_obj_set_style(sep_and, &sep_and_bg);3163lv_obj_align(sep_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);3164part_info.sep_and = sep_and;31653166// Create slider type labels.3167lv_obj_t *cont_lbl_hos = lv_cont_create(h1, NULL);3168lv_cont_set_fit(cont_lbl_hos, false, true);3169lv_obj_set_width(cont_lbl_hos, LV_DPI * 17 / 7);3170lv_obj_t *lbl_hos = lv_label_create(cont_lbl_hos, NULL);3171lv_label_set_recolor(lbl_hos, true);3172lv_label_set_static_text(lbl_hos, !emmc ? "#96FF00 "SYMBOL_DOT" HOS (FAT32):#" :3173"#96FF00 "SYMBOL_DOT" eMMC (USER):#");3174lv_obj_align(lbl_hos, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);31753176lv_obj_t *lbl_emu = lbl_hos;3177if (!emmc)3178{3179lbl_emu = lv_label_create(h1, lbl_hos);3180lv_label_set_static_text(lbl_emu, "#FF3C28 "SYMBOL_DOT" emuMMC (RAW):#");3181lv_obj_align(lbl_emu, lbl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);3182}31833184lv_obj_t *lbl_l4t = lv_label_create(h1, lbl_hos);3185lv_label_set_static_text(lbl_l4t, "#00DDFF "SYMBOL_DOT" Linux (EXT4):#");3186lv_obj_align(lbl_l4t, lbl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);31873188lv_obj_t *lbl_and = lv_label_create(h1, lbl_hos);3189lv_label_set_static_text(lbl_and, "#FF8000 "SYMBOL_DOT" Android (USER):#");3190lv_obj_align(lbl_and, lbl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);31913192// Create HOS size slider. Non-interactive.3193lv_obj_t *slider_bar_hos = lv_bar_create(h1, NULL);3194lv_obj_set_size(slider_bar_hos, LV_DPI * 7, LV_DPI * 3 / 17);3195lv_bar_set_range(slider_bar_hos, 0, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);3196lv_bar_set_value(slider_bar_hos, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);3197lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_BG, &bar_hos_bg);3198lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_INDIC, &bar_hos_ind);3199lv_obj_align(slider_bar_hos, cont_lbl_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI, 0);3200part_info.slider_bar_hos = slider_bar_hos;32013202lv_obj_t *slider_emu = slider_bar_hos;3203if (!emmc)3204{3205// Create emuMMC size slider.3206slider_emu = lv_slider_create(h1, NULL);3207lv_obj_set_size(slider_emu, LV_DPI * 7, LV_DPI / 3);3208lv_slider_set_range(slider_emu, EMU_SLIDER_MIN, EMU_SLIDER_MAX);3209lv_slider_set_value(slider_emu, EMU_SLIDER_MIN);3210lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_BG, &bar_emu_bg);3211lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_INDIC, &bar_emu_ind);3212lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_KNOB, &bar_emu_btn);3213lv_obj_align(slider_emu, slider_bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 + 5);3214lv_slider_set_action(slider_emu, _action_slider_emu);3215}32163217// Create L4T size slider.3218lv_obj_t *slider_l4t = lv_slider_create(h1, NULL);3219lv_obj_set_size(slider_l4t, LV_DPI * 7, LV_DPI / 3);3220lv_slider_set_range(slider_l4t, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB);3221lv_slider_set_value(slider_l4t, 0);3222lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_BG, &bar_l4t_bg);3223lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_INDIC, &bar_l4t_ind);3224lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_KNOB, &bar_l4t_btn);3225lv_obj_align(slider_l4t, slider_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, !emmc ? (LV_DPI / 3 - 3) : (LV_DPI / 3 + 5));3226lv_slider_set_action(slider_l4t, _action_slider_l4t);32273228// Create Android size slider.3229lv_obj_t *slider_and = lv_slider_create(h1, NULL);3230lv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3);3231lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - (AND_SYS_SIZE_MB / 1024)); // Subtract android reserved size.3232lv_slider_set_value(slider_and, 0);3233lv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg);3234lv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind);3235lv_slider_set_style(slider_and, LV_SLIDER_STYLE_KNOB, &bar_and_btn);3236lv_obj_align(slider_and, slider_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3);3237lv_slider_set_action(slider_and, _action_slider_and);32383239// Create container for the labels.3240lv_obj_t *cont_lbl = lv_cont_create(h1, NULL);3241lv_cont_set_fit(cont_lbl, false, true);3242lv_obj_set_width(cont_lbl, LV_DPI * 3 / 2);3243part_info.cont_lbl = cont_lbl;32443245// Create HOS size label.3246lv_obj_t *lbl_sl_hos = lv_label_create(cont_lbl, NULL);3247lv_label_set_recolor(lbl_sl_hos, true);3248lv_label_set_align(lbl_sl_hos, LV_LABEL_ALIGN_RIGHT);3249s_printf(txt_buf, "#96FF00 %4d GiB#", (part_info.total_sct - AU_ALIGN_SECTORS) >> 11 >> 10);3250lv_label_set_text(lbl_sl_hos, txt_buf);3251lv_obj_align(lbl_sl_hos, cont_lbl, LV_ALIGN_IN_TOP_RIGHT, 0, 0);3252part_info.lbl_hos = lbl_sl_hos;32533254// Create emuMMC size label.3255part_info.lbl_emu = lbl_sl_hos;3256if (!emmc)3257{3258lv_obj_t *lbl_sl_emu = lv_label_create(cont_lbl, lbl_sl_hos);3259lv_label_set_text(lbl_sl_emu, "#FF3C28 0 GiB#");3260lv_obj_align(lbl_sl_emu, lbl_sl_hos, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);3261part_info.lbl_emu = lbl_sl_emu;3262}32633264// Create L4T size label.3265lv_obj_t *lbl_sl_l4t = lv_label_create(cont_lbl, lbl_sl_hos);3266lv_label_set_text(lbl_sl_l4t, "#00DDFF 0 GiB#");3267lv_obj_align(lbl_sl_l4t, part_info.lbl_emu, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);3268part_info.lbl_l4t = lbl_sl_l4t;32693270// Create Android size label.3271lv_obj_t *lbl_sl_and = lv_label_create(cont_lbl, lbl_sl_hos);3272lv_label_set_text(lbl_sl_and, "#FF8000 0 GiB#");3273lv_obj_align(lbl_sl_and, lbl_sl_l4t, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);3274part_info.lbl_and = lbl_sl_and;32753276lv_obj_align(cont_lbl, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 11 - LV_DPI / 2, LV_DPI * 9 / 23);32773278// Set partition manager notes.3279lv_obj_t *lbl_notes = lv_label_create(h1, NULL);3280lv_label_set_recolor(lbl_notes, true);3281lv_label_set_style(lbl_notes, &hint_small_style);3282if (!emmc)3283{3284lv_label_set_static_text(lbl_notes,3285"Note 1: Only up to #C7EA46 1.2GB# can be backed up. If more, you will be asked to back them manually at the next step.\n"3286"Note 2: Resized emuMMC formats the USER partition. A save data manager can be used to move them over.\n"3287"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n");3288lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 2);3289}3290else3291{3292lv_label_set_static_text(lbl_notes,3293"Note 1: Any partition existing after the selected ones gets removed from the table.\n"3294"Note 2: The HOS USER partition gets formatted. A save data manager can be used to move them over.\n"3295"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n");3296lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 4);3297}32983299lv_obj_t *btn1 = NULL;3300lv_obj_t *label_btn = NULL;3301if (!emmc)3302{3303// Create UMS button.3304btn1 = lv_btn_create(h1, NULL);3305lv_obj_t *label_btn = lv_label_create(btn1, NULL);3306lv_btn_set_fit(btn1, true, true);3307lv_label_set_static_text(label_btn, SYMBOL_USB" SD UMS");3308lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);3309lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_part_manager_ums_sd);3310}33113312// Create Flash Linux button.3313btn_flash_l4t = lv_btn_create(h1, NULL);3314label_btn = lv_label_create(btn_flash_l4t, NULL);3315lv_btn_set_fit(btn_flash_l4t, true, true);3316lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Linux");3317if (!emmc)3318lv_obj_align(btn_flash_l4t, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);3319else3320lv_obj_align(btn_flash_l4t, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);3321lv_btn_set_action(btn_flash_l4t, LV_BTN_ACTION_CLICK, _action_check_flash_linux);33223323// Disable Flash Linux button if partition not found.3324u32 size_sct = _get_available_l4t_partition();3325if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)3326{3327lv_obj_set_click(btn_flash_l4t, false);3328lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);3329}33303331int part_type_and = _get_available_android_partition();33323333// Create Flash Android button.3334btn_flash_android = lv_btn_create(h1, NULL);3335label_btn = lv_label_create(btn_flash_android, NULL);3336lv_btn_set_fit(btn_flash_android, true, true);3337switch (part_type_and)3338{3339case 0: // Disable Flash Android button if partition not found.3340lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android");3341lv_obj_set_click(btn_flash_android, false);3342lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);3343break;3344case 1: // Android 10/11.3345lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 10/11");3346break;3347case 2: // Android 13+3348lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 13+");3349break;3350}3351lv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);3352lv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android);33533354// Create next step button.3355btn1 = lv_btn_create(h1, NULL);3356label_btn = lv_label_create(btn1, NULL);3357lv_btn_set_fit(btn1, true, true);3358lv_label_set_static_text(label_btn, SYMBOL_SD" Next Step");3359lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_RIGHT, 0, LV_DPI * 5);3360lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _create_mbox_partitioning_next);3361part_info.partition_button = btn1;33623363free(txt_buf);33643365if (!emmc)3366sd_unmount();3367else3368emmc_end();33693370return LV_RES_OK;3371}33723373lv_res_t create_window_sd_partition_manager(lv_obj_t *btn) { return create_window_partition_manager(false); }3374lv_res_t create_window_emmc_partition_manager(lv_obj_t *btn) { return create_window_partition_manager(true); }337533763377