This patch improves GPT support on PC/BIOS systems by allowing grub-setup to
locate usable regions for embedding our core.img (akin to sector 0x1 on PC
partmap), and use them accordingly.

Comments?

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
2008-02-17  Robert Millan  <[EMAIL PROTECTED]>

	* partmap/gpt.c: Include `<grub/gpt_partition.h>'.
	(grub_gpt_partition_type_empty): Redefine with macro from
	`<grub/gpt_partition.h>'.
	(gpt_partition_map_iterate): Adjust partition type comparison.

	Export `entry' as partmap-specific `part.data' struct.
	(grub_gpt_header, grub_gpt_partentry): Move from here ...

	* include/grub/gpt_partition.h (grub_gpt_header)
	(grub_gpt_partentry): ... to here (new file).

	* util/i386/pc/grub-setup.c: Include `<grub/gpt_partition.h>'.

	(grub_gpt_partition_type_bios_boot): New const variable, defined
	with macro from `<grub/gpt_partition.h>'.

	(setup): Replace `first_start' with `embed_region', which keeps
	track of the embed region (and is partmap-agnostic).

	Replace find_first_partition_start() with find_usable_region(),
	which finds a usable region for embedding using partmap-specific
	knowledge (supports PC/MSDOS and GPT).

	Fix all assumptions that the embed region start at sector 1, using
	`embed_region.start' from now on.  Similarly, use `embed_region.end'
	rather than `first_start' to calculate available size.

	In grub_util_info() message, replace "into after the MBR" with an
	indication of the specific sector our embed region starts at.

diff -x '*~' -Nurp ../grub2/partmap/gpt.c ./partmap/gpt.c
--- ../grub2/partmap/gpt.c	2007-07-21 19:32:30.000000000 -0400
+++ ./partmap/gpt.c	2008-02-16 19:49:14.000000000 -0500
@@ -1,7 +1,7 @@
 /* gpt.c - Read GUID Partition Tables (GPT).  */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2005,2006,2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2005,2006,2007,2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -23,41 +23,14 @@
 #include <grub/partition.h>
 #include <grub/dl.h>
 #include <grub/pc_partition.h>
-
-struct grub_gpt_header
-{
-  grub_uint8_t magic[8];
-  grub_uint32_t version;
-  grub_uint32_t headersize;
-  grub_uint32_t crc32;
-  grub_uint32_t unused1;
-  grub_uint64_t primary;
-  grub_uint64_t backup;
-  grub_uint64_t start;
-  grub_uint64_t end;
-  grub_uint8_t guid[16];
-  grub_uint64_t partitions;
-  grub_uint32_t maxpart;
-  grub_uint32_t partentry_size;
-  grub_uint32_t partentry_crc32;
-} __attribute__ ((packed));
-
-struct grub_gpt_partentry
-{
-  grub_uint8_t type[16];
-  grub_uint8_t guid[16];
-  grub_uint64_t start;
-  grub_uint64_t end;
-  grub_uint8_t attrib;
-  char name[72];
-} __attribute__ ((packed));
+#include <grub/gpt_partition.h>
 
 static grub_uint8_t grub_gpt_magic[8] =
   {
     45, 46, 49, 20, 50, 41, 52, 54
   };
 
-static grub_uint8_t grub_gpt_partition_type_empty[16] = { 0 };
+static const grub_gpt_part_type_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY;
 
 static struct grub_partition_map grub_gpt_partition_map;
 
@@ -114,7 +87,7 @@ gpt_partition_map_iterate (grub_disk_t d
 			  sizeof (entry), (char *) &entry))
 	return grub_errno;
 
-      if (grub_memcmp (grub_gpt_partition_type_empty, entry.type,
+      if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
 		       sizeof (grub_gpt_partition_type_empty)))
 	{
 	  /* Calculate the first block and the size of the partition.  */
@@ -124,6 +97,7 @@ gpt_partition_map_iterate (grub_disk_t d
 	  part.offset = entries;
 	  part.index = partno;
 	  part.partmap = &grub_gpt_partition_map;
+	  part.data = &entry;
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n",
 			partno, part.start, part.len);
diff -x '*~' -Nurp ../grub2/include/grub/gpt_partition.h ./include/grub/gpt_partition.h
--- ../grub2/include/grub/gpt_partition.h	1969-12-31 19:00:00.000000000 -0500
+++ ./include/grub/gpt_partition.h	2008-02-16 19:46:30.000000000 -0500
@@ -0,0 +1,71 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GPT_PARTITION_HEADER
+#define GRUB_GPT_PARTITION_HEADER	1
+
+#include <grub/types.h>
+
+struct grub_gpt_part_type
+{
+  grub_uint32_t data1;
+  grub_uint16_t data2;
+  grub_uint16_t data3;
+  grub_uint8_t data4[8];
+} __attribute__ ((aligned(8)));
+typedef struct grub_gpt_part_type grub_gpt_part_type_t;
+
+#define GRUB_GPT_PARTITION_TYPE_EMPTY \
+  { 0x0, 0x0, 0x0, \
+    { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } \
+  }
+
+#define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \
+  { 0x6b6f6f4c, 0x6449, 0x6e6f, \
+    { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \
+  }
+
+struct grub_gpt_header
+{
+  grub_uint8_t magic[8];
+  grub_uint32_t version;
+  grub_uint32_t headersize;
+  grub_uint32_t crc32;
+  grub_uint32_t unused1;
+  grub_uint64_t primary;
+  grub_uint64_t backup;
+  grub_uint64_t start;
+  grub_uint64_t end;
+  grub_uint8_t guid[16];
+  grub_uint64_t partitions;
+  grub_uint32_t maxpart;
+  grub_uint32_t partentry_size;
+  grub_uint32_t partentry_crc32;
+} __attribute__ ((packed));
+
+struct grub_gpt_partentry
+{
+  grub_gpt_part_type_t type;
+  grub_uint8_t guid[16];
+  grub_uint64_t start;
+  grub_uint64_t end;
+  grub_uint8_t attrib;
+  char name[72];
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_GPT_PARTITION_HEADER */
diff -x '*~' -Nurp ../grub2/util/i386/pc/grub-setup.c ./util/i386/pc/grub-setup.c
--- ../grub2/util/i386/pc/grub-setup.c	2008-02-16 18:45:53.000000000 -0500
+++ ./util/i386/pc/grub-setup.c	2008-02-16 19:47:21.000000000 -0500
@@ -1,7 +1,7 @@
 /* grub-setup.c - make GRUB usable */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007  Free Software Foundation, Inc.
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
 #include <grub/fs.h>
 #include <grub/partition.h>
 #include <grub/pc_partition.h>
+#include <grub/gpt_partition.h>
 #include <grub/env.h>
 #include <grub/util/biosdisk.h>
 #include <grub/machine/boot.h>
@@ -34,6 +35,8 @@
 #include <grub/util/raid.h>
 #include <grub/util/lvm.h>
 
+static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
+
 #include <grub_setup_init.h>
 
 #include <stdio.h>
@@ -106,7 +109,8 @@ setup (const char *prefix, const char *d
   grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE;
   grub_file_t file;
   FILE *fp;
-  unsigned long first_start = ~0UL;
+  struct { grub_uint64_t start; grub_uint64_t end; } embed_region;
+  embed_region.start = embed_region.end = ~0UL;
   int able_to_embed = 1;
   
   auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset,
@@ -114,25 +118,37 @@ setup (const char *prefix, const char *d
   auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset,
 			     unsigned length);
 
-  auto int find_first_partition_start (grub_disk_t disk,
-				       const grub_partition_t p);
-  
-  int find_first_partition_start (grub_disk_t disk __attribute__ ((unused)),
-				  const grub_partition_t p)
+  auto int find_usable_region (grub_disk_t disk,
+			       const grub_partition_t p);
+  int find_usable_region (grub_disk_t disk __attribute__ ((unused)),
+			  const grub_partition_t p)
     {
       if (! strcmp (p->partmap->name, "pc_partition_map"))
 	{
 	  struct grub_pc_partition *pcdata = p->data;
 	  
+	  /* There's always an embed region, and it starts right after the MBR.  */
+	  embed_region.start = 1;
+	  
+	  /* For its end offset, include as many dummy partitions as we can.  */
 	  if (! grub_pc_partition_is_empty (pcdata->dos_type)
 	      && ! grub_pc_partition_is_bsd (pcdata->dos_type)
-	      && first_start > p->start)
-	    first_start = p->start;
+	      && embed_region.end > p->start)
+	    embed_region.end = p->start;
 	}
       else
-	/* In other partition maps, the region after MBR and before first
-	   partition is not reserved (on GPT, it contains the primary header).  */
-	first_start = 0;
+	{
+	  struct grub_gpt_partentry *gptdata = p->data;
+	  
+	  /* If there's an embed region, it is in a dedicated partition.  */
+	  if (! memcmp (&gptdata->type, &grub_gpt_partition_type_bios_boot, 16))
+	    {
+	      embed_region.start = p->start;
+	      embed_region.end = p->start + p->len;
+	      
+	      return 1;
+	    }
+	}
 
       return 0;
     }
@@ -262,15 +278,15 @@ setup (const char *prefix, const char *d
      try to embed the core image into after the MBR.  */
   if (dest_dev->disk->has_partitions && ! dest_dev->disk->partition)
     {
-      grub_partition_iterate (dest_dev->disk, find_first_partition_start);
+      grub_partition_iterate (dest_dev->disk, find_usable_region);
 
       /* If there is enough space...  */
-      if ((unsigned long) core_sectors + 1 <= first_start)
+      if ((unsigned long) core_sectors <= embed_region.end - embed_region.start)
 	{
-	  grub_util_info ("will embed the core image into after the MBR");
-	  
+	  grub_util_info ("will embed the core image at sector 0x%llx", embed_region.start);
+
 	  /* The first blocklist contains the whole sectors.  */
-	  first_block->start = grub_cpu_to_le64 (2);
+	  first_block->start = grub_cpu_to_le64 (embed_region.start + 1);
 	  first_block->len = grub_cpu_to_le16 (core_sectors - 1);
 	  first_block->segment
 	    = grub_cpu_to_le16 (GRUB_BOOT_MACHINE_KERNEL_SEG
@@ -316,13 +332,13 @@ setup (const char *prefix, const char *d
 	  strcpy (install_prefix, prefix);
 	  
 	  /* Write the core image onto the disk.  */
-	  if (grub_disk_write (dest_dev->disk, 1, 0, core_size, core_img))
+	  if (grub_disk_write (dest_dev->disk, embed_region.start, 0, core_size, core_img))
 	    grub_util_error ("%s", grub_errmsg);
 
 	  /* The boot image and the core image are on the same drive,
 	     so there is no need to specify the boot drive explicitly.  */
 	  *boot_drive = 0xff;
-	  *kernel_sector = grub_cpu_to_le64 (1);
+	  *kernel_sector = grub_cpu_to_le64 (embed_region.start);
 
           /* If the root device is different from the destination device,
              it is necessary to embed the root drive explicitly.  */
_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to