Hi,
pretty much since Macs started a hybrid GPT/MBR approach there were
several attempts to get to a solution on using GPT on BIOS-based
computers. Unfortunately up to today I know of none that actually made
it somewhere except for the manual Mac syncing approach.
So my approach is trying to go the easiest way I could think of: always
sync. Instead of writing a fake MBR, when this code is enabled, it tries
to construct primary MBR entries from the first partitions it finds in
the GPT. This means, that as long as the partition we want to boot from
is within the first four partitions, everything will be fine.
This enables a user that is aware of this restriction to have a fully
working hybrid GPT/MBR setup, enabling him to boot without much
intervention on an Intel Mac and with disks >2TB.
The patch is based on parted 1.8.8.
Alex
Signed-off-by: Alexander Graf <[EMAIL PROTECTED]>
Index: libparted/labels/gpt.c
===================================================================
--- libparted/labels/gpt.c.orig
+++ libparted/labels/gpt.c
@@ -46,6 +46,8 @@
# define _(String) (String)
#endif /* ENABLE_NLS */
+#define GPT_SYNC_MBR
+
#define EFI_PMBR_OSTYPE_EFI 0xEE
#define MSDOS_MBR_SIGNATURE 0xaa55
@@ -402,6 +404,7 @@ guid_cmp (efi_guid_t left, efi_guid_t ri
return memcmp(&left, &right, sizeof(efi_guid_t));
}
+#ifndef GPT_SYNC_MBR
/* checks if 'mbr' is a protective MBR partition table */
static inline int
_pmbr_is_valid (const LegacyMBR_t* mbr)
@@ -418,6 +421,7 @@ _pmbr_is_valid (const LegacyMBR_t* mbr)
}
return 0;
}
+#endif
static int
gpt_probe (const PedDevice * dev)
@@ -445,6 +449,7 @@ gpt_probe (const PedDevice * dev)
if (!gpt_sig_found)
return 0;
+#ifndef GPT_SYNC_MBR
if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) {
if (!_pmbr_is_valid (&legacy_mbr)) {
int ex_status = ped_exception_throw (
@@ -463,6 +468,7 @@ gpt_probe (const PedDevice * dev)
return 0;
}
}
+#endif
return 1;
}
@@ -928,15 +934,51 @@ error:
return 0;
}
+#ifdef GPT_SYNC_MBR
+static inline unsigned char
+_part_to_ostype (PedPartition* part)
+{
+ GPTPartitionData* gpt_part_data = part->disk_specific;
+ 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 uint32_t
+_part_32bitmax (uint64_t in)
+{
+ if (in > 0xFFFFFFFFULL)
+ return 0xFFFFFFFF;
+ else
+ return (uint32_t)in;
+}
+#endif
+
#ifndef DISCOVER_ONLY
/* Writes the protective MBR (to keep DOS happy) */
static int
-_write_pmbr (PedDevice * dev)
+_write_pmbr (PedDisk * disk)
{
+ PedDevice * dev = disk->dev;
LegacyMBR_t pmbr;
+#ifdef GPT_SYNC_MBR
+ int i;
+ PedPartition* part = NULL;
+#endif
+#ifdef GPT_SYNC_MBR
+ /* Keep the old MBR as much as possible */
+ ped_device_read(dev, &pmbr, 0, GPT_HEADER_SECTORS);
+ memset(&pmbr.PartitionRecord, 0, sizeof(pmbr.PartitionRecord));
+#else
memset(&pmbr, 0, sizeof(pmbr));
+#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;
@@ -947,6 +989,31 @@ _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
+ /* sync the first 4 GPT entries to MBR primary partitions */
+ for (i=0; i < 4; 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) {
+ i--;
+ continue;
+ }
+ pmbr.PartitionRecord[i].OSType = _part_to_ostype(part);
+ pmbr.PartitionRecord[i].StartSector = 1;
+ 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);
+ }
+#endif
return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
}
@@ -1050,7 +1117,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 */
_______________________________________________
parted-devel mailing list
parted-devel@lists.alioth.debian.org
http://lists.alioth.debian.org/mailman/listinfo/parted-devel