--- libparted/labels/gpt.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) Index: libparted/labels/gpt.c =================================================================== --- libparted/labels/gpt.c.orig +++ libparted/labels/gpt.c @@ -51,6 +51,11 @@ # 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 @@ -1072,11 +1077,60 @@ error: return 0; } + +#ifdef GPT_SYNC_MBR +static inline unsigned char +_part_to_ostype (PedPartition* part) +{ + if (part->fs_type) { + if (strncmp (part->fs_type->name, "fat", 3) == 0) return 0xc; + if (strncmp (part->fs_type->name, "ntfs", 4) == 0) return 0x7; + if (strncmp (part->fs_type->name, "hfs", 3) == 0) return 0xaf; + if (strstr (part->fs_type->name, "swap")) return 0x82; + } + return 0x83; // Everything else is Linux +} + +static inline PedPartition* +_find_first_part (const PedDisk* disk) +{ + PedPartition *retval = NULL, *part = NULL; + uint64_t lowest_end = 0xffffffffffffffff; + while (part = ped_disk_next_partition (disk, part)) { + if (part->geom.start == 0 || part->type == PED_PARTITION_METADATA + || part->type == PED_PARTITION_FREESPACE) + continue; + if (part->geom.end < lowest_end) { + retval = part; + lowest_end = part->geom.end; + } + } + return retval; +} + +static inline uint32_t +_part_32bitmax (uint64_t in) +{ + if (in > 0xFFFFFFFFULL) + return 0xFFFFFFFF; + else + return (uint32_t)in; +} +#endif + + #ifndef DISCOVER_ONLY /* Write the protective MBR (to keep DOS happy) */ static int -_write_pmbr (PedDevice *dev) +_write_pmbr (const PedDisk *disk) { + PedDevice * dev = disk->dev; + +#ifdef GPT_SYNC_MBR + 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), UniqueMBRSignature (440B-444B) and Unknown (444B-446B). @@ -1086,10 +1140,13 @@ _write_pmbr (PedDevice *dev) 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 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI; pmbr->PartitionRecord[0].StartSector = 1; pmbr->PartitionRecord[0].EndHead = 0xFE; @@ -1100,6 +1157,53 @@ _write_pmbr (PedDevice *dev) pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF); else pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL); +#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) + esp = NULL; + + pmbr_id = 3; + if (esp) { + pmbr_id = 0; + first_entry = 1; + last_entry = 4; + } + + /* Write a pseudo-PMBR so Linux is happy */ + pmbr->PartitionRecord[pmbr_id].OSType = EFI_PMBR_OSTYPE_EFI; + pmbr->PartitionRecord[pmbr_id].StartSector = 1; + pmbr->PartitionRecord[pmbr_id].EndHead = 0xFE; + pmbr->PartitionRecord[pmbr_id].EndSector = 0xFF; + pmbr->PartitionRecord[pmbr_id].EndTrack = 0xFF; + pmbr->PartitionRecord[pmbr_id].StartingLBA = PED_CPU_TO_LE32(1); + pmbr->PartitionRecord[pmbr_id].SizeInLBA = 1; + if (esp) + pmbr->PartitionRecord[pmbr_id].SizeInLBA = esp->geom.end - 1; + + /* sync the first 3 GPT entries to MBR primary partitions */ + for (i=first_entry; i < last_entry; i++) { + part = ped_disk_next_partition (disk, part); + if (part == NULL) + break; + /* we might get a starting garbage partition */ + if (part->geom.start == 0 || part->type == PED_PARTITION_METADATA || part->type == PED_PARTITION_FREESPACE || part == esp) { + i--; + continue; + } + pmbr->PartitionRecord[i].OSType = _part_to_ostype(part); + pmbr->PartitionRecord[i].StartHead = 0xFE; + pmbr->PartitionRecord[i].StartSector = 0xFF; + pmbr->PartitionRecord[i].StartTrack = 0xFF; + pmbr->PartitionRecord[i].EndHead = 0xFE; + pmbr->PartitionRecord[i].EndSector = 0xFF; + pmbr->PartitionRecord[i].EndTrack = 0xFF; + pmbr->PartitionRecord[i].StartingLBA = _part_32bitmax(part->geom.start); + if(((GPTPartitionData*)part->disk_specific)->boot) + 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); @@ -1216,7 +1320,7 @@ gpt_write (const PedDisk *disk) ptes_crc = efi_crc32 (ptes, ptes_size); /* Write protective MBR */ - if (!_write_pmbr (disk->dev)) + if (!_write_pmbr (disk)) goto error_free_ptes; /* Write PTH and PTEs */