Index: parted-2.4/libparted/labels/gpt.c =================================================================== --- parted-2.4.orig/libparted/labels/gpt.c +++ parted-2.4/libparted/labels/gpt.c @@ -51,11 +51,6 @@ # define _(String) (String) #endif /* ENABLE_NLS */ -/* IA64 always has a properly working EFI implementation */ -#ifndef __ia64__ -#define GPT_SYNC_MBR -#endif - #define EFI_PMBR_OSTYPE_EFI 0xEE #define MSDOS_MBR_SIGNATURE 0xaa55 @@ -290,6 +285,7 @@ typedef struct _GPTPartitionData } GPTPartitionData; static PedDiskType gpt_disk_type; +static PedDiskType gpt_sync_mbr_disk_type; static inline uint32_t pth_get_size (const PedDevice *dev) @@ -458,8 +454,50 @@ _pmbr_is_valid (const LegacyMBR_t *mbr) return 0; } +/* checks if device has a hybrid protective MBR partition table + * + * If the 1st partition has type 0xEE that spans the entire + * size of the disk from sector 1 to the last sector + * (or 2 TiB, whichever is smaller), we consider it 'normal' GPT. + * Otherwise it is synced GPT with hybridized pMBR. + */ +static inline int +_has_hybrid_pmbr (const PedDevice *dev) +{ + int has_hybrid_pmbr = 1; + + PED_ASSERT (dev != NULL); + + void *label; + if (!ptt_read_sector (dev, 0, &label)) + return 0; + + LegacyMBR_t mbr; + memcpy(&mbr, label, sizeof(mbr)); + + if (mbr.Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE)) { + free(label); + return 0; + } + + uint32_t efi_gpt_expected_size; + if ((dev->length - 1ULL) > 0xFFFFFFFFULL) + efi_gpt_expected_size = 0xFFFFFFFF; + else + efi_gpt_expected_size = dev->length - 1UL; + + if ((mbr.PartitionRecord[0].OSType == EFI_PMBR_OSTYPE_EFI) && + (mbr.PartitionRecord[0].StartingLBA == PED_CPU_TO_LE32(1)) && + (mbr.PartitionRecord[0].SizeInLBA == PED_CPU_TO_LE32(efi_gpt_expected_size))) + /* pMBR is not hybrid */ + has_hybrid_pmbr = 0; + + free(label); + return has_hybrid_pmbr; +} + static int -gpt_probe (const PedDevice *dev) +_gpt_probe_generic(const PedDevice *dev) { GuidPartitionTableHeader_t *gpt = NULL; int gpt_sig_found = 0; @@ -512,6 +550,19 @@ gpt_probe (const PedDevice *dev) return ok; } +static int +gpt_probe (const PedDevice *dev) +{ + return _gpt_probe_generic(dev) && !_has_hybrid_pmbr(dev); +} + + +static int +gpt_sync_mbr_probe (const PedDevice *dev) +{ + return _gpt_probe_generic(dev) && _has_hybrid_pmbr(dev); +} + static PedDisk * gpt_alloc (const PedDevice *dev) { @@ -543,6 +594,36 @@ error: } static PedDisk * +gpt_sync_mbr_alloc (const PedDevice *dev) +{ + PedDisk *disk; + GPTDiskData *gpt_disk_data; + PedSector data_start, data_end; + + disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_sync_mbr_disk_type); + if (!disk) + goto error; + disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData)); + if (!disk->disk_specific) + goto error_free_disk; + + data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size; + data_end = dev->length - 2 + - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size; + ped_geometry_init (&gpt_disk_data->data_area, dev, data_start, + data_end - data_start + 1); + gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES; + uuid_generate ((unsigned char *) &gpt_disk_data->uuid); + swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid)); + return disk; + +error_free_disk: + free (disk); +error: + return NULL; +} + +static PedDisk * gpt_duplicate (const PedDisk *disk) { PedDisk *new_disk; @@ -920,7 +1001,7 @@ gpt_read (PedDisk *disk) /* motivation: let the user decide about the pmbr... during ped_disk_probe(), they probably didn't get a choice... */ - if (!gpt_probe (disk->dev)) + if (!gpt_probe (disk->dev) && !gpt_sync_mbr_probe(disk->dev)) goto error; GuidPartitionTableHeader_t *gpt = NULL; @@ -1078,7 +1159,6 @@ error: } -#ifdef GPT_SYNC_MBR static inline unsigned char _part_to_ostype (PedPartition* part) { @@ -1116,7 +1196,6 @@ _part_32bitmax (uint64_t in) else return (uint32_t)in; } -#endif #ifndef DISCOVER_ONLY @@ -1126,10 +1205,11 @@ _write_pmbr (const PedDisk *disk) { PedDevice * dev = disk->dev; -#ifdef GPT_SYNC_MBR + /* need sync GPT -> hybrid pMBR ? */ + int sync_pmbr = !strcmp(disk->type->name, "gpt_sync_mbr") ? 1 : 0; + int i, pmbr_id, first_entry = 0, last_entry = 3; PedPartition *part = NULL, *esp; -#endif /* The UEFI spec is not clear about what to do with the following elements of the Protective MBR (pmbr): BootCode (0-440B), @@ -1140,13 +1220,12 @@ _write_pmbr (const PedDisk *disk) return 0; LegacyMBR_t *pmbr = s0; -#ifndef GPT_SYNC_MBR /* Zero out the legacy partitions. */ memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord); -#endif pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE); -#ifndef GPT_SYNC_MBR + + if (!sync_pmbr) { pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI; pmbr->PartitionRecord[0].StartSector = 1; pmbr->PartitionRecord[0].EndHead = 0xFE; @@ -1157,7 +1236,7 @@ _write_pmbr (const PedDisk *disk) pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF); else pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL); -#else + } else { /* Search for an EFI System Partition */ esp = _find_first_part(disk); if (!esp || !esp->fs_type || strncmp (esp->fs_type->name, "fat", 3) != 0) @@ -1191,6 +1270,13 @@ _write_pmbr (const PedDisk *disk) i--; continue; } + + /* partition can not be represented by dos label - don't sync it */ + if (part->geom.start > 0xFFFFFFFF || + (part->geom.end - part->geom.start + 1) > 0xFFFFFFFF) { + continue; + } + pmbr->PartitionRecord[i].OSType = _part_to_ostype(part); pmbr->PartitionRecord[i].StartHead = 0xFE; pmbr->PartitionRecord[i].StartSector = 0xFF; @@ -1203,8 +1289,7 @@ _write_pmbr (const PedDisk *disk) pmbr->PartitionRecord[i].BootIndicator = 0x80; pmbr->PartitionRecord[i].SizeInLBA = _part_32bitmax(part->geom.end - part->geom.start + 1); } -#endif - + } int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS); free (s0); @@ -1902,6 +1987,38 @@ static PedDiskOps gpt_disk_ops = PT_op_function_initializers (gpt) }; +static PedDiskOps gpt_sync_mbr_disk_ops = +{ + clobber: NULL, + write: NULL_IF_DISCOVER_ONLY (gpt_write), + + partition_set_name: gpt_partition_set_name, + partition_get_name: gpt_partition_get_name, + + /* probe function redefined */ + probe: gpt_sync_mbr_probe, + /* alloc function redefined */ + alloc: gpt_sync_mbr_alloc, + duplicate: gpt_duplicate, + free: gpt_free, + read: gpt_read, + partition_new: gpt_partition_new, + partition_duplicate: gpt_partition_duplicate, + partition_set_flag: gpt_partition_set_flag, + partition_get_flag: gpt_partition_get_flag, + partition_set_system: gpt_partition_set_system, + partition_is_flag_available: gpt_partition_is_flag_available, + partition_align: gpt_partition_align, + partition_destroy: gpt_partition_destroy, + partition_enumerate: gpt_partition_enumerate, + alloc_metadata: gpt_alloc_metadata, + get_max_primary_partition_count: gpt_get_max_primary_partition_count, + get_max_supported_partition_count: gpt_get_max_supported_partition_count, + partition_check: gpt_partition_check, + max_length: gpt_partition_max_length, + max_start_sector: gpt_partition_max_start_sector +}; + static PedDiskType gpt_disk_type = { next: NULL, @@ -1910,16 +2027,26 @@ static PedDiskType gpt_disk_type = features: PED_DISK_TYPE_PARTITION_NAME }; +static PedDiskType gpt_sync_mbr_disk_type = +{ + next: NULL, + name: "gpt_sync_mbr", + ops: &gpt_sync_mbr_disk_ops, + features: PED_DISK_TYPE_PARTITION_NAME +}; + void ped_disk_gpt_init () { ped_disk_type_register (&gpt_disk_type); + ped_disk_type_register (&gpt_sync_mbr_disk_type); } void ped_disk_gpt_done () { ped_disk_type_unregister (&gpt_disk_type); + ped_disk_type_unregister (&gpt_sync_mbr_disk_type); } verify (sizeof (GuidPartitionEntryAttributes_t) == 8);