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

Reply via email to