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
This commit is contained in:
CTCaer
2025-11-10 15:28:41 +02:00
parent b461bfc846
commit 453ec18048

View File

@@ -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");