From 453ec180487036a7a10fe9debd1d378a4aec1076 Mon Sep 17 00:00:00 2001 From: CTCaer Date: Mon, 10 Nov 2025 15:28:41 +0200 Subject: [PATCH] nyx: part: extend Fix Hybrid MBR/GPT functionality - Allow invalid/out-of-bounds and empty partitions to be removed from GPT - Add fix for wrong emuMMC offset because of older bugged Android Dynamic scheme --- .../frontend/gui_tools_partition_manager.c | 193 ++++++++++++------ 1 file changed, 136 insertions(+), 57 deletions(-) diff --git a/nyx/nyx_gui/frontend/gui_tools_partition_manager.c b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c index b376bf0d..f0e001f9 100644 --- a/nyx/nyx_gui/frontend/gui_tools_partition_manager.c +++ b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c @@ -2616,7 +2616,7 @@ static void _create_mbox_check_files_total_size() free(path); } -static lv_res_t _action_fix_mbr(lv_obj_t *btn) +static lv_res_t _action_fix_mbr_gpt(lv_obj_t *btn) { lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); lv_obj_set_style(dark_bg, &mbox_darken); @@ -2636,9 +2636,11 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn) gpt_t *gpt = zalloc(sizeof(gpt_t)); gpt_header_t gpt_hdr_backup = { 0 }; - bool has_mbr_attributes = false; - bool hybrid_mbr_changed = false; + bool has_mbr_attributes = false; + bool hybrid_mbr_changed = false; bool gpt_partition_exists = false; + int gpt_oob_empty_part_no = 0; + int gpt_emummc_migrate_no = 0; // Try to init sd card. No need for valid MBR. if (!sd_mount() && !sd_get_card_initialized()) @@ -2684,10 +2686,16 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn) LIST_INIT(gpt_parsed); for (u32 i = 0; i < gpt->header.num_part_ents; i++) { - emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t)); - - if (gpt->entries[i].lba_start < gpt->header.first_use_lba) + // Check if partition is out of bounds or empty. + if ( gpt->entries[i].lba_start < gpt->header.first_use_lba || + gpt->entries[i].lba_start >= gpt->entries[i].lba_end || + !gpt->entries[i].lba_end) + { + gpt_oob_empty_part_no++; continue; + } + + emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t)); part->index = i; part->lba_start = gpt->entries[i].lba_start; @@ -2704,6 +2712,7 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn) // Set FAT and emuMMC partitions. u32 mbr_idx = 1; bool found_hos_data = false; + u32 emummc_mbr_part_idx[2] = {0}; LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link) { // FatFS simple GPT found a fat partition, set it. @@ -2711,7 +2720,7 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn) { mbr[1].partitions[0].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC; mbr[1].partitions[0].start_sct = part->lba_start; - mbr[1].partitions[0].size_sct = (part->lba_end - part->lba_start + 1); + mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1; } // FatFS simple GPT didn't find a fat partition as the first one. @@ -2719,7 +2728,7 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn) { mbr[1].partitions[0].type = 0xC; mbr[1].partitions[0].start_sct = part->lba_start; - mbr[1].partitions[0].size_sct = (part->lba_end - part->lba_start + 1); + mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1; found_hos_data = true; } @@ -2728,7 +2737,11 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn) { mbr[1].partitions[mbr_idx].type = 0xE0; mbr[1].partitions[mbr_idx].start_sct = part->lba_start; - mbr[1].partitions[mbr_idx].size_sct = (part->lba_end - part->lba_start + 1); + mbr[1].partitions[mbr_idx].size_sct = part->lba_end - part->lba_start + 1; + if (!strcmp(part->name, "emummc")) + emummc_mbr_part_idx[0] = mbr_idx; + else + emummc_mbr_part_idx[1] = mbr_idx; mbr_idx++; } @@ -2751,13 +2764,21 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn) (mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) || (mbr[0].partitions[i].size_sct != mbr[1].partitions[i].size_sct)) { - hybrid_mbr_changed = true; + // Check if original MBR already has an emuMMC and use it as source of truth. + if (mbr[0].partitions[i].type == 0xE0) + { + memcpy(&mbr[1].partitions[i], &mbr[0].partitions[i], sizeof(mbr_part_t)); + gpt_emummc_migrate_no++; + continue; + } + else + hybrid_mbr_changed = true; break; } } check_changes: - if (!hybrid_mbr_changed && !has_mbr_attributes) + if (!hybrid_mbr_changed && !has_mbr_attributes && !gpt_emummc_migrate_no) { lv_label_set_text(lbl_status, "#96FF00 Warning:# The Hybrid MBR needs no change!#"); goto out; @@ -2765,29 +2786,42 @@ check_changes: char *txt_buf = malloc(SZ_16K); - // Current MBR info. - s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n"); - s_printf(txt_buf + strlen(txt_buf), - "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" - "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" - "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" - "Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n", - mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct, - mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct, - mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct, - mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct); + if (hybrid_mbr_changed) + { + // Current MBR info. + s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n"); + s_printf(txt_buf + strlen(txt_buf), + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n", + mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct, + mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct, + mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct, + mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct); - // New MBR info. - s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n"); - s_printf(txt_buf + strlen(txt_buf), - "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" - "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" - "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" - "Partition 3 - Type: %02x, Start: %08x, Size: %08x", - mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct, - mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct, - mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct, - mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct); + // New MBR info. + s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n"); + s_printf(txt_buf + strlen(txt_buf), + "Partition 0 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 1 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 2 - Type: %02x, Start: %08x, Size: %08x\n" + "Partition 3 - Type: %02x, Start: %08x, Size: %08x", + mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct, + mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct, + mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct, + mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct); + } + else if (has_mbr_attributes || gpt_emummc_migrate_no || gpt_oob_empty_part_no) + { + s_printf(txt_buf, "#00DDFF The following need to be corrected:#\n"); + if (has_mbr_attributes) + s_printf(txt_buf + strlen(txt_buf), "- MBR attributes\n"); + if (gpt_emummc_migrate_no) + s_printf(txt_buf + strlen(txt_buf), "- emuMMC GPT Partition address and size\n"); + if (gpt_oob_empty_part_no) + s_printf(txt_buf + strlen(txt_buf), "- GPT OOB/Empty Partitions (removal)\n"); + } lv_label_set_text(lbl_status, txt_buf); lv_label_set_style(lbl_status, &monospace_text); @@ -2809,6 +2843,8 @@ check_changes: if (btn_wait() & BTN_POWER) { + bool has_gpt_changes = false; + sd_mount(); // Write MBR. @@ -2820,36 +2856,79 @@ check_changes: { // Clear secret attributes. gpt->entries[0].part_guid[7] = 0; + has_gpt_changes = gpt_partition_exists; - if (gpt_partition_exists) - { - // Fix CRC32s. - u32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents; - gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size); - gpt->header.crc32 = 0; // Set to 0 for calculation. - gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size); - - gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32; - gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation. - gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size); - - // Write main GPT. - u32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE); - sdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt); - - // Write backup GPT partition table. - sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries); - - // Write backup GPT header. - sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup); - } - else + if (!has_gpt_changes) { // Only write the relevant sector if the only change is MBR attributes. sdmmc_storage_write(&sd_storage, 2, 1, &gpt->entries[0]); } } + if (gpt_emummc_migrate_no) + { + u32 emu_idx = 0; + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if (!memcmp(gpt->entries[i].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12)) + { + u32 idx = emummc_mbr_part_idx[emu_idx]; + gpt->entries[i].lba_start = mbr[0].partitions[idx].start_sct; + gpt->entries[i].lba_end = mbr[0].partitions[idx].start_sct + mbr[0].partitions[idx].size_sct - 1; + gpt_emummc_migrate_no--; + emu_idx++; + + has_gpt_changes = true; + } + + if (i > 126 || !gpt_emummc_migrate_no) + break; + } + } + + if (gpt_oob_empty_part_no) + { + u32 part_idx = 0; + for (u32 i = 0; i < gpt->header.num_part_ents; i++) + { + if ( gpt->entries[i].lba_start < gpt->header.first_use_lba || + gpt->entries[i].lba_start >= gpt->entries[i].lba_end || + !gpt->entries[i].lba_end) + { + continue; + } + + if (part_idx != i) + memcpy(&gpt->entries[part_idx], &gpt->entries[i], sizeof(gpt_entry_t)); + part_idx++; + } + gpt->header.num_part_ents -= gpt_oob_empty_part_no; + has_gpt_changes = true; + } + + if (has_gpt_changes) + { + // Fix GPT CRC32s. + u32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents; + gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size); + gpt->header.crc32 = 0; // Set to 0 for calculation. + gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size); + + gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32; + gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation. + gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size); + + // Write main GPT. + u32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE); + sdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt); + + // Write backup GPT partition table. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries); + + // Write backup GPT header. + sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup); + } + sd_unmount(); lv_label_set_text(lbl_status, "#96FF00 The new Hybrid MBR was written successfully!#"); @@ -2875,7 +2954,7 @@ lv_res_t create_window_partition_manager(bool emmc) if (!emmc) { win = nyx_create_standard_window(SYMBOL_SD" SD Partition Manager"); - lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR", _action_fix_mbr); + lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR/GPT", _action_fix_mbr_gpt); } else win = nyx_create_standard_window(SYMBOL_CHIP" eMMC Partition Manager");