Path: blob/master/nyx/nyx_gui/frontend/gui_tools_partition_manager.c
3711 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_ALT_DMA_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_ALT_DMA_BUFFER, 0, AU_ALIGN_BYTES);342sdmmc_storage_write(&sd_storage, 0, AU_ALIGN_SECTORS, (void *)SDMMC_ALT_DMA_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_ALT_DMA_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_ALT_DMA_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 };553554memset((void *)SDMMC_ALT_DMA_BUFFER, 0, AU_ALIGN_BYTES);555556// Read main GPT.557sdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt);558559// Set GPT header.560gpt->header.alt_lba = emmc_storage.sec_cnt - 1;561gpt->header.last_use_lba = emmc_storage.sec_cnt - 0x800 - 1; // emmc_storage.sec_cnt - 33 is start of backup gpt partition entries.562563// Calculate HOS USER partition564u32 part_rsvd_size = (part_info.l4t_size << 11) + (part_info.and_size << 11);565part_rsvd_size += part_rsvd_size ? part_info.alignment : 0x800; // Only reserve 1MB if no extra partitions.566u32 hos_user_size = emmc_storage.sec_cnt - HOS_USER_SECTOR - part_rsvd_size;567568// Get HOS USER partition index.569LIST_INIT(gpt_emmc);570emmc_gpt_parse(&gpt_emmc);571emmc_part_t *user_part = emmc_part_find(&gpt_emmc, "USER");572if (!user_part)573{574emmc_gpt_free(&gpt_emmc);575free(gpt);576577return 1;578}579u8 gpt_idx = user_part->index;580emmc_gpt_free(&gpt_emmc);581582// HOS USER partition.583u32 curr_part_lba = gpt->entries[gpt_idx].lba_start;584gpt->entries[gpt_idx].lba_end = curr_part_lba + hos_user_size - 1;585586curr_part_lba += hos_user_size;587gpt_idx++;588589// L4T partition.590if (part_info.l4t_size)591{592u32 l4t_size = part_info.l4t_size << 11;593if (!part_info.and_size)594l4t_size -= 0x800; // Reserve 1MB.595_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, l4t_size, "l4t", 6);596}597598if (part_info.and_size && part_info.and_dynamic)599{600// Android Linux Kernel partition. 64MB.601_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "boot", 8);602603// Android Recovery partition. 64MB.604_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "recovery", 16);605606// Android Device Tree Reference partition. 1MB.607_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "dtb", 6);608609// Android Misc partition. 3MB.610_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "misc", 8);611612// Android Cache partition. 60MB.613_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1E000, "cache", 10);614615// Android Super dynamic partition. 5952MB.616_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xBA0000, "super", 10);617618// Android Userdata partition.619u32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).620uda_size -= 0x800; // Reserve 1MB.621_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "userdata", 16);622}623else if (part_info.and_size)624{625// Android Vendor partition. 1GB626_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, "vendor", 12);627628// Android System partition. 3GB.629_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, "APP", 6);630631// Android Linux Kernel partition. 32MB.632_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x10000, "LNX", 6);633634// Android Recovery partition. 64MB.635_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "SOS", 6);636637// Android Device Tree Reference partition. 1MB.638_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "DTB", 6);639640// Android Encryption partition. 16MB.641// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.642sdmmc_storage_write(&emmc_storage, curr_part_lba, 0x8000, (void *)SDMMC_ALT_DMA_BUFFER); // Clear the whole of it.643_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x8000, "MDA", 6);644645// Android Cache partition. 700MB.646_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, "CAC", 6);647648// Android Misc partition. 3MB.649_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "MSC", 6);650651// Android Userdata partition.652u32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).653uda_size -= 0x800; // Reserve 1MB.654_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "UDA", 6);655}656657// Clear the rest of GPT partition table.658for (u32 i = gpt_idx; i < 128; i++)659memset(&gpt->entries[i], 0, sizeof(gpt_entry_t));660661// Set final GPT header parameters.662gpt->header.num_part_ents = gpt_idx;663gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);664gpt->header.crc32 = 0; // Set to 0 for calculation.665gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);666667// Set final backup GPT header parameters.668memcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));669gpt_hdr_backup.my_lba = emmc_storage.sec_cnt - 1;670gpt_hdr_backup.alt_lba = 1;671gpt_hdr_backup.part_ent_lba = emmc_storage.sec_cnt - 33;672gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.673gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);674675// Write main GPT.676sdmmc_storage_write(&emmc_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);677678// Write backup GPT partition table.679sdmmc_storage_write(&emmc_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);680681// Write backup GPT header.682sdmmc_storage_write(&emmc_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);683684// Clear nand patrol.685u8 *buf = (u8 *)gpt;686memset(buf, 0, EMMC_BLOCKSIZE);687emmc_set_partition(EMMC_BOOT0);688sdmmc_storage_write(&emmc_storage, NAND_PATROL_SECTOR, 1, buf);689emmc_set_partition(EMMC_GPP);690691free(gpt);692693return 0;694}695696static lv_res_t _action_part_manager_ums_sd(lv_obj_t *btn)697{698action_ums_sd(NULL);699700// Close and reopen partition manager.701lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK);702close_btn_action(close_btn);703lv_obj_del(ums_mbox);704create_window_sd_partition_manager(NULL);705706return LV_RES_INV;707}708709static lv_res_t _action_delete_linux_installer_files(lv_obj_t * btns, const char * txt)710{711712int btn_idx = lv_btnm_get_pressed(btns);713714// Delete parent mbox.715nyx_mbox_action(btns, txt);716717// Flash Linux.718if (!btn_idx)719{720char path[128];721722sd_mount();723724strcpy(path, "switchroot/install/l4t.");725726// Delete all l4t.xx files.727u32 idx = 0;728while (true)729{730if (idx < 10)731{732path[23] = '0';733itoa(idx, &path[23 + 1], 10);734}735else736itoa(idx, &path[23], 10);737738if (!f_stat(path, NULL))739{740f_unlink(path);741}742else743break;744745idx++;746}747748sd_unmount();749}750751return LV_RES_INV;752}753754static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt)755{756int btn_idx = lv_btnm_get_pressed(btns);757758// Delete parent mbox.759nyx_mbox_action(btns, txt);760761bool succeeded = false;762763if (btn_idx)764return LV_RES_INV;765766// Flash Linux.767lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);768lv_obj_set_style(dark_bg, &mbox_darken);769lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);770771static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };772static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "" };773lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);774lv_mbox_set_recolor_text(mbox, true);775lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);776777lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");778779lv_obj_t *lbl_status = lv_label_create(mbox, NULL);780lv_label_set_recolor(lbl_status, true);781lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux...");782783// Create container to keep content inside.784lv_obj_t *h1 = lv_cont_create(mbox, NULL);785lv_cont_set_fit(h1, true, true);786lv_cont_set_style(h1, &lv_style_transp_tight);787788lv_obj_t *bar = lv_bar_create(h1, NULL);789lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5);790lv_bar_set_range(bar, 0, 100);791lv_bar_set_value(bar, 0);792793lv_obj_t *label_pct = lv_label_create(h1, NULL);794lv_label_set_recolor(label_pct, true);795lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%");796lv_label_set_style(label_pct, lv_theme_get_current()->label.prim);797lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);798799lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);800lv_obj_set_top(mbox, true);801802sd_mount();803if (part_info.emmc)804emmc_initialize(false);805806int res = 0;807char *path = malloc(1024);808char *txt_buf = malloc(SZ_4K);809strcpy(path, "switchroot/install/l4t.00");810u32 path_len = strlen(path) - 2;811812FIL fp;813814res = f_open(&fp, path, FA_READ);815if (res)816{817lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!");818819goto exit;820}821822u64 fileSize = (u64)f_size(&fp);823824u32 num = 0;825u32 pct = 0;826u32 lba_curr = 0;827u32 bytesWritten = 0;828u32 currPartIdx = 0;829u32 prevPct = 200;830int retryCount = 0;831u32 total_size_sct = l4t_flash_ctxt.image_size_sct;832833u8 *buf = (u8 *)MIXD_BUF_ALIGNED;834DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);835836// Start flashing L4T.837while (total_size_sct > 0)838{839// 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.840if (bytesWritten >= fileSize)841{842// If we have more bytes written then close the file pointer and increase the part index we are using843f_close(&fp);844free(clmt);845memset(&fp, 0, sizeof(fp));846currPartIdx++;847848if (currPartIdx < 10)849{850path[path_len] = '0';851itoa(currPartIdx, &path[path_len + 1], 10);852}853else854itoa(currPartIdx, &path[path_len], 10);855856// Try to open the next file part857res = f_open(&fp, path, FA_READ);858if (res)859{860s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx);861lv_label_set_text(lbl_status, txt_buf);862manual_system_maintenance(true);863864goto exit;865}866fileSize = (u64)f_size(&fp);867bytesWritten = 0;868clmt = f_expand_cltbl(&fp, SZ_4M, 0);869}870871retryCount = 0;872num = MIN(total_size_sct, 8192);873874// Read next data block from SD.875res = f_read_fast(&fp, buf, num << 9);876manual_system_maintenance(false);877878if (res)879{880lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!");881manual_system_maintenance(true);882883f_close(&fp);884free(clmt);885goto exit;886}887888// Write data block to L4T partition.889res = sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);890891manual_system_maintenance(false);892893// If failed, retry 3 more times.894while (res)895{896msleep(150);897manual_system_maintenance(true);898899if (retryCount >= 3)900{901lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!");902manual_system_maintenance(true);903904f_close(&fp);905free(clmt);906goto exit;907}908909res = sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);910manual_system_maintenance(false);911}912913// Update completion percentage.914pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct;915if (pct != prevPct)916{917lv_bar_set_value(bar, pct);918s_printf(txt_buf, " #DDDDDD "SYMBOL_DOT"# %d%%", pct);919lv_label_set_text(label_pct, txt_buf);920manual_system_maintenance(true);921prevPct = pct;922}923924lba_curr += num;925total_size_sct -= num;926bytesWritten += num * EMMC_BLOCKSIZE;927}928lv_bar_set_value(bar, 100);929lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%");930manual_system_maintenance(true);931932// Restore operation ended successfully.933f_close(&fp);934free(clmt);935936succeeded = true;937938exit:939free(path);940free(txt_buf);941942if (!succeeded)943lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);944else945lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files);946lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);947948sd_unmount();949if (part_info.emmc)950emmc_end();951952return LV_RES_INV;953}954955static u32 _get_available_l4t_partition()956{957mbr_t mbr = { 0 };958gpt_t *gpt = zalloc(sizeof(gpt_t));959960memset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t));961962// Read MBR.963sdmmc_storage_read(part_info.storage, 0, 1, &mbr);964965// Read main GPT.966sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);967968// Search for a suitable partition.969u32 size_sct = 0;970if (!memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)971{972for (u32 i = 0; i < gpt->header.num_part_ents; i++)973{974if (!memcmp(gpt->entries[i].name, (u16[]) { 'l', '4', 't' }, 6))975{976l4t_flash_ctxt.offset_sct = gpt->entries[i].lba_start;977size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;978break;979}980}981}982else983{984for (u32 i = 1; i < 4; i++)985{986if (mbr.partitions[i].type == 0x83)987{988l4t_flash_ctxt.offset_sct = mbr.partitions[i].start_sct;989size_sct = mbr.partitions[i].size_sct;990break;991}992}993}994995free(gpt);996997return size_sct;998}9991000static int _get_available_android_partition()1001{1002gpt_t *gpt = zalloc(sizeof(gpt_t));10031004// Read main GPT.1005sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);10061007// Check if GPT.1008if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)1009goto out;10101011// Find kernel partition.1012for (u32 i = 0; i < gpt->header.num_part_ents; i++)1013{1014if (gpt->entries[i].lba_start)1015{1016int found = !memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8) ? 2 : 0;1017found |= !memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' }, 6) ? 1 : 0;10181019if (found)1020{1021free(gpt);10221023return found;1024}1025}1026}10271028out:1029free(gpt);10301031return false;1032}10331034static lv_res_t _action_check_flash_linux(lv_obj_t *btn)1035{1036FILINFO fno;1037char path[128];10381039lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1040lv_obj_set_style(dark_bg, &mbox_darken);1041lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);10421043static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1044static const char *mbox_btn_map2[] = { "\222Continue", "\222Cancel", "" };1045lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1046lv_mbox_set_recolor_text(mbox, true);1047lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);10481049lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");10501051lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1052lv_label_set_recolor(lbl_status, true);1053lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");10541055lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1056lv_obj_set_top(mbox, true);10571058manual_system_maintenance(true);10591060sd_mount();1061if (part_info.emmc)1062emmc_initialize(false);10631064// Check if L4T image exists.1065strcpy(path, "switchroot/install/l4t.00");1066if (f_stat(path, NULL))1067{1068lv_label_set_text(lbl_status, "#FFDD00 Error:# Installation files not found!");1069goto error;1070}10711072// Find an applicable partition for L4T.1073u32 size_sct = _get_available_l4t_partition();1074if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)1075{1076lv_label_set_text(lbl_status, "#FFDD00 Error:# No partition found!");1077goto error;1078}10791080u32 idx = 0;1081path[23] = 0;10821083// Validate L4T images and consolidate their info.1084while (true)1085{1086if (idx < 10)1087{1088path[23] = '0';1089itoa(idx, &path[23 + 1], 10);1090}1091else1092itoa(idx, &path[23], 10);10931094// Check for alignment.1095if (f_stat(path, &fno))1096break;10971098// Check if current part is unaligned.1099if ((u64)fno.fsize % SZ_4M)1100{1101// Get next part filename.1102idx++;1103if (idx < 10)1104{1105path[23] = '0';1106itoa(idx, &path[23 + 1], 10);1107}1108else1109itoa(idx, &path[23], 10);11101111// If it exists, unaligned size for current part is not permitted.1112if (!f_stat(path, NULL)) // NULL: Don't override current part fs info.1113{1114lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!");1115goto error;1116}11171118// Last part. Align size to LBA (SD_BLOCKSIZE).1119fno.fsize = ALIGN((u64)fno.fsize, SD_BLOCKSIZE);1120idx--;1121}1122l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9;11231124idx++;1125}11261127// Check if image size is bigger than the partition available.1128if (l4t_flash_ctxt.image_size_sct > size_sct)1129{1130lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is bigger than the partition!");1131goto error;1132}11331134char *txt_buf = malloc(SZ_4K);1135s_printf(txt_buf,1136"#C7EA46 Status:# Found installation files and partition.\n"1137"#00DDFF Offset:# %08x, #00DDFF Size:# %X, #00DDFF Image size:# %d MiB\n"1138"\nDo you want to continue?", l4t_flash_ctxt.offset_sct, size_sct, l4t_flash_ctxt.image_size_sct >> 11);1139lv_label_set_text(lbl_status, txt_buf);1140free(txt_buf);1141lv_mbox_add_btns(mbox, mbox_btn_map2, _action_flash_linux_data);1142goto exit;11431144error:1145lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);11461147exit:1148lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);11491150sd_unmount();1151if (part_info.emmc)1152emmc_end();11531154return LV_RES_OK;1155}11561157static lv_res_t _action_reboot_recovery(lv_obj_t * btns, const char * txt)1158{1159int btn_idx = lv_btnm_get_pressed(btns);11601161// Delete parent mbox.1162nyx_mbox_action(btns, txt);11631164if (!btn_idx)1165{1166// Set custom reboot type to Android Recovery.1167PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY;11681169// Enable hekate boot configuration.1170b_cfg->boot_cfg = BOOT_CFG_FROM_ID | BOOT_CFG_AUTOBOOT_EN;11711172// Set id to Android.1173strcpy((char *)b_cfg->id, "SWANDR");11741175void (*main_ptr)() = (void *)nyx_str->hekate;11761177// Deinit hardware.1178sd_end();1179hw_deinit(false);11801181// Chainload to hekate main.1182(*main_ptr)();1183}11841185return LV_RES_INV;1186}11871188static lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt)1189{1190int btn_idx = lv_btnm_get_pressed(btns);1191bool boot_recovery = false;11921193// Delete parent mbox.1194nyx_mbox_action(btns, txt);11951196if (btn_idx)1197return LV_RES_INV;11981199// Flash Android components.1200char path[128];1201gpt_t *gpt = zalloc(sizeof(gpt_t));1202char *txt_buf = malloc(SZ_4K);12031204lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1205lv_obj_set_style(dark_bg, &mbox_darken);1206lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);12071208static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1209static const char *mbox_btn_map2[] = { "\222Continue", "\222No", "" };1210lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1211lv_mbox_set_recolor_text(mbox, true);1212lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);12131214lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");12151216lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1217lv_label_set_recolor(lbl_status, true);1218lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");12191220lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1221lv_obj_set_top(mbox, true);12221223manual_system_maintenance(true);12241225sd_mount();1226if (part_info.emmc)1227emmc_initialize(false);12281229// Read main GPT.1230sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);12311232// Validate GPT header.1233if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)1234{1235lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!");1236goto error;1237}12381239u32 offset_sct = 0;1240u32 size_sct = 0;12411242// Check if Kernel image should be flashed.1243strcpy(path, "switchroot/install/boot.img");1244if (f_stat(path, NULL))1245{1246s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n");1247goto boot_img_not_found;1248}12491250// Find Kernel partition.1251for (u32 i = 0; i < gpt->header.num_part_ents; i++)1252{1253if (!memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' }, 6) ||1254!memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8))1255{1256offset_sct = gpt->entries[i].lba_start;1257size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1258break;1259}1260}12611262// Flash Kernel.1263if (offset_sct && size_sct)1264{1265u32 file_size = 0;1266u8 *buf = sd_file_read(path, &file_size);12671268if (file_size % 0x200)1269{1270file_size = ALIGN(file_size, 0x200);1271u8 *buf_tmp = zalloc(file_size);1272memcpy(buf_tmp, buf, file_size);1273free(buf);1274buf = buf_tmp;1275}12761277if ((file_size >> 9) > size_sct)1278s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n");1279else1280{1281sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);12821283s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n");1284f_unlink(path);1285}12861287free(buf);1288}1289else1290s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n");12911292boot_img_not_found:1293lv_label_set_text(lbl_status, txt_buf);1294manual_system_maintenance(true);12951296// Check if Recovery should be flashed.1297strcpy(path, "switchroot/install/recovery.img");1298if (f_stat(path, NULL))1299{1300// Not found, try twrp.img instead.1301strcpy(path, "switchroot/install/twrp.img");1302if (f_stat(path, NULL))1303{1304strcat(txt_buf, "#FF8000 Warning:# Recovery image not found!\n");1305goto recovery_not_found;1306}1307}13081309offset_sct = 0;1310size_sct = 0;13111312// Find Recovery partition.1313for (u32 i = 0; i < gpt->header.num_part_ents; i++)1314{1315if (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' }, 6) ||1316!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))1317{1318offset_sct = gpt->entries[i].lba_start;1319size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1320break;1321}1322}13231324// Flash Recovery.1325if (offset_sct && size_sct)1326{1327u32 file_size = 0;1328u8 *buf = sd_file_read(path, &file_size);13291330if (file_size % 0x200)1331{1332file_size = ALIGN(file_size, 0x200);1333u8 *buf_tmp = zalloc(file_size);1334memcpy(buf_tmp, buf, file_size);1335free(buf);1336buf = buf_tmp;1337}13381339if ((file_size >> 9) > size_sct)1340strcat(txt_buf, "#FF8000 Warning:# Recovery image too big!\n");1341else1342{1343sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);1344strcat(txt_buf, "#C7EA46 Success:# Recovery image flashed!\n");1345f_unlink(path);1346}13471348free(buf);1349}1350else1351strcat(txt_buf, "#FF8000 Warning:# Recovery partition not found!\n");13521353recovery_not_found:1354lv_label_set_text(lbl_status, txt_buf);1355manual_system_maintenance(true);13561357// Check if Device Tree should be flashed.1358strcpy(path, "switchroot/install/nx-plat.dtimg");1359if (f_stat(path, NULL))1360{1361strcpy(path, "switchroot/install/tegra210-icosa.dtb");1362if (f_stat(path, NULL))1363{1364strcat(txt_buf, "#FF8000 Warning:# DTB image not found!");1365goto dtb_not_found;1366}1367}13681369offset_sct = 0;1370size_sct = 0;13711372// Find Device Tree partition.1373for (u32 i = 0; i < gpt->header.num_part_ents; i++)1374{1375if (!memcmp(gpt->entries[i].name, (u16[]) { 'D', 'T', 'B' }, 6) ||1376!memcmp(gpt->entries[i].name, (u16[]) { 'd', 't', 'b' }, 6))1377{1378offset_sct = gpt->entries[i].lba_start;1379size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;1380break;1381}1382}13831384// Flash Device Tree.1385if (offset_sct && size_sct)1386{1387u32 file_size = 0;1388u8 *buf = sd_file_read(path, &file_size);13891390if (file_size % 0x200)1391{1392file_size = ALIGN(file_size, 0x200);1393u8 *buf_tmp = zalloc(file_size);1394memcpy(buf_tmp, buf, file_size);1395free(buf);1396buf = buf_tmp;1397}13981399if ((file_size >> 9) > size_sct)1400strcat(txt_buf, "#FF8000 Warning:# DTB image too big!");1401else1402{1403sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);1404strcat(txt_buf, "#C7EA46 Success:# DTB image flashed!");1405f_unlink(path);1406}14071408free(buf);1409}1410else1411strcat(txt_buf, "#FF8000 Warning:# DTB partition not found!");14121413dtb_not_found:1414lv_label_set_text(lbl_status, txt_buf);14151416// Check if Recovery is flashed unconditionally.1417u8 *rec = malloc(SD_BLOCKSIZE);1418for (u32 i = 0; i < gpt->header.num_part_ents; i++)1419{1420if (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' }, 6) ||1421!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))1422{1423sdmmc_storage_read(part_info.storage, gpt->entries[i].lba_start, 1, rec);1424if (!memcmp(rec, "ANDROID", 7))1425boot_recovery = true;1426break;1427}1428}1429free(rec);14301431error:1432if (boot_recovery)1433{1434// If a Recovery partition was found, ask user if rebooting into it is wanted.1435strcat(txt_buf,"\n\nDo you want to reboot into Recovery\nto finish Android installation?");1436lv_label_set_text(lbl_status, txt_buf);1437lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_recovery);1438}1439else1440lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);14411442lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);14431444free(txt_buf);1445free(gpt);14461447sd_unmount();1448if (part_info.emmc)1449emmc_end();14501451return LV_RES_INV;1452}14531454static lv_res_t _action_flash_android(lv_obj_t *btn)1455{1456lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1457lv_obj_set_style(dark_bg, &mbox_darken);1458lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);14591460static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" };1461lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1462lv_mbox_set_recolor_text(mbox, true);1463lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);14641465lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");14661467lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1468lv_label_set_recolor(lbl_status, true);1469lv_label_set_text(lbl_status,1470"This will flash #C7EA46 Kernel#, #C7EA46 DTB# and #C7EA46 Recovery# if found.\n"1471"These will be deleted after a successful flash.\n"1472"Do you want to continue?");14731474lv_mbox_add_btns(mbox, mbox_btn_map, _action_flash_android_data);1475lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1476lv_obj_set_top(mbox, true);14771478return LV_RES_OK;1479}14801481static lv_res_t _action_part_manager_flash_options0(lv_obj_t *btns, const char *txt)1482{1483int btn_idx = lv_btnm_get_pressed(btns);1484if (part_info.emmc)1485btn_idx++;14861487switch (btn_idx)1488{1489case 0:1490action_ums_sd(NULL);1491lv_obj_del(ums_mbox);1492break;1493case 1:1494_action_check_flash_linux(NULL);1495break;1496case 2:1497_action_flash_android(NULL);1498break;1499case 3:1500nyx_mbox_action(btns, txt);1501return LV_RES_INV;1502}15031504return LV_RES_OK;1505}15061507static lv_res_t _action_part_manager_flash_options1(lv_obj_t *btns, const char *txt)1508{1509int btn_idx = lv_btnm_get_pressed(btns);1510if (part_info.emmc)1511btn_idx++;15121513switch (btn_idx)1514{1515case 0:1516action_ums_sd(NULL);1517lv_obj_del(ums_mbox);1518break;1519case 1:1520nyx_mbox_action(btns, txt);1521_action_check_flash_linux(NULL);1522return LV_RES_INV;1523case 2:1524nyx_mbox_action(btns, txt);1525return LV_RES_INV;1526}15271528return LV_RES_OK;1529}15301531static lv_res_t _action_part_manager_flash_options2(lv_obj_t *btns, const char *txt)1532{1533int btn_idx = lv_btnm_get_pressed(btns);1534if (part_info.emmc)1535btn_idx++;15361537switch (btn_idx)1538{1539case 0:1540action_ums_sd(NULL);1541lv_obj_del(ums_mbox);1542break;1543case 1:1544nyx_mbox_action(btns, txt);1545_action_flash_android(NULL);1546return LV_RES_INV;1547case 2:1548nyx_mbox_action(btns, txt);1549return LV_RES_INV;1550}15511552return LV_RES_OK;1553}15541555static int _backup_and_restore_files(bool backup, lv_obj_t **labels)1556{1557const char *src_drv = backup ? "sd:" : "ram:";1558const char *dst_drv = backup ? "ram:" : "sd:";15591560int res = 0;1561u32 total_size = 0;1562u32 total_files = 0;1563char *path = malloc(0x1000);1564path[0] = 0; // Set default as root folder.15651566// Check if Mariko Warmboot Storage exists in source drive.1567f_chdrive(src_drv);1568bool backup_pld = !part_info.backup_possible && !f_stat("payload.bin", NULL);15691570if (!part_info.backup_possible)1571{1572// Change path to hekate/Nyx.1573strcpy(path, "bootloader");15741575// Create hekate/Nyx/MWS folders in destination drive.1576f_chdrive(dst_drv);1577f_mkdir("bootloader");1578}15791580// Copy all or hekate/Nyx files.1581res = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels);15821583// If incomplete backup mode, copy MWS and payload.bin also.1584if (!res)1585{1586if (!res && backup_pld)1587{1588strcpy(path, "payload.bin");1589res = _copy_file(src_drv, dst_drv, path);1590}1591}15921593free(path);15941595return res;1596}15971598static lv_res_t _sd_create_mbox_start_partitioning()1599{1600lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1601lv_obj_set_style(dark_bg, &mbox_darken);1602lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);16031604static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1605static const char *mbox_btn_map1[] = { "\222SD UMS", "\222Flash Linux", "\222Flash Android", "\221OK", "" };1606static const char *mbox_btn_map2[] = { "\222SD UMS", "\222Flash Linux", "\221OK", "" };1607static const char *mbox_btn_map3[] = { "\222SD UMS", "\222Flash Android", "\221OK", "" };1608lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1609lv_mbox_set_recolor_text(mbox, true);1610lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);16111612lv_mbox_set_text(mbox, "#FF8000 SD Partition Manager#");1613lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1614lv_obj_set_top(mbox, true);16151616bool buttons_set = false;16171618// Use safety wait if backup is not possible.1619char *txt_buf = malloc(SZ_4K);1620strcpy(txt_buf, "#FF8000 SD Partition Manager#\n\nSafety wait ends in ");1621lv_mbox_set_text(mbox, txt_buf);16221623u32 seconds = 5;1624u32 text_idx = strlen(txt_buf);1625while (seconds)1626{1627s_printf(txt_buf + text_idx, "%d seconds...", seconds);1628lv_mbox_set_text(mbox, txt_buf);1629manual_system_maintenance(true);1630msleep(1000);1631seconds--;1632}16331634lv_mbox_set_text(mbox,1635"#FF8000 SD Partition Manager#\n\n"1636"#FFDD00 Warning: Do you really want to continue?!#\n\n"1637"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");1638lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1639manual_system_maintenance(true);16401641free(txt_buf);16421643if (!(btn_wait() & BTN_POWER))1644goto exit;16451646// Start partitioning.1647lv_mbox_set_text(mbox, "#FF8000 SD Partition Manager#");1648lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1649manual_system_maintenance(true);16501651lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1652lv_label_set_recolor(lbl_status, true);16531654lv_obj_t *lbl_paths[2];16551656// Create backup/restore paths labels.1657lbl_paths[0] = lv_label_create(mbox, NULL);1658lv_label_set_text(lbl_paths[0], "/");1659lv_label_set_long_mode(lbl_paths[0], LV_LABEL_LONG_DOT);1660lv_cont_set_fit(lbl_paths[0], false, true);1661lv_obj_set_width(lbl_paths[0], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1662lv_label_set_align(lbl_paths[0], LV_LABEL_ALIGN_CENTER);1663lbl_paths[1] = lv_label_create(mbox, NULL);1664lv_label_set_text(lbl_paths[1], " ");1665lv_label_set_long_mode(lbl_paths[1], LV_LABEL_LONG_DOT);1666lv_cont_set_fit(lbl_paths[1], false, true);1667lv_obj_set_width(lbl_paths[1], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1668lv_label_set_align(lbl_paths[1], LV_LABEL_ALIGN_CENTER);16691670sd_mount();16711672FATFS ram_fs;16731674// Read current MBR.1675sdmmc_storage_read(part_info.storage, 0, 1, &part_info.mbr_old);16761677lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing Ramdisk...");1678lv_label_set_text(lbl_paths[0], "Please wait...");1679lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1680manual_system_maintenance(true);16811682// Initialize RAM disk.1683if (ram_disk_init(&ram_fs, RAM_DISK_SZ))1684{1685lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to initialize Ramdisk!");1686goto error;1687}16881689lv_label_set_text(lbl_status, "#00DDFF Status:# Backing up files...");1690manual_system_maintenance(true);16911692// Do full or hekate/Nyx backup.1693if (_backup_and_restore_files(true, lbl_paths))1694{1695if (part_info.backup_possible)1696lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!");1697else1698lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!\nBootloader folder exceeds 1.2GB or corrupt!");16991700goto error;1701}17021703f_unmount("sd:"); // Unmount SD card.17041705lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting FAT32 partition...");1706lv_label_set_text(lbl_paths[0], "Please wait...");1707lv_label_set_text(lbl_paths[1], " ");1708manual_system_maintenance(true);17091710// Set reserved size.1711u32 part_rsvd_size = (part_info.emu_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);1712part_rsvd_size += part_rsvd_size ? part_info.alignment : 0; // Do not reserve alignment space if no extra partitions.1713disk_set_info(DRIVE_SD, SET_SECTOR_COUNT, &part_rsvd_size);1714u8 *buf = malloc(SZ_4M);17151716// Set cluster size to 64KB and try to format.1717u32 cluster_size = 65536;1718u32 mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);17191720if (!mkfs_error)1721goto mkfs_no_error;17221723// Retry formatting by halving cluster size, until one succeeds.1724while (cluster_size > 4096)1725{1726cluster_size /= 2;1727mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);17281729if (!mkfs_error)1730break;1731}17321733if (mkfs_error)1734{1735// Failed to format.1736s_printf((char *)buf, "#FFDD00 Error:# Failed to format disk (%d)!\n\n"1737"Remove the SD card and check that is OK.\nIf not, format it, reinsert it and\npress #FF8000 POWER#!", mkfs_error);17381739lv_label_set_text(lbl_status, (char *)buf);1740lv_label_set_text(lbl_paths[0], " ");1741manual_system_maintenance(true);17421743sd_end();17441745while (!(btn_wait() & BTN_POWER));17461747sd_mount();17481749lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");1750manual_system_maintenance(true);17511752// Restore backed up files back to SD.1753if (_backup_and_restore_files(false, lbl_paths))1754{1755// Failed to restore files. Try again once more.1756if (_backup_and_restore_files(false, lbl_paths))1757{1758lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");1759free(buf);1760goto error;1761}1762}17631764lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!");1765f_unmount("ram:");1766free(buf);1767goto error;1768}17691770mkfs_no_error:1771free(buf);17721773// Remount sd card as it was unmounted from formatting it.1774f_mount(&sd_fs, "sd:", 1); // Mount SD card.17751776lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");1777manual_system_maintenance(true);17781779// Restore backed up files back to SD.1780if (_backup_and_restore_files(false, lbl_paths))1781{1782// Failed to restore files. Try again once more.1783if (_backup_and_restore_files(false, lbl_paths))1784{1785lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");1786goto error;1787}1788}17891790// Unmount ramdisk.1791f_unmount("ram:");1792f_chdrive("sd:");17931794// Set Volume label.1795f_setlabel("0:SWITCH SD");17961797lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table...");1798lv_label_set_text(lbl_paths[0], "Please wait...");1799lv_label_set_text(lbl_paths[1], " ");1800manual_system_maintenance(true);18011802// Prepare MBR and GPT header and partition entries and flash them.1803_sd_prepare_and_flash_mbr_gpt();18041805// Enable/Disable buttons depending on partition layout.1806if (part_info.l4t_size)1807{1808lv_obj_set_click(btn_flash_l4t, true);1809lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);1810}1811else1812{1813lv_obj_set_click(btn_flash_l4t, false);1814lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);1815}18161817// Enable/Disable buttons depending on partition layout.1818if (part_info.and_size)1819{1820lv_obj_set_click(btn_flash_android, true);1821lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);1822}1823else1824{1825lv_obj_set_click(btn_flash_android, false);1826lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);1827}18281829sd_unmount();1830lv_label_set_text(lbl_status, "#00DDFF Status:# Done!");1831manual_system_maintenance(true);18321833// Set buttons depending on what user chose to create.1834if (part_info.l4t_size && part_info.and_size)1835lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);1836else if (part_info.l4t_size)1837lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);1838else if (part_info.and_size)1839lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);18401841if (part_info.l4t_size || part_info.and_size)1842buttons_set = true;18431844goto out;18451846error:1847f_chdrive("sd:");18481849out:1850lv_obj_del(lbl_paths[0]);1851lv_obj_del(lbl_paths[1]);1852exit:1853if (!buttons_set)1854lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);1855lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1856lv_obj_set_top(mbox, true);18571858// Disable partitioning button.1859if (part_info.partition_button)1860lv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);18611862return LV_RES_OK;1863}18641865static lv_res_t _emmc_create_mbox_start_partitioning()1866{1867lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);1868lv_obj_set_style(dark_bg, &mbox_darken);1869lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);18701871static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };1872static const char *mbox_btn_map1[] = { "\222Flash Linux", "\222Flash Android", "\221OK", "" };1873static const char *mbox_btn_map2[] = { "\222Flash Linux", "\221OK", "" };1874static const char *mbox_btn_map3[] = { "\222Flash Android", "\221OK", "" };1875lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);1876lv_mbox_set_recolor_text(mbox, true);1877lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);18781879lv_mbox_set_text(mbox, "#FF8000 eMMC Partition Manager#");1880lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1881lv_obj_set_top(mbox, true);18821883bool buttons_set = false;18841885// Use safety wait if backup is not possible.1886char *txt_buf = malloc(SZ_4K);1887strcpy(txt_buf, "#FF8000 eMMC Partition Manager#\n\nSafety wait ends in ");1888lv_mbox_set_text(mbox, txt_buf);18891890u32 seconds = 5;1891u32 text_idx = strlen(txt_buf);1892while (seconds)1893{1894s_printf(txt_buf + text_idx, "%d seconds...", seconds);1895lv_mbox_set_text(mbox, txt_buf);1896manual_system_maintenance(true);1897msleep(1000);1898seconds--;1899}19001901lv_mbox_set_text(mbox,1902"#FF8000 eMMC Partition Manager#\n\n"1903"#FFDD00 Warning: Do you really want to continue?!#\n\n"1904"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");1905lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1906manual_system_maintenance(true);19071908if (!(btn_wait() & BTN_POWER))1909goto exit;19101911// Start partitioning.1912lv_mbox_set_text(mbox, "#FF8000 eMMC Partition Manager#");1913lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1914manual_system_maintenance(true);19151916lv_obj_t *lbl_status = lv_label_create(mbox, NULL);1917lv_label_set_recolor(lbl_status, true);19181919lv_obj_t *lbl_extra = lv_label_create(mbox, NULL);1920lv_label_set_long_mode(lbl_extra, LV_LABEL_LONG_DOT);1921lv_cont_set_fit(lbl_extra, false, true);1922lv_obj_set_width(lbl_extra, (LV_HOR_RES / 9 * 6) - LV_DPI / 2);1923lv_label_set_align(lbl_extra, LV_LABEL_ALIGN_CENTER);19241925lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing...");1926lv_label_set_text(lbl_extra, "Please wait...");1927lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);1928manual_system_maintenance(true);19291930if (emmc_initialize(false))1931{1932lv_label_set_text(lbl_extra, "#FFDD00 Failed to init eMMC!#");1933goto exit;1934}19351936emmc_set_partition(EMMC_GPP);19371938if (!emummc_raw_derive_bis_keys())1939{1940lv_label_set_text(lbl_extra, "#FFDD00 For formatting USER partition,#\n#FFDD00 BIS keys are needed!#");1941emmc_end();1942goto exit;1943}19441945lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table...");1946lv_label_set_text(lbl_extra, "Please wait...");1947manual_system_maintenance(true);19481949// Prepare MBR and GPT header and partition entries and flash them.1950if (_emmc_prepare_and_flash_mbr_gpt())1951goto no_hos_user_part;19521953lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting USER partition...");1954lv_label_set_text(lbl_extra, "Please wait...");1955manual_system_maintenance(true);19561957// Get USER partition and configure BIS and FatFS.1958LIST_INIT(gpt);1959emmc_gpt_parse(&gpt);1960emmc_part_t *user_part = emmc_part_find(&gpt, "USER");19611962if (!user_part)1963{1964no_hos_user_part:1965s_printf(txt_buf, "#FF0000 HOS USER partition doesn't exist!#\nRestore HOS backup first...");1966lv_label_set_text(lbl_extra, txt_buf);19671968emmc_gpt_free(&gpt);1969emmc_end();19701971goto exit;1972}19731974// Initialize BIS for eMMC. BIS keys should be already in place.1975nx_emmc_bis_init(user_part, true, 0);19761977// Set BIS size for FatFS.1978u32 user_sectors = user_part->lba_end - user_part->lba_start + 1;1979disk_set_info(DRIVE_BIS, SET_SECTOR_COUNT, &user_sectors);19801981// Enable writing.1982bool allow_writes = true;1983disk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);19841985// Format USER partition as FAT32 with 16KB cluster and PRF2SAFE.1986u8 *buff = malloc(SZ_4M);1987int mkfs_error = f_mkfs("bis:", FM_FAT32 | FM_SFD | FM_PRF2, 16384, buff, SZ_4M);19881989if (mkfs_error)1990{1991s_printf(txt_buf, "#FF0000 Failed (%d)!#\nPlease try again...\n", mkfs_error);1992lv_label_set_text(lbl_extra, txt_buf);19931994free(buff);1995emmc_end();19961997goto exit;1998}19992000// Disable writes to BIS.2001allow_writes = false;2002disk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);20032004// Flush BIS cache, deinit, clear BIS keys slots and reinstate SBK.2005nx_emmc_bis_end();2006hos_bis_keys_clear();2007emmc_gpt_free(&gpt);2008emmc_end();20092010// Enable/Disable buttons depending on partition layout.2011if (part_info.l4t_size)2012{2013lv_obj_set_click(btn_flash_l4t, true);2014lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);2015}2016else2017{2018lv_obj_set_click(btn_flash_l4t, false);2019lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);2020}20212022// Enable/Disable buttons depending on partition layout.2023if (part_info.and_size)2024{2025lv_obj_set_click(btn_flash_android, true);2026lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);2027}2028else2029{2030lv_obj_set_click(btn_flash_android, false);2031lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);2032}20332034lv_label_set_text(lbl_status, "#00DDFF Status:# Done!");2035manual_system_maintenance(true);20362037// Set buttons depending on what user chose to create.2038if (part_info.l4t_size && part_info.and_size)2039lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);2040else if (part_info.l4t_size)2041lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);2042else if (part_info.and_size)2043lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);20442045if (part_info.l4t_size || part_info.and_size)2046buttons_set = true;20472048lv_obj_del(lbl_extra);20492050exit:2051free(txt_buf);20522053if (!buttons_set)2054lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);2055lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2056lv_obj_set_top(mbox, true);20572058// Disable partitioning button.2059if (part_info.partition_button)2060lv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);20612062return LV_RES_OK;2063}20642065static lv_res_t _create_mbox_partitioning_option0(lv_obj_t *btns, const char *txt)2066{2067int btn_idx = lv_btnm_get_pressed(btns);20682069switch (btn_idx)2070{2071case 0:2072action_ums_sd(NULL);2073return LV_RES_OK;2074case 1:2075nyx_mbox_action(btns, txt);2076_sd_create_mbox_start_partitioning();2077break;2078case 2:2079nyx_mbox_action(btns, txt);2080break;2081}20822083return LV_RES_INV;2084}20852086static lv_res_t _create_mbox_partitioning_option1(lv_obj_t *btns, const char *txt)2087{2088int btn_idx = lv_btnm_get_pressed(btns);20892090nyx_mbox_action(btns, txt);20912092if (!btn_idx)2093{2094if (!part_info.emmc)2095_sd_create_mbox_start_partitioning();2096else2097_emmc_create_mbox_start_partitioning();2098return LV_RES_INV;2099}21002101return LV_RES_OK;2102}21032104static lv_res_t _create_mbox_partitioning_warn()2105{2106lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2107lv_obj_set_style(dark_bg, &mbox_darken);2108lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);21092110static const char *mbox_btn_map[] = { "\222SD UMS", "\222Start", "\222Cancel", "" };2111static const char *mbox_btn_map1[] = { "\222Start", "\222Cancel", "" };2112lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);2113lv_mbox_set_recolor_text(mbox, true);21142115char *txt_buf = malloc(SZ_4K);2116lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);2117lv_mbox_set_text(mbox, "#FF8000 Partition Manager#");21182119lv_obj_t *lbl_status = lv_label_create(mbox, NULL);2120lv_label_set_recolor(lbl_status, true);21212122if (!part_info.emmc)2123{2124s_printf(txt_buf, "#FFDD00 Warning: This will partition the SD Card!#\n\n");21252126if (part_info.backup_possible)2127{2128strcat(txt_buf, "#C7EA46 Your files will be backed up and restored!#\n"2129"#FFDD00 Any other partition will be wiped!#");2130}2131else2132{2133strcat(txt_buf, "#FFDD00 Your files will be wiped!#\n"2134"#FFDD00 Any other partition will be also wiped!#\n"2135"#FFDD00 Use USB UMS to copy them over!#");2136}21372138lv_label_set_text(lbl_status, txt_buf);21392140if (part_info.backup_possible)2141lv_mbox_add_btns(mbox, mbox_btn_map1, _create_mbox_partitioning_option1);2142else2143lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_option0);2144}2145else2146{2147s_printf(txt_buf, "#FFDD00 Warning: This will partition the eMMC!#\n\n"2148"#FFDD00 The USER partition will also be formatted!#");2149lv_label_set_text(lbl_status, txt_buf);2150lv_mbox_add_btns(mbox, mbox_btn_map1, _create_mbox_partitioning_option1);2151}21522153lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2154lv_obj_set_top(mbox, true);21552156free(txt_buf);21572158return LV_RES_OK;2159}21602161static lv_res_t _create_mbox_partitioning_android(lv_obj_t *btns, const char *txt)2162{2163part_info.and_dynamic = lv_btnm_get_pressed(btns);21642165nyx_mbox_action(btns, txt);21662167_create_mbox_partitioning_warn();21682169return LV_RES_INV;2170}21712172static lv_res_t _create_mbox_partitioning_andr_part()2173{2174lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2175lv_obj_set_style(dark_bg, &mbox_darken);2176lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);21772178static const char *mbox_btn_map[] = { "\222Legacy", "\222Dynamic", "" };2179lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);2180lv_mbox_set_recolor_text(mbox, true);21812182lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);2183lv_mbox_set_text(mbox, "#FF8000 Android Partitioning#");21842185lv_obj_t *lbl_status = lv_label_create(mbox, NULL);2186lv_label_set_recolor(lbl_status, true);21872188lv_label_set_text(lbl_status,2189"Please select a partition scheme:\n\n"2190"#C7EA46 Dynamic:# Android 13+ (Preferred)\n"2191"#C7EA46 Legacy:# Android 11\n");21922193lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_android);2194lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2195lv_obj_set_top(mbox, true);21962197return LV_RES_OK;2198}21992200static lv_res_t _create_mbox_partitioning_next(lv_obj_t *btn) {2201if (part_info.and_size)2202return _create_mbox_partitioning_andr_part();2203else2204return _create_mbox_partitioning_warn();2205}22062207static void _update_partition_bar()2208{2209lv_obj_t *h1 = lv_obj_get_parent(part_info.bar_hos);22102211// Set widths based on max bar width.2212u32 total_size = (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB;2213u32 bar_hos_size = lv_obj_get_width(h1) * (part_info.hos_size >> 10) / total_size;2214u32 bar_emu_size = lv_obj_get_width(h1) * (part_info.emu_size >> 10) / total_size;2215u32 bar_l4t_size = lv_obj_get_width(h1) * (part_info.l4t_size >> 10) / total_size;2216u32 bar_and_size = lv_obj_get_width(h1) * (part_info.and_size >> 10) / total_size;22172218// Update bar widths.2219lv_obj_set_width(part_info.bar_hos, bar_hos_size);2220lv_obj_set_width(part_info.bar_emu, bar_emu_size);2221lv_obj_set_width(part_info.bar_l4t, bar_l4t_size);2222lv_obj_set_width(part_info.bar_and, bar_and_size);22232224// Re-align bars.2225lv_obj_realign(part_info.bar_emu);2226lv_obj_realign(part_info.bar_l4t);2227lv_obj_realign(part_info.bar_and);22282229// Set emuMMC blending separator sizes and realign.2230lv_obj_set_width(part_info.sep_emu, bar_emu_size ? 8 : 0);2231lv_obj_realign(part_info.sep_emu);22322233// Set L4T blending separator sizes and realign.2234lv_obj_set_width(part_info.sep_l4t, bar_l4t_size ? 8 : 0);2235lv_obj_realign(part_info.sep_l4t);22362237// Set Android blending separator sizes and realign.2238lv_obj_set_width(part_info.sep_and, bar_and_size ? 8 : 0);2239lv_obj_realign(part_info.sep_and);22402241// Re-align size labels.2242lv_obj_realign(part_info.lbl_hos);2243lv_obj_realign(part_info.lbl_emu);2244lv_obj_realign(part_info.lbl_l4t);2245lv_obj_realign(part_info.lbl_and);2246lv_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);2247}22482249static lv_res_t _action_slider_emu(lv_obj_t *slider)2250{2251u32 size;2252char lbl_text[64];2253bool prev_emu_double = part_info.emu_double;2254int slide_val = lv_slider_get_value(slider);2255u32 max_emmc_size = !part_info.emmc_is_64gb ? EMU_32GB_FULL : EMU_64GB_FULL;22562257part_info.emu_double = false;22582259// Check that eMMC exists.2260if (!part_info.emmc_size_mb)2261{2262lv_slider_set_value(slider, 0);2263return LV_RES_OK;2264}22652266// In case of upgraded eMMC, do not allow FULL sizes. Max size is always bigger than official eMMCs.2267if (max_emmc_size < part_info.emmc_size_mb)2268{2269if (slide_val == EMU_SLIDER_1X_FULL)2270{2271if (prev_emu_double)2272slide_val--;2273else2274slide_val++;2275lv_slider_set_value(slider, slide_val);2276}2277else if (slide_val == EMU_SLIDER_2X_FULL)2278{2279slide_val--;2280lv_slider_set_value(slider, slide_val);2281}2282}22832284size = (slide_val > EMU_SLIDER_1X_MAX ? (slide_val - EMU_SLIDER_1X_MAX) : slide_val) + EMU_SLIDER_OFFSET;2285size *= 1024; // Convert to GB.2286size += EMU_RSVD_MB; // Add reserved size.22872288if (slide_val == EMU_SLIDER_MIN)2289size = 0; // Reset if 0.2290else if (slide_val >= EMU_SLIDER_2X_MIN)2291{2292size *= 2;2293part_info.emu_double = true;2294}22952296// Handle special cases. 2nd value is for 64GB Aula. Values already include reserved space.2297if (slide_val == EMU_SLIDER_1X_FULL)2298size = max_emmc_size;2299else if (slide_val == EMU_SLIDER_2X_FULL)2300size = 2 * max_emmc_size;23012302// Sanitize sizes based on new HOS size.2303s32 hos_size = (part_info.total_sct >> 11) - 16 - size - part_info.l4t_size - part_info.and_size;2304if (hos_size > part_info.hos_min_size)2305{2306part_info.emu_size = size;2307part_info.hos_size = hos_size;23082309s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);2310lv_label_set_text(part_info.lbl_hos, lbl_text);2311lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);23122313if (!part_info.emu_double)2314{2315if (slide_val != EMU_SLIDER_1X_FULL)2316s_printf(lbl_text, "#FF3C28 %4d GiB#", size >> 10);2317else2318s_printf(lbl_text, "#FF3C28 %d FULL#", size >> 10);2319}2320else2321s_printf(lbl_text, "#FFDD00 2x##FF3C28 %d GiB#", size >> 11);2322lv_label_set_text(part_info.lbl_emu, lbl_text);2323}2324else2325{2326u32 emu_size = part_info.emu_size;23272328if (emu_size == max_emmc_size)2329emu_size = EMU_SLIDER_1X_FULL;2330else if (emu_size == 2 * max_emmc_size)2331emu_size = EMU_SLIDER_2X_FULL;2332else if (emu_size)2333{2334if (prev_emu_double)2335emu_size /= 2;2336emu_size -= EMU_RSVD_MB;2337emu_size /= 1024;2338emu_size -= EMU_SLIDER_OFFSET;23392340if (prev_emu_double)2341emu_size += EMU_SLIDER_2X_MIN;2342}23432344int new_slider_val = emu_size;2345part_info.emu_double = prev_emu_double ? true : false;23462347lv_slider_set_value(slider, new_slider_val);2348}23492350_update_partition_bar();23512352return LV_RES_OK;2353}23542355static lv_res_t _action_slider_l4t(lv_obj_t *slider)2356{2357char lbl_text[64];23582359u32 size = (u32)lv_slider_get_value(slider) << 10;2360if (size < 4096)2361size = 0;2362else if (size < 8192)2363size = 8192;23642365s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - size - part_info.and_size;23662367// Sanitize sizes based on new HOS size.2368if (hos_size > part_info.hos_min_size)2369{2370if (size <= 8192)2371lv_slider_set_value(slider, size >> 10);2372}2373else2374{2375size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - 2048;2376hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - size;2377if (hos_size < part_info.hos_min_size || size < 8192)2378{2379lv_slider_set_value(slider, part_info.l4t_size >> 10);2380goto out;2381}2382lv_slider_set_value(slider, size >> 10);2383}23842385part_info.l4t_size = size;2386part_info.hos_size = hos_size;23872388s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);2389lv_label_set_text(part_info.lbl_hos, lbl_text);2390lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);2391s_printf(lbl_text, "#00DDFF %4d GiB#", size >> 10);2392lv_label_set_text(part_info.lbl_l4t, lbl_text);23932394_update_partition_bar();23952396out:2397return LV_RES_OK;2398}23992400static lv_res_t _action_slider_and(lv_obj_t *slider)2401{2402char lbl_text[64];24032404u32 user_size = (u32)lv_slider_get_value(slider) << 10;2405if (user_size < 2048)2406user_size = 0;2407else if (user_size < 4096)2408user_size = 4096;24092410u32 and_size = user_size ? (user_size + AND_SYS_SIZE_MB) : 0;2411s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;24122413// Sanitize sizes based on new HOS size.2414if (hos_size > part_info.hos_min_size)2415{2416if (user_size <= 4096)2417lv_slider_set_value(slider, user_size >> 10);2418}2419else2420{2421and_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - 2048;2422hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;2423if (hos_size < part_info.hos_min_size || and_size < 8192)2424{2425lv_slider_set_value(slider, part_info.and_size >> 10);2426goto out;2427}2428user_size = and_size - AND_SYS_SIZE_MB;2429lv_slider_set_value(slider, user_size >> 10);2430}24312432part_info.and_size = and_size;2433part_info.hos_size = hos_size;24342435s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);2436lv_label_set_text(part_info.lbl_hos, lbl_text);2437lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);2438s_printf(lbl_text, "#FF8000 %4d GiB#", user_size >> 10);2439lv_label_set_text(part_info.lbl_and, lbl_text);24402441_update_partition_bar();24422443out:2444return LV_RES_OK;2445}24462447static lv_res_t _mbox_check_files_total_size_option(lv_obj_t *btns, const char *txt)2448{2449// If "don't backup" button was pressed, disable backup/restore of files.2450if (!lv_btnm_get_pressed(btns))2451part_info.backup_possible = false;24522453nyx_mbox_action(btns, txt);24542455return LV_RES_INV;2456}24572458static void _create_mbox_check_files_total_size()2459{2460static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;2461static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;24622463// Set HOS bar style.2464lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);2465bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);2466bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;24672468// Set emuMMC bar style.2469lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);2470bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);2471bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;24722473// Set L4T bar style.2474lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);2475bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);2476bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;24772478// Set GPT bar style.2479lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);2480bar_and_ind.body.main_color = LV_COLOR_HEX(0xC000FF);2481bar_and_ind.body.grad_color = bar_and_ind.body.main_color;24822483// Set separator styles.2484lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);2485sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);2486sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;2487sep_emu_bg.body.radius = 0;2488lv_style_copy(&sep_l4t_bg, &sep_emu_bg);2489sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);2490sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;2491lv_style_copy(&sep_and_bg, &sep_emu_bg);2492sep_and_bg.body.main_color = LV_COLOR_HEX(0xC000FF);2493sep_and_bg.body.grad_color = sep_and_bg.body.main_color;24942495char *txt_buf = malloc(SZ_8K);24962497lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2498lv_obj_set_style(dark_bg, &mbox_darken);2499lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);25002501static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };2502static const char *mbox_btn_map2[] = { "\222Don't Backup", "\222OK", "" };2503lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);2504lv_mbox_set_recolor_text(mbox, true);2505lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);25062507lv_mbox_set_text(mbox, "Analyzing SD card usage. This might take a while...");25082509lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2510lv_obj_set_top(mbox, true);2511manual_system_maintenance(true);25122513char *path = malloc(0x1000);2514u32 total_files = 0;2515u32 total_size = 0;2516path[0] = 0;25172518// Check total size of files.2519int res = _stat_and_copy_files("sd:", NULL, path, &total_files, &total_size, NULL);25202521// Not more than 1.2GB.2522part_info.backup_possible = !res && !(total_size > (RAM_DISK_SZ - SZ_16M)); // Account for alignment.25232524if (part_info.backup_possible)2525{2526s_printf(txt_buf,2527"#96FF00 The SD Card files will be backed up automatically!#\n"2528"#FFDD00 Any other partition will be wiped!#\n"2529"#00DDFF Total files:# %d, #00DDFF Total size:# %d MiB", total_files, total_size >> 20);2530lv_mbox_set_text(mbox, txt_buf);2531}2532else2533{2534lv_mbox_set_text(mbox,2535"#FFDD00 The SD Card cannot be backed up automatically!#\n"2536"#FFDD00 Any other partition will be also wiped!#\n\n"2537"You will be asked to back up your files later via UMS.");2538}25392540// Create container to keep content inside.2541lv_obj_t *h1 = lv_cont_create(mbox, NULL);2542lv_cont_set_fit(h1, false, true);2543lv_cont_set_style(h1, &lv_style_transp_tight);2544lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI * 3);25452546lv_obj_t *lbl_part = lv_label_create(h1, NULL);2547lv_label_set_recolor(lbl_part, true);2548lv_label_set_text(lbl_part, "#00DDFF Current MBR partition layout:#");25492550// Read current MBR.2551mbr_t mbr = { 0 };2552sdmmc_storage_read(&sd_storage, 0, 1, &mbr);25532554// Calculate MBR partitions size.2555total_size = (sd_storage.sec_cnt - AU_ALIGN_SECTORS) / SECTORS_PER_GB;2556u32 bar_hos_size = lv_obj_get_width(h1) * (mbr.partitions[0].size_sct / SECTORS_PER_GB) / total_size;2557u32 bar_emu_size = 0;2558for (u32 i = 1; i < 4; i++)2559if (mbr.partitions[i].type == 0xE0)2560bar_emu_size += mbr.partitions[i].size_sct;2561bar_emu_size = lv_obj_get_width(h1) * (bar_emu_size / SECTORS_PER_GB) / total_size;25622563u32 bar_l4t_size = 0;2564for (u32 i = 1; i < 4; i++)2565if (mbr.partitions[i].type == 0x83)2566bar_l4t_size += mbr.partitions[i].size_sct;2567bar_l4t_size = lv_obj_get_width(h1) * (bar_l4t_size / SECTORS_PER_GB) / total_size;25682569u32 bar_and_size = lv_obj_get_width(h1) - bar_hos_size - bar_emu_size - bar_l4t_size;25702571// Create HOS bar.2572lv_obj_t *bar_mbr_hos = lv_bar_create(h1, NULL);2573lv_obj_set_size(bar_mbr_hos, bar_hos_size, LV_DPI / 3);2574lv_bar_set_range(bar_mbr_hos, 0, 1);2575lv_bar_set_value(bar_mbr_hos, 1);2576lv_bar_set_style(bar_mbr_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);2577lv_obj_align(bar_mbr_hos, lbl_part, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);25782579// Create emuMMC bar.2580lv_obj_t *bar_mbr_emu = lv_bar_create(h1, bar_mbr_hos);2581lv_obj_set_size(bar_mbr_emu, bar_emu_size, LV_DPI / 3);2582lv_bar_set_style(bar_mbr_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);2583lv_obj_align(bar_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);25842585// Create L4T bar.2586lv_obj_t *bar_mbr_l4t = lv_bar_create(h1, bar_mbr_hos);2587lv_obj_set_size(bar_mbr_l4t, bar_l4t_size, LV_DPI / 3);2588lv_bar_set_style(bar_mbr_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);2589lv_obj_align(bar_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);25902591// Create GPT bar.2592lv_obj_t *bar_mbr_gpt = lv_bar_create(h1, bar_mbr_hos);2593lv_obj_set_size(bar_mbr_gpt, bar_and_size > 1 ? bar_and_size : 0, LV_DPI / 3);2594lv_bar_set_style(bar_mbr_gpt, LV_BAR_STYLE_INDIC, &bar_and_ind);2595lv_obj_align(bar_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);25962597// Create emuMMC separator.2598lv_obj_t *sep_mbr_emu = lv_cont_create(h1, NULL);2599lv_obj_set_size(sep_mbr_emu, bar_emu_size ? 8 : 0, LV_DPI / 3);2600lv_obj_set_style(sep_mbr_emu, &sep_emu_bg);2601lv_obj_align(sep_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);26022603// Create L4T separator.2604lv_obj_t *sep_mbr_l4t = lv_cont_create(h1, sep_mbr_emu);2605lv_obj_set_size(sep_mbr_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 3);2606lv_obj_set_style(sep_mbr_l4t, &sep_l4t_bg);2607lv_obj_align(sep_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);26082609// Create GPT separator.2610lv_obj_t *sep_mbr_gpt = lv_cont_create(h1, sep_mbr_emu);2611lv_obj_set_size(sep_mbr_gpt, bar_and_size ? (bar_and_size > 1 ? 8 : 0) : 0, LV_DPI / 3);2612lv_obj_set_style(sep_mbr_gpt, &sep_and_bg);2613lv_obj_align(sep_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);26142615// Print partition table info.2616s_printf(txt_buf,2617"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2618"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2619"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2620"Partition 3 - Type: %02x, Start: %08x, Size: %08x",2621mbr.partitions[0].type, mbr.partitions[0].start_sct, mbr.partitions[0].size_sct,2622mbr.partitions[1].type, mbr.partitions[1].start_sct, mbr.partitions[1].size_sct,2623mbr.partitions[2].type, mbr.partitions[2].start_sct, mbr.partitions[2].size_sct,2624mbr.partitions[3].type, mbr.partitions[3].start_sct, mbr.partitions[3].size_sct);26252626lv_obj_t *lbl_table = lv_label_create(h1, NULL);2627lv_label_set_style(lbl_table, &monospace_text);2628lv_label_set_text(lbl_table, txt_buf);2629lv_obj_align(lbl_table, h1, LV_ALIGN_IN_TOP_MID, 0, LV_DPI);26302631if (!part_info.backup_possible)2632lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);2633else2634lv_mbox_add_btns(mbox, mbox_btn_map2, _mbox_check_files_total_size_option);26352636lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);26372638free(txt_buf);2639free(path);2640}26412642static lv_res_t _action_fix_mbr_gpt(lv_obj_t *btn)2643{2644lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);2645lv_obj_set_style(dark_bg, &mbox_darken);2646lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);26472648static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };2649lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);2650lv_mbox_set_recolor_text(mbox, true);26512652lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);2653lv_mbox_set_text(mbox, "#FF8000 Fix Hybrid MBR#");26542655lv_obj_t *lbl_status = lv_label_create(mbox, NULL);2656lv_label_set_recolor(lbl_status, true);26572658mbr_t mbr[2] = { 0 };2659gpt_t *gpt = zalloc(sizeof(gpt_t));2660gpt_header_t gpt_hdr_backup = { 0 };26612662bool has_mbr_attributes = false;2663bool hybrid_mbr_changed = false;2664bool gpt_partition_exists = false;2665int gpt_oob_empty_part_no = 0;2666int gpt_emummc_migrate_no = 0;26672668// Try to init sd card. No need for valid MBR.2669if (sd_mount() && !sd_get_card_initialized())2670{2671lv_label_set_text(lbl_status, "#FFDD00 Failed to init SD!#");2672goto out;2673}26742675sdmmc_storage_read(&sd_storage, 0, 1, &mbr[0]);2676sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);26772678memcpy(&mbr[1], &mbr[0], sizeof(mbr_t));26792680sd_unmount();26812682// Check for secret MBR attributes.2683if (gpt->entries[0].part_guid[7])2684has_mbr_attributes = true;26852686// Check if there's a GPT Protective partition.2687for (u32 i = 0; i < 4; i++)2688{2689if (mbr[0].partitions[i].type == 0xEE)2690gpt_partition_exists = true;2691}26922693// Check if GPT is valid.2694if (!gpt_partition_exists || memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)2695{2696lv_label_set_text(lbl_status, "#FFDD00 Warning:# No valid GPT was found!");26972698gpt_partition_exists = false;26992700if (has_mbr_attributes)2701goto check_changes;2702else2703goto out;2704}27052706sdmmc_storage_read(&sd_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);27072708// Parse GPT.2709LIST_INIT(gpt_parsed);2710for (u32 i = 0; i < gpt->header.num_part_ents; i++)2711{2712// Check if partition is out of bounds or empty.2713if ( gpt->entries[i].lba_start < gpt->header.first_use_lba ||2714gpt->entries[i].lba_start >= gpt->entries[i].lba_end ||2715!gpt->entries[i].lba_end)2716{2717gpt_oob_empty_part_no++;2718continue;2719}27202721emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t));27222723part->index = i;2724part->lba_start = gpt->entries[i].lba_start;2725part->lba_end = gpt->entries[i].lba_end;27262727// ASCII conversion. Copy only the LSByte of the UTF-16LE name.2728for (u32 j = 0; j < 36; j++)2729part->name[j] = gpt->entries[i].name[j];2730part->name[35] = 0;27312732list_append(&gpt_parsed, &part->link);2733}27342735// Set FAT and emuMMC partitions.2736u32 mbr_idx = 1;2737bool found_hos_data = false;2738u32 emummc_mbr_part_idx[2] = {0};2739LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link)2740{2741// FatFS simple GPT found a fat partition, set it.2742if (sd_fs.part_type && !part->index)2743{2744mbr[1].partitions[0].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC;2745mbr[1].partitions[0].start_sct = part->lba_start;2746mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1;2747}27482749// FatFS simple GPT didn't find a fat partition as the first one.2750if (!sd_fs.part_type && !found_hos_data && !strcmp(part->name, "hos_data"))2751{2752mbr[1].partitions[0].type = 0xC;2753mbr[1].partitions[0].start_sct = part->lba_start;2754mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1;2755found_hos_data = true;2756}27572758// Set up to max 2 emuMMC partitions.2759if (!strcmp(part->name, "emummc") || !strcmp(part->name, "emummc2"))2760{2761mbr[1].partitions[mbr_idx].type = 0xE0;2762mbr[1].partitions[mbr_idx].start_sct = part->lba_start;2763mbr[1].partitions[mbr_idx].size_sct = part->lba_end - part->lba_start + 1;2764if (!strcmp(part->name, "emummc"))2765emummc_mbr_part_idx[0] = mbr_idx;2766else2767emummc_mbr_part_idx[1] = mbr_idx;2768mbr_idx++;2769}27702771// Total reached last slot.2772if (mbr_idx >= 3)2773break;2774}27752776emmc_gpt_free(&gpt_parsed);27772778// Set GPT protective partition.2779mbr[1].partitions[mbr_idx].type = 0xEE;2780mbr[1].partitions[mbr_idx].start_sct = 1;2781mbr[1].partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;27822783// Check for differences.2784for (u32 i = 1; i < 4; i++)2785{2786if ((mbr[0].partitions[i].type != mbr[1].partitions[i].type) ||2787(mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) ||2788(mbr[0].partitions[i].size_sct != mbr[1].partitions[i].size_sct))2789{2790// Check if original MBR already has an emuMMC and use it as source of truth.2791if (mbr[0].partitions[i].type == 0xE0)2792{2793memcpy(&mbr[1].partitions[i], &mbr[0].partitions[i], sizeof(mbr_part_t));2794gpt_emummc_migrate_no++;2795continue;2796}2797else2798hybrid_mbr_changed = true;2799break;2800}2801}28022803check_changes:2804if (!hybrid_mbr_changed && !has_mbr_attributes && !gpt_emummc_migrate_no)2805{2806lv_label_set_text(lbl_status, "#96FF00 Warning:# The Hybrid MBR needs no change!#");2807goto out;2808}28092810char *txt_buf = malloc(SZ_16K);28112812if (hybrid_mbr_changed)2813{2814// Current MBR info.2815s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n");2816s_printf(txt_buf + strlen(txt_buf),2817"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2818"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2819"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2820"Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n",2821mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct,2822mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct,2823mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct,2824mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct);28252826// New MBR info.2827s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n");2828s_printf(txt_buf + strlen(txt_buf),2829"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"2830"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"2831"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"2832"Partition 3 - Type: %02x, Start: %08x, Size: %08x",2833mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct,2834mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct,2835mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct,2836mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct);2837}2838else if (has_mbr_attributes || gpt_emummc_migrate_no || gpt_oob_empty_part_no)2839{2840s_printf(txt_buf, "#00DDFF The following need to be corrected:#\n");2841if (has_mbr_attributes)2842s_printf(txt_buf + strlen(txt_buf), "- MBR attributes\n");2843if (gpt_emummc_migrate_no)2844s_printf(txt_buf + strlen(txt_buf), "- emuMMC GPT Partition address and size\n");2845if (gpt_oob_empty_part_no)2846s_printf(txt_buf + strlen(txt_buf), "- GPT OOB/Empty Partitions (removal)\n");2847}28482849lv_label_set_text(lbl_status, txt_buf);2850lv_label_set_style(lbl_status, &monospace_text);28512852free(txt_buf);28532854lbl_status = lv_label_create(mbox, NULL);2855lv_label_set_recolor(lbl_status, true);2856lv_label_set_align(lbl_status, LV_LABEL_ALIGN_CENTER);28572858lv_label_set_text(lbl_status,2859"#FF8000 Warning: Do you really want to continue?!#\n\n"2860"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");28612862lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2863lv_obj_set_top(mbox, true);28642865manual_system_maintenance(true);28662867if (btn_wait() & BTN_POWER)2868{2869bool has_gpt_changes = false;28702871sd_mount();28722873// Write MBR.2874if (hybrid_mbr_changed)2875sdmmc_storage_write(&sd_storage, 0, 1, &mbr[1]);28762877// Fix MBR secret attributes.2878if (has_mbr_attributes)2879{2880// Clear secret attributes.2881gpt->entries[0].part_guid[7] = 0;2882has_gpt_changes = gpt_partition_exists;28832884if (!has_gpt_changes)2885{2886// Only write the relevant sector if the only change is MBR attributes.2887sdmmc_storage_write(&sd_storage, 2, 1, &gpt->entries[0]);2888}2889}28902891if (gpt_emummc_migrate_no)2892{2893u32 emu_idx = 0;2894for (u32 i = 0; i < gpt->header.num_part_ents; i++)2895{2896if (!memcmp(gpt->entries[i].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12))2897{2898u32 idx = emummc_mbr_part_idx[emu_idx];2899gpt->entries[i].lba_start = mbr[0].partitions[idx].start_sct;2900gpt->entries[i].lba_end = mbr[0].partitions[idx].start_sct + mbr[0].partitions[idx].size_sct - 1;2901gpt_emummc_migrate_no--;2902emu_idx++;29032904has_gpt_changes = true;2905}29062907if (i > 126 || !gpt_emummc_migrate_no)2908break;2909}2910}29112912if (gpt_oob_empty_part_no)2913{2914u32 part_idx = 0;2915for (u32 i = 0; i < gpt->header.num_part_ents; i++)2916{2917if ( gpt->entries[i].lba_start < gpt->header.first_use_lba ||2918gpt->entries[i].lba_start >= gpt->entries[i].lba_end ||2919!gpt->entries[i].lba_end)2920{2921continue;2922}29232924if (part_idx != i)2925memcpy(&gpt->entries[part_idx], &gpt->entries[i], sizeof(gpt_entry_t));2926part_idx++;2927}2928gpt->header.num_part_ents -= gpt_oob_empty_part_no;2929has_gpt_changes = true;2930}29312932if (has_gpt_changes)2933{2934// Fix GPT CRC32s.2935u32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents;2936gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size);2937gpt->header.crc32 = 0; // Set to 0 for calculation.2938gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);29392940gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32;2941gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.2942gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);29432944// Write main GPT.2945u32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE);2946sdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt);29472948// Write backup GPT partition table.2949sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries);29502951// Write backup GPT header.2952sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);2953}29542955sd_unmount();29562957lv_label_set_text(lbl_status, "#96FF00 The new Hybrid MBR was written successfully!#");2958}2959else2960lv_label_set_text(lbl_status, "#FFDD00 Warning: The Hybrid MBR Fix was canceled!#");29612962out:2963free(gpt);29642965lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);29662967lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);2968lv_obj_set_top(mbox, true);29692970return LV_RES_OK;2971}29722973lv_res_t create_window_partition_manager(bool emmc)2974{2975lv_obj_t *win;29762977if (!emmc)2978{2979win = nyx_create_standard_window(SYMBOL_SD" SD Partition Manager", NULL);2980lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR/GPT", _action_fix_mbr_gpt);2981}2982else2983win = nyx_create_standard_window(SYMBOL_CHIP" eMMC Partition Manager", NULL);29842985static lv_style_t bar_hos_bg, bar_emu_bg, bar_l4t_bg, bar_and_bg;2986static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;2987static lv_style_t bar_emu_btn, bar_l4t_btn, bar_and_btn;2988static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;29892990// Set HOS bar styles.2991lv_style_copy(&bar_hos_bg, lv_theme_get_current()->bar.bg);2992bar_hos_bg.body.main_color = LV_COLOR_HEX(0x4A8000);2993bar_hos_bg.body.grad_color = bar_hos_bg.body.main_color;2994lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);2995bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);2996bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;29972998// Set eMUMMC bar styles.2999lv_style_copy(&bar_emu_bg, lv_theme_get_current()->bar.bg);3000bar_emu_bg.body.main_color = LV_COLOR_HEX(0x940F00);3001bar_emu_bg.body.grad_color = bar_emu_bg.body.main_color;3002lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);3003bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);3004bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;3005lv_style_copy(&bar_emu_btn, lv_theme_get_current()->slider.knob);3006bar_emu_btn.body.main_color = LV_COLOR_HEX(0xB31200);3007bar_emu_btn.body.grad_color = bar_emu_btn.body.main_color;3008lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);3009sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);3010sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;3011sep_emu_bg.body.radius = 0;30123013// Set L4T bar styles.3014lv_style_copy(&bar_l4t_bg, lv_theme_get_current()->bar.bg);3015bar_l4t_bg.body.main_color = LV_COLOR_HEX(0x006E80);3016bar_l4t_bg.body.grad_color = bar_l4t_bg.body.main_color;3017lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);3018bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);3019bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;3020lv_style_copy(&bar_l4t_btn, lv_theme_get_current()->slider.knob);3021bar_l4t_btn.body.main_color = LV_COLOR_HEX(0x00B1CC);3022bar_l4t_btn.body.grad_color = bar_l4t_btn.body.main_color;3023lv_style_copy(&sep_l4t_bg, &sep_emu_bg);3024sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);3025sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;30263027// Set Android bar styles.3028lv_style_copy(&bar_and_bg, lv_theme_get_current()->bar.bg);3029bar_and_bg.body.main_color = LV_COLOR_HEX(0x804000);3030bar_and_bg.body.grad_color = bar_and_bg.body.main_color;3031lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);3032bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000);3033bar_and_ind.body.grad_color = bar_and_ind.body.main_color;3034lv_style_copy(&bar_and_btn, lv_theme_get_current()->slider.knob);3035bar_and_btn.body.main_color = LV_COLOR_HEX(0xCC6600);3036bar_and_btn.body.grad_color = bar_and_btn.body.main_color;3037lv_style_copy(&sep_and_bg, &sep_emu_bg);3038sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000);3039sep_and_bg.body.grad_color = sep_and_bg.body.main_color;30403041lv_obj_t *sep = lv_label_create(win, NULL);3042lv_label_set_static_text(sep, "");3043lv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);30443045// Create container to keep content inside.3046lv_obj_t *h1 = lv_cont_create(win, NULL);3047lv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES - LV_DPI);30483049u32 emmc_size = 0;3050if (!emmc)3051{3052if (sd_mount())3053{3054lv_obj_t *lbl = lv_label_create(h1, NULL);3055lv_label_set_recolor(lbl, true);3056lv_label_set_text(lbl, "#FFDD00 Failed to init SD!#");3057return LV_RES_OK;3058}30593060if (!emmc_initialize(false))3061{3062emmc_set_partition(EMMC_GPP);3063emmc_size = emmc_storage.sec_cnt >> 11;3064emmc_end();3065}3066}3067else3068{3069if (emmc_initialize(false))3070{3071lv_obj_t *lbl = lv_label_create(h1, NULL);3072lv_label_set_recolor(lbl, true);3073lv_label_set_text(lbl, "#FFDD00 Failed to init eMMC!#");3074return LV_RES_OK;3075}3076emmc_set_partition(EMMC_GPP);3077}30783079memset(&part_info, 0, sizeof(partition_ctxt_t));3080if (!emmc)3081_create_mbox_check_files_total_size();30823083char *txt_buf = malloc(SZ_8K);30843085part_info.emmc = emmc;3086part_info.storage = !emmc ? &sd_storage : &emmc_storage;3087part_info.total_sct = part_info.storage->sec_cnt;3088if (emmc)3089part_info.total_sct -= HOS_USER_SECTOR; // Reserved HOS partitions.30903091// Align down total size to ensure alignment of all partitions after HOS one.3092part_info.alignment = part_info.total_sct - ALIGN_DOWN(part_info.total_sct, AU_ALIGN_SECTORS);3093part_info.total_sct -= part_info.alignment;30943095u32 extra_sct = AU_ALIGN_SECTORS + 0x400000; // Reserved 16MB alignment for FAT partition + 2GB.30963097// Set initial HOS partition size, so the correct cluster size can be selected.3098part_info.hos_size = (part_info.total_sct >> 11) - 16; // Important if there's no slider change.30993100// Check if eMMC should be 64GB (Aula).3101part_info.emmc_is_64gb = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA;31023103// Set actual eMMC size.3104part_info.emmc_size_mb = emmc_size;31053106// Set HOS FAT or USER minimum size.3107part_info.hos_min_size = !emmc? HOS_FAT_MIN_SIZE_MB : HOS_USER_MIN_SIZE_MB;31083109// Read current MBR.3110mbr_t mbr = { 0 };3111sdmmc_storage_read(part_info.storage, 0, 1, &mbr);31123113u32 bar_hos_size = lv_obj_get_width(h1);3114u32 bar_emu_size = 0;3115u32 bar_l4t_size = 0;3116u32 bar_and_size = 0;31173118lv_obj_t *lbl = lv_label_create(h1, NULL);3119lv_label_set_recolor(lbl, true);3120lv_label_set_text(lbl, "Choose #FFDD00 new# partition layout:");31213122// Create disk layout blocks.3123// HOS partition block.3124lv_obj_t *bar_hos = lv_bar_create(h1, NULL);3125lv_obj_set_size(bar_hos, bar_hos_size, LV_DPI / 2);3126lv_bar_set_range(bar_hos, 0, 1);3127lv_bar_set_value(bar_hos, 1);3128lv_bar_set_style(bar_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);3129lv_obj_align(bar_hos, lbl, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);3130part_info.bar_hos = bar_hos;31313132// emuMMC partition block.3133lv_obj_t *bar_emu = lv_bar_create(h1, bar_hos);3134lv_obj_set_size(bar_emu, bar_emu_size, LV_DPI / 2);3135lv_bar_set_style(bar_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);3136lv_obj_align(bar_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);3137part_info.bar_emu = bar_emu;31383139// L4T partition block.3140lv_obj_t *bar_l4t = lv_bar_create(h1, bar_hos);3141lv_obj_set_size(bar_l4t, bar_l4t_size, LV_DPI / 2);3142lv_bar_set_style(bar_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);3143lv_obj_align(bar_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);3144part_info.bar_l4t = bar_l4t;31453146// Android partition block.3147lv_obj_t *bar_and = lv_bar_create(h1, bar_hos);3148lv_obj_set_size(bar_and, bar_and_size, LV_DPI / 2);3149lv_bar_set_style(bar_and, LV_BAR_STYLE_INDIC, &bar_and_ind);3150lv_obj_align(bar_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);3151part_info.bar_and = bar_and;31523153// HOS partition block.3154lv_obj_t *sep_emu = lv_cont_create(h1, NULL);3155lv_cont_set_fit(sep_emu, false, false);3156lv_obj_set_size(sep_emu, 0, LV_DPI / 2); // 8.3157lv_obj_set_style(sep_emu, &sep_emu_bg);3158lv_obj_align(sep_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);3159part_info.sep_emu = sep_emu;31603161// Create disk layout blending separators.3162lv_obj_t *sep_l4t = lv_cont_create(h1, sep_emu);3163lv_obj_set_style(sep_l4t, &sep_l4t_bg);3164lv_obj_align(sep_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);3165part_info.sep_l4t = sep_l4t;31663167lv_obj_t *sep_and = lv_cont_create(h1, sep_emu);3168lv_obj_set_style(sep_and, &sep_and_bg);3169lv_obj_align(sep_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);3170part_info.sep_and = sep_and;31713172// Create slider type labels.3173lv_obj_t *cont_lbl_hos = lv_cont_create(h1, NULL);3174lv_cont_set_fit(cont_lbl_hos, false, true);3175lv_obj_set_width(cont_lbl_hos, LV_DPI * 17 / 7);3176lv_obj_t *lbl_hos = lv_label_create(cont_lbl_hos, NULL);3177lv_label_set_recolor(lbl_hos, true);3178lv_label_set_static_text(lbl_hos, !emmc ? "#96FF00 "SYMBOL_DOT" HOS (FAT32):#" :3179"#96FF00 "SYMBOL_DOT" eMMC (USER):#");3180lv_obj_align(lbl_hos, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);31813182lv_obj_t *lbl_emu = lbl_hos;3183if (!emmc)3184{3185lbl_emu = lv_label_create(h1, lbl_hos);3186lv_label_set_static_text(lbl_emu, "#FF3C28 "SYMBOL_DOT" emuMMC (RAW):#");3187lv_obj_align(lbl_emu, lbl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);3188}31893190lv_obj_t *lbl_l4t = lv_label_create(h1, lbl_hos);3191lv_label_set_static_text(lbl_l4t, "#00DDFF "SYMBOL_DOT" Linux (EXT4):#");3192lv_obj_align(lbl_l4t, lbl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);31933194lv_obj_t *lbl_and = lv_label_create(h1, lbl_hos);3195lv_label_set_static_text(lbl_and, "#FF8000 "SYMBOL_DOT" Android (USER):#");3196lv_obj_align(lbl_and, lbl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);31973198// Create HOS size slider. Non-interactive.3199lv_obj_t *slider_bar_hos = lv_bar_create(h1, NULL);3200lv_obj_set_size(slider_bar_hos, LV_DPI * 7, LV_DPI * 3 / 17);3201lv_bar_set_range(slider_bar_hos, 0, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);3202lv_bar_set_value(slider_bar_hos, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);3203lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_BG, &bar_hos_bg);3204lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_INDIC, &bar_hos_ind);3205lv_obj_align(slider_bar_hos, cont_lbl_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI, 0);3206part_info.slider_bar_hos = slider_bar_hos;32073208lv_obj_t *slider_emu = slider_bar_hos;3209if (!emmc)3210{3211// Create emuMMC size slider.3212slider_emu = lv_slider_create(h1, NULL);3213lv_obj_set_size(slider_emu, LV_DPI * 7, LV_DPI / 3);3214lv_slider_set_range(slider_emu, EMU_SLIDER_MIN, EMU_SLIDER_MAX);3215lv_slider_set_value(slider_emu, EMU_SLIDER_MIN);3216lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_BG, &bar_emu_bg);3217lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_INDIC, &bar_emu_ind);3218lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_KNOB, &bar_emu_btn);3219lv_obj_align(slider_emu, slider_bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 + 5);3220lv_slider_set_action(slider_emu, _action_slider_emu);3221}32223223// Create L4T size slider.3224lv_obj_t *slider_l4t = lv_slider_create(h1, NULL);3225lv_obj_set_size(slider_l4t, LV_DPI * 7, LV_DPI / 3);3226lv_slider_set_range(slider_l4t, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB);3227lv_slider_set_value(slider_l4t, 0);3228lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_BG, &bar_l4t_bg);3229lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_INDIC, &bar_l4t_ind);3230lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_KNOB, &bar_l4t_btn);3231lv_obj_align(slider_l4t, slider_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, !emmc ? (LV_DPI / 3 - 3) : (LV_DPI / 3 + 5));3232lv_slider_set_action(slider_l4t, _action_slider_l4t);32333234// Create Android size slider.3235lv_obj_t *slider_and = lv_slider_create(h1, NULL);3236lv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3);3237lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - (AND_SYS_SIZE_MB / 1024)); // Subtract android reserved size.3238lv_slider_set_value(slider_and, 0);3239lv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg);3240lv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind);3241lv_slider_set_style(slider_and, LV_SLIDER_STYLE_KNOB, &bar_and_btn);3242lv_obj_align(slider_and, slider_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3);3243lv_slider_set_action(slider_and, _action_slider_and);32443245// Create container for the labels.3246lv_obj_t *cont_lbl = lv_cont_create(h1, NULL);3247lv_cont_set_fit(cont_lbl, false, true);3248lv_obj_set_width(cont_lbl, LV_DPI * 3 / 2);3249part_info.cont_lbl = cont_lbl;32503251// Create HOS size label.3252lv_obj_t *lbl_sl_hos = lv_label_create(cont_lbl, NULL);3253lv_label_set_recolor(lbl_sl_hos, true);3254lv_label_set_align(lbl_sl_hos, LV_LABEL_ALIGN_RIGHT);3255s_printf(txt_buf, "#96FF00 %4d GiB#", (part_info.total_sct - AU_ALIGN_SECTORS) >> 11 >> 10);3256lv_label_set_text(lbl_sl_hos, txt_buf);3257lv_obj_align(lbl_sl_hos, cont_lbl, LV_ALIGN_IN_TOP_RIGHT, 0, 0);3258part_info.lbl_hos = lbl_sl_hos;32593260// Create emuMMC size label.3261part_info.lbl_emu = lbl_sl_hos;3262if (!emmc)3263{3264lv_obj_t *lbl_sl_emu = lv_label_create(cont_lbl, lbl_sl_hos);3265lv_label_set_text(lbl_sl_emu, "#FF3C28 0 GiB#");3266lv_obj_align(lbl_sl_emu, lbl_sl_hos, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);3267part_info.lbl_emu = lbl_sl_emu;3268}32693270// Create L4T size label.3271lv_obj_t *lbl_sl_l4t = lv_label_create(cont_lbl, lbl_sl_hos);3272lv_label_set_text(lbl_sl_l4t, "#00DDFF 0 GiB#");3273lv_obj_align(lbl_sl_l4t, part_info.lbl_emu, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);3274part_info.lbl_l4t = lbl_sl_l4t;32753276// Create Android size label.3277lv_obj_t *lbl_sl_and = lv_label_create(cont_lbl, lbl_sl_hos);3278lv_label_set_text(lbl_sl_and, "#FF8000 0 GiB#");3279lv_obj_align(lbl_sl_and, lbl_sl_l4t, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);3280part_info.lbl_and = lbl_sl_and;32813282lv_obj_align(cont_lbl, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 11 - LV_DPI / 2, LV_DPI * 9 / 23);32833284// Set partition manager notes.3285lv_obj_t *lbl_notes = lv_label_create(h1, NULL);3286lv_label_set_recolor(lbl_notes, true);3287lv_label_set_style(lbl_notes, &hint_small_style);3288if (!emmc)3289{3290lv_label_set_static_text(lbl_notes,3291"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"3292"Note 2: Resized emuMMC formats the USER partition. A save data manager can be used to move them over.\n"3293"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n");3294lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 2);3295}3296else3297{3298lv_label_set_static_text(lbl_notes,3299"Note 1: Any partition existing after the selected ones gets removed from the table.\n"3300"Note 2: The HOS USER partition gets formatted. A save data manager can be used to move them over.\n"3301"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n");3302lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 4);3303}33043305lv_obj_t *btn1 = NULL;3306lv_obj_t *label_btn = NULL;3307if (!emmc)3308{3309// Create UMS button.3310btn1 = lv_btn_create(h1, NULL);3311lv_obj_t *label_btn = lv_label_create(btn1, NULL);3312lv_btn_set_fit(btn1, true, true);3313lv_label_set_static_text(label_btn, SYMBOL_USB" SD UMS");3314lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);3315lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_part_manager_ums_sd);3316}33173318// Create Flash Linux button.3319btn_flash_l4t = lv_btn_create(h1, NULL);3320label_btn = lv_label_create(btn_flash_l4t, NULL);3321lv_btn_set_fit(btn_flash_l4t, true, true);3322lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Linux");3323if (!emmc)3324lv_obj_align(btn_flash_l4t, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);3325else3326lv_obj_align(btn_flash_l4t, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);3327lv_btn_set_action(btn_flash_l4t, LV_BTN_ACTION_CLICK, _action_check_flash_linux);33283329// Disable Flash Linux button if partition not found.3330u32 size_sct = _get_available_l4t_partition();3331if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)3332{3333lv_obj_set_click(btn_flash_l4t, false);3334lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);3335}33363337int part_type_and = _get_available_android_partition();33383339// Create Flash Android button.3340btn_flash_android = lv_btn_create(h1, NULL);3341label_btn = lv_label_create(btn_flash_android, NULL);3342lv_btn_set_fit(btn_flash_android, true, true);3343switch (part_type_and)3344{3345case 0: // Disable Flash Android button if partition not found.3346lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android");3347lv_obj_set_click(btn_flash_android, false);3348lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);3349break;3350case 1: // Android 11.3351lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 11");3352break;3353case 2: // Android 13+3354lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 13+");3355break;3356}3357lv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);3358lv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android);33593360// Create next step button.3361btn1 = lv_btn_create(h1, NULL);3362label_btn = lv_label_create(btn1, NULL);3363lv_btn_set_fit(btn1, true, true);3364lv_label_set_static_text(label_btn, SYMBOL_SD" Next Step");3365lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_RIGHT, 0, LV_DPI * 5);3366lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _create_mbox_partitioning_next);3367part_info.partition_button = btn1;33683369free(txt_buf);33703371if (!emmc)3372sd_unmount();3373else3374emmc_end();33753376return LV_RES_OK;3377}33783379lv_res_t create_window_sd_partition_manager(lv_obj_t *btn) { return create_window_partition_manager(false); }3380lv_res_t create_window_emmc_partition_manager(lv_obj_t *btn) { return create_window_partition_manager(true); }338133823383