static UINTN analyze(VOID) { UINTN i, detected_parttype; CHARN *fsname; UINTN status; new_mbr_part_count = 0; // determine correct MBR types for GPT partitions if (gpt_part_count == 0) { Print(L"Status: No GPT partitions defined, nothing to sync.\n"); return 0; } for (i = 0; i < gpt_part_count; i++) { gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type; if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) { // Basic Data: need to look at data in the partition status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname); if (status != 0) Print(L"Warning: Error %d when detecting filesystem type!\n", status); if (detected_parttype) gpt_parts[i].mbr_type = detected_parttype; else gpt_parts[i].mbr_type = 0x0b; // fallback: FAT32 } // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems } // for // generate the new table generate_hybrid_mbr(); if (!should_rewrite()) return EFI_ABORTED; // display table Print(L"\nProposed new MBR partition table:\n"); Print(L" # A Start LBA End LBA Type\n"); for (i = 0; i < new_mbr_part_count; i++) { Print(L" %d %s %12lld %12lld %02x %s\n", new_mbr_parts[i].index + 1, new_mbr_parts[i].active ? STR("*") : STR(" "), new_mbr_parts[i].start_lba, new_mbr_parts[i].end_lba, new_mbr_parts[i].mbr_type, mbr_parttype_name(new_mbr_parts[i].mbr_type)); } return 0; } // UINTN analyze()
static UINTN analyze_part(UINT64 partlba) { UINTN status; UINTN i; CHARN *bootcodename; UINTN parttype; CHARN *fsname; if (partlba == 0) Print(L"\nMBR contents:\n"); else Print(L"\nPartition at LBA %lld:\n", partlba); // detect boot code status = detect_bootcode(partlba, &bootcodename); if (status) return status; Print(L" Boot Code: %s\n", bootcodename); if (partlba == 0) return 0; // short-circuit MBR analysis // detect file system status = detect_mbrtype_fs(partlba, &parttype, &fsname); if (status) return status; Print(L" File System: %s\n", fsname); // cross-reference with partition table for (i = 0; i < gpt_part_count; i++) { if (gpt_parts[i].start_lba == partlba) { Print(L" Listed in GPT as partition %d, type %s\n", i+1, gpt_parts[i].gpt_parttype->name); } } for (i = 0; i < mbr_part_count; i++) { if (mbr_parts[i].start_lba == partlba) { Print(L" Listed in MBR as partition %d, type %02x %s%s\n", i+1, mbr_parts[i].mbr_type, mbr_parttype_name(mbr_parts[i].mbr_type), mbr_parts[i].active ? STR(", active") : STR("")); } } return 0; }
static UINTN analyze(int optind, int argc, char **argv) { UINTN action; UINTN i, k, count_active, detected_parttype; CHARN *fsname; UINT64 min_start_lba, max_end_lba, block_count, last_disk_lba; UINTN status; BOOLEAN have_esp; new_mbr_part_count = 0; block_count = get_disk_size(); last_disk_lba = block_count - 1; if (block_count == 0) { error("can't retrieve disk size"); return 1; } // determine correct MBR types for GPT partitions if (gpt_part_count == 0) { Print(L"Status: No GPT partitions defined, nothing to sync.\n"); return 1; } have_esp = FALSE; for (i = 0; i < gpt_part_count; i++) { gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type; if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) { // Basic Data: need to look at data in the partition status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname); if (detected_parttype) gpt_parts[i].mbr_type = detected_parttype; else gpt_parts[i].mbr_type = 0x0b; // fallback: FAT32 } else if (gpt_parts[i].mbr_type == 0xef) { // EFI System Partition: GNU parted can put this on any partition, // need to detect file systems status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname); if (!have_esp && (detected_parttype == 0x01 || detected_parttype == 0x0e || detected_parttype == 0x0c)) ; // seems to be a legitimate ESP, don't change else if (detected_parttype) gpt_parts[i].mbr_type = detected_parttype; else if (have_esp) // make sure there's no more than one ESP per disk gpt_parts[i].mbr_type = 0x83; // fallback: Linux } // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems if (gpt_parts[i].mbr_type == 0xef) have_esp = TRUE; } // generate the new table new_mbr_part_count = 1; count_active = 0; if (! create_empty_mbr) { if (optind < argc) { for (i = optind; i < argc; i++) { char *separator, csep = 0; BOOLEAN active = FALSE; UINT8 force_type = 0; separator = strchr (argv[i], '+'); if (! separator) separator = strchr (argv[i], '-'); if (separator) { csep = *separator; *separator = 0; } int part = atoi(argv[i]); if (part < 1 || part > gpt_part_count) { error("invalid argument '%s', partition number must be between 1-%d !", argv[i], gpt_part_count); return 1; } part--; // 0 base partition number if (csep == '+') { active = TRUE; count_active ++; if (count_active == 2) { error("only one partition can be active !"); return 1; } } if (separator && *(separator + 1)) { char *str_type = separator + 1; if(xtoi (str_type, &force_type) != 0) { error("invalid hex type: %s !", str_type); return 1; } } // Check that a partition has not already enter for (k = 1; k < new_mbr_part_count; k++) { if (new_mbr_parts[k].start_lba == gpt_parts[part].start_lba || new_mbr_parts[k].end_lba == gpt_parts[part].end_lba ) { error("you already add partition %d !",part+1); return 1; } } add_gpt_partition_to_mbr(new_mbr_part_count, part, force_type, active); new_mbr_part_count++; } } else { // add other GPT partitions until the table is full // TODO: in the future, prioritize partitions by kind if (gpt_parts[0].mbr_type == 0xef) i = 1; else i = 0; for (; i < gpt_part_count && new_mbr_part_count < 4; i++) { add_gpt_partition_to_mbr(new_mbr_part_count, i, 0, FALSE); new_mbr_part_count++; } } } // get the first and last used lba if ( new_mbr_part_count == 1) { // Only one EFI Protective partition min_start_lba = max_end_lba = last_disk_lba + 1; // Take whole disk } else { min_start_lba = new_mbr_parts[1].start_lba; max_end_lba = new_mbr_parts[1].end_lba; for (k = 2; k < new_mbr_part_count; k++) { if (max_end_lba < new_mbr_parts[k].end_lba) max_end_lba = new_mbr_parts[k].end_lba; if (min_start_lba > new_mbr_parts[k].start_lba) min_start_lba = new_mbr_parts[k].start_lba; } } // Reserved last part if not used if (new_mbr_part_count < 4 && max_end_lba < last_disk_lba && fill_mbr) { new_mbr_parts[new_mbr_part_count].index = new_mbr_part_count; new_mbr_parts[new_mbr_part_count].start_lba = max_end_lba + 1; new_mbr_parts[new_mbr_part_count].end_lba = last_disk_lba; new_mbr_parts[new_mbr_part_count].mbr_type = 0xee; // another protective area new_mbr_parts[new_mbr_part_count].active = FALSE; new_mbr_part_count ++; } // first entry: EFI Protective new_mbr_parts[0].index = 0; new_mbr_parts[0].start_lba = 1; new_mbr_parts[0].end_lba = min_start_lba - 1; new_mbr_parts[0].mbr_type = 0xee; action = ACTION_NOP; // Check if we need to rewrite MBR for (i = 0; i < 4; i ++) { if (new_mbr_parts[i].index != mbr_parts[i].index || new_mbr_parts[i].start_lba != mbr_parts[i].start_lba || new_mbr_parts[i].end_lba != mbr_parts[i].end_lba || new_mbr_parts[i].mbr_type != mbr_parts[i].mbr_type || new_mbr_parts[i].active != mbr_parts[i].active) { action = ACTION_REWRITE; break; } } if (action == ACTION_NOP) { Print(L"Status: Tables are synchronized, no need to sync.\n"); return 1; } else { Print(L"Status: MBR table must be updated.\n"); } // dump table Print(L"\nProposed new MBR partition table:\n"); Print(L" # A Start LBA End LBA Type\n"); for (i = 0; i < new_mbr_part_count; i++) { Print(L" %d %s %12lld %12lld %02x %s\n", new_mbr_parts[i].index + 1, new_mbr_parts[i].active ? STR("*") : STR(" "), new_mbr_parts[i].start_lba, new_mbr_parts[i].end_lba, new_mbr_parts[i].mbr_type, mbr_parttype_name(new_mbr_parts[i].mbr_type)); } return 0; }
UINTN read_mbr(VOID) { UINTN status; UINTN i; BOOLEAN used; MBR_PARTITION_INFO *table; Print(L"\nCurrent MBR partition table:\n"); // read MBR data status = read_sector(0, sector); if (status != 0) return status; // check for validity if (*((UINT16 *)(sector + 510)) != 0xaa55) { Print(L" No MBR partition table present!\n"); return 1; } table = (MBR_PARTITION_INFO *)(sector + 446); for (i = 0; i < 4; i++) { if (table[i].flags != 0x00 && table[i].flags != 0x80) { Print(L" MBR partition table is invalid!\n"); return 1; } } // check if used used = FALSE; for (i = 0; i < 4; i++) { if (table[i].start_lba > 0 && table[i].size > 0) { used = TRUE; break; } } if (!used) { Print(L" No partitions defined\n"); return 0; } // dump current state & fill internal structures Print(L" # A Start LBA End LBA Type\n"); for (i = 0; i < 4; i++) { if (table[i].start_lba == 0 || table[i].size == 0) continue; mbr_parts[mbr_part_count].index = i; mbr_parts[mbr_part_count].start_lba = (UINT64)table[i].start_lba; mbr_parts[mbr_part_count].end_lba = (UINT64)table[i].start_lba + (UINT64)table[i].size - 1; mbr_parts[mbr_part_count].mbr_type = table[i].type; mbr_parts[mbr_part_count].active = (table[i].flags == 0x80) ? TRUE : FALSE; Print(L" %d %s %12lld %12lld %02x %s\n", mbr_parts[mbr_part_count].index + 1, mbr_parts[mbr_part_count].active ? STR("*") : STR(" "), mbr_parts[mbr_part_count].start_lba, mbr_parts[mbr_part_count].end_lba, mbr_parts[mbr_part_count].mbr_type, mbr_parttype_name(mbr_parts[mbr_part_count].mbr_type)); mbr_part_count++; } return 0; }