[parted-devel] [PATCH] Synchronise MBR tables with GPT

Matthew Garrett mjg59 at srcf.ucam.org
Fri Mar 2 20:21:25 CET 2007


This is a rough and unfinished patch that alters the behaviour of the 
GPT label code such that it writes a valid MBR rather than a protective 
one. This is necessary for Apple systems using legacy BIOS emulation - 
the system will only boot drives that have an entry in the MBR. I've 
attempted to keep it bug compatible with the Apple firmware, but haven't 
been able to find any documentation to explain some of the issues. The 
two main quirks I've found seem to be:

1) The EFI system partition must be tagged as starting from the very 
beginning of the disk
2) The second partition must be tagged as bootable

and so I've special cased both of these. If anyone has any contacts in 
Apple who could explain what the constraints actually are, that would be 
helpful.

I'm not terribly familiar with the parted code, so if there are better 
ways of doing any of these bits then I'd love to know.

--- /tmp/parted-1.7.1/libparted/labels/gpt.c	2006-06-09 21:10:19.000000000 +0100
+++ libparted/labels/gpt.c	2007-03-02 19:17:47.000000000 +0000
@@ -420,30 +420,10 @@
 
         if (gpt)
 	        pth_free (gpt);
-
         
 	if (!gpt_sig_found)
 		return 0;
 
-	if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) {
-		if (!_pmbr_is_valid (&legacy_mbr)) {
-			int ex_status = ped_exception_throw (
-				PED_EXCEPTION_WARNING,
-				PED_EXCEPTION_YES_NO,
-			_("%s contains GPT signatures, indicating that it has "
-			  "a GPT table.  However, it does not have a valid "
-			  "fake msdos partition table, as it should.  Perhaps "
-			  "it was corrupted -- possibly by a program that "
-			  "doesn't understand GPT partition tables.  Or "
-			  "perhaps you deleted the GPT table, and are now "
-			  "using an msdos partition table.  Is this a GPT "
-			  "partition table?"),
-				dev->path);
-			if (ex_status == PED_EXCEPTION_NO)
-				return 0;
-		}
-	}
-
 	return 1;
 }
 
@@ -711,6 +691,10 @@
  *  warn if it's not there, and treat the disk as MSDOS, with a note
  *  for users to use Parted to "fix up" their disk if they
  *  really want it to be considered GPT.
+ *
+ *  Of course, this is incompatible with how Apple handle things. For
+ *  legacy BIOS compatibility on Apple machines, we need a valid legacy MBR
+ *  rather than a protective one. Aren't standards wonderful?
  ************************************************************/
 static int
 gpt_read (PedDisk * disk)
@@ -847,26 +831,94 @@
 }
 
 #ifndef DISCOVER_ONLY
-/* Writes the protective MBR (to keep DOS happy) */
+
 static int
-_write_pmbr (PedDevice * dev)
+fill_raw_part (PartitionRecord_t* raw_part, PedPartition *part, PedSector offset, int number)
+{
+        GPTPartitionData* gpt_part_data = part->disk_specific;
+
+	if (part->fs_type) {
+	        if (strncmp (part->fs_type->name, "fat", 3) == 0)
+		        raw_part->OSType = 0x0b;
+		else if (strncmp (part->fs_type->name, "ntfs", 4) == 0)
+  		        raw_part->OSType = 0x07;
+		else if (strncmp (part->fs_type->name, "hfs", 3) == 0)
+		        raw_part->OSType = 0xaf;
+		else if (strncmp (part->fs_type->name, "ext3", 4) == 0)
+		        raw_part->OSType = 0x83;
+		else if (strncmp (part->fs_type->name, "linux-swap", 10) == 0)
+		        raw_part->OSType = 0x82;
+		else 
+			raw_part->OSType = 0xef;
+	}
+
+	/* EFI system partitions will have a FAT filesystem and 
+	   PARTITION_SYSTEM_GUID */
+
+	if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID)) {
+		if (raw_part->OSType = 0x0b) {
+			raw_part->OSType = 0xee;
+		}
+	}
+
+	/* Apple's firmware appears to become unhappy if the second partition
+	   isn't bootable */
+
+	if (number == 2)
+		raw_part->BootIndicator = 0x80;
+
+	raw_part->StartingLBA = PED_CPU_TO_LE32 ((part->geom.start - offset)
+                                / (part->disk->dev->sector_size / 512));
+
+	raw_part->SizeInLBA = PED_CPU_TO_LE32 (part->geom.length
+				  / (part->disk->dev->sector_size / 512));
+
+	/* Apple's firmware also appears to be unhappy if the EFI system 
+	   partition doesn't extend all the way to the start of the disk */
+
+	if (raw_part->OSType == 0xee) {
+	  raw_part->SizeInLBA += raw_part->StartingLBA - 1;
+	  raw_part->StartingLBA = 1;
+	}
+
+	raw_part->StartHead = 0xfe;
+	raw_part->StartSector = 0xff;
+	raw_part->StartTrack = 0xff;
+	raw_part->EndHead = 0xfe;
+	raw_part->EndSector = 0xff;
+	raw_part->EndTrack = 0xff;
+	
+	return 1;
+}
+
+static int
+_gptsync (PedDisk * disk)
 {
 	LegacyMBR_t pmbr;
+	PedPartition* part;
+	int i;
 
-	memset(&pmbr, 0, sizeof(pmbr));
+	if (!ped_device_read (disk->dev, (void*) &pmbr, GPT_PMBR_LBA, 
+			       GPT_PMBR_SECTORS))
+	        return 0;
+
+	memset(&pmbr.PartitionRecord, 0, sizeof(pmbr.PartitionRecord));
 	pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
-	pmbr.PartitionRecord[0].OSType      = EFI_PMBR_OSTYPE_EFI;
-	pmbr.PartitionRecord[0].StartSector = 1;
-	pmbr.PartitionRecord[0].EndHead     = 0xFE;
-	pmbr.PartitionRecord[0].EndSector   = 0xFF;
-	pmbr.PartitionRecord[0].EndTrack    = 0xFF;
-	pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
-	if ((dev->length - 1ULL) > 0xFFFFFFFFULL) 
-		pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
-	else
-		pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
 
-	return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
+	for (i=1; i<=4; i++) {
+		part = ped_disk_get_partition (disk, i);
+		if (!part)
+			continue;
+
+		if (!fill_raw_part (&pmbr.PartitionRecord [i - 1], part, 0, i))
+			return 0;
+	}
+
+	if (!ped_device_write (disk->dev, (void*) &pmbr, GPT_PMBR_LBA, 
+			       GPT_PMBR_SECTORS))
+	        return 0;
+
+	return ped_device_sync (disk->dev);
 }
 
 static void
@@ -966,8 +1018,8 @@
 
 	ptes_crc = efi_crc32 (ptes, ptes_size);
 
-	/* Write protective MBR */
-	if (!_write_pmbr (disk->dev))
+	/* Write synced MBR */
+	if (!_gptsync (disk))
 		goto error_free_ptes;
 
 	/* Write PTH and PTEs */

-- 
Matthew Garrett | mjg59 at srcf.ucam.org



More information about the parted-devel mailing list