All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFT,PATCH] Move embedding to appropriate partmap files
@ 2009-08-11 13:33 Vladimir 'phcoder' Serbinenko
  2009-08-12  0:38 ` Robert Millan
  0 siblings, 1 reply; 12+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-11 13:33 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 452 bytes --]

Hello. A bug was filed that embedding code in grub-setup.c was
ignoring partmap metadata which could cause its overwriting. To avoid
usage of metadata and because of upcoming sunpc embedding support I
propose to move embedding to partmap/*.c. For this I devised an
interface which enables future reusage of embedding for other too if
necessary.

-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: partfix.diff --]
[-- Type: text/plain, Size: 15923 bytes --]

diff --git a/include/grub/partition.h b/include/grub/partition.h
index 37c5f24..c162955 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -25,6 +25,13 @@ struct grub_disk;
 
 typedef struct grub_partition *grub_partition_t;
 
+#ifdef GRUB_UTIL
+typedef enum
+{
+  GRUB_EMBED_PCBIOS
+} grub_embed_type_t;
+#endif
+
 /* Partition map type.  */
 struct grub_partition_map
 {
@@ -43,6 +50,12 @@ struct grub_partition_map
   /* Return the name of the partition PARTITION.  */
   char *(*get_name) (const grub_partition_t partition);
 
+#ifdef GRUB_UTIL
+  /* Determine sectors available for embedding.  */
+  grub_err_t (*embed) (struct grub_disk *disk, unsigned int nsectors,
+		       grub_embed_type_t embed_type, grub_disk_addr_t *sectors);
+#endif
+
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
diff --git a/partmap/gpt.c b/partmap/gpt.c
index d646d41..0ac38a4 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -25,6 +25,13 @@
 #include <grub/pc_partition.h>
 #include <grub/gpt_partition.h>
 
+#ifdef GRUB_UTIL
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#endif
+
 static grub_uint8_t grub_gpt_magic[8] =
   {
     0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
@@ -32,6 +39,10 @@ static grub_uint8_t grub_gpt_magic[8] =
 
 static const grub_gpt_part_type_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY;
 
+#ifdef GRUB_UTIL
+static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
+#endif
+
 static struct grub_partition_map grub_gpt_partition_map;
 
 \f
@@ -99,7 +110,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
 			(unsigned long long) part.len);
 
 	  if (hook (disk, &part))
-	    return 1;
+	    return grub_errno;
 	}
 
       last_offset += grub_le_to_cpu32 (gpt.partentry_size);
@@ -172,6 +183,60 @@ gpt_partition_map_get_name (const grub_partition_t p)
   return name;
 }
 
+#ifdef GRUB_UTIL
+static grub_err_t
+gpt_partition_map_embed (struct grub_disk *disk, unsigned int nsectors,
+			 grub_embed_type_t embed_type,
+			 grub_disk_addr_t *sectors)
+{
+  grub_disk_addr_t start = 0, len = 0;
+  unsigned i;
+  grub_err_t err;
+
+  auto int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk,
+						const grub_partition_t p);
+  int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk __attribute__ ((unused)),
+					   const grub_partition_t p)
+    {
+      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))
+	{
+	  start = p->start;
+	  len = p->len;
+
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  if (embed_type != GRUB_EMBED_PCBIOS)
+    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+		       "GPT curently supports only PC-BIOS embedding");
+
+  err = gpt_partition_map_iterate (disk, find_usable_region);
+  if (err)
+    return err;
+
+  if (len == 0)
+    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+		       "This GPT partition label has no BIOS Boot Partition;"
+		       " embedding won't be possible!");
+
+  if (len < nsectors)
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+		       "Your BIOS Boot Partition is too small;"
+		       " embedding won't be possible!");
+
+  for (i = 0; i < nsectors; i++)
+    sectors[i] = start + i;
+
+  return GRUB_ERR_NONE;
+}
+#endif
+
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_gpt_partition_map =
@@ -179,7 +244,10 @@ static struct grub_partition_map grub_gpt_partition_map =
     .name = "gpt_partition_map",
     .iterate = gpt_partition_map_iterate,
     .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
+    .get_name = gpt_partition_map_get_name,
+#ifdef GRUB_UTIL
+    .embed = gpt_partition_map_embed
+#endif
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/pc.c b/partmap/pc.c
index 6a2efd2..466e790 100644
--- a/partmap/pc.c
+++ b/partmap/pc.c
@@ -153,7 +153,7 @@ pc_partition_map_iterate (grub_disk_t disk,
 	      pcdata.dos_part++;
 
 	      if (hook (disk, &p))
-		return 1;
+		return grub_errno;
 
 	      /* Check if this is a BSD partition.  */
 	      if (grub_pc_partition_is_bsd (e->type))
@@ -299,6 +299,107 @@ pc_partition_map_get_name (const grub_partition_t p)
   return name;
 }
 
+#ifdef GRUB_UTIL
+static grub_err_t
+pc_partition_map_embed (struct grub_disk *disk, unsigned int nsectors,
+			 grub_embed_type_t embed_type,
+			 grub_disk_addr_t *sectors)
+{
+  grub_disk_addr_t end = ~0ULL;
+  unsigned int i;
+  struct grub_pc_partition_mbr mbr;
+  struct grub_disk raw;
+  grub_uint32_t ext_offset, offset;
+  int index;
+  grub_err_t err;
+
+  if (embed_type != GRUB_EMBED_PCBIOS)
+    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+		       "PC-style partitions curently support "
+		       "only PC-BIOS embedding");
+
+  /* Enforce raw disk access.  */
+  raw = *disk;
+  raw.partition = 0;
+
+  offset = 0;
+  ext_offset = 0;
+
+  while (1)
+    {
+      struct grub_pc_partition_entry *e;
+
+      /* Read the MBR.  */
+      err = grub_disk_read (&raw, offset, 0, sizeof (mbr), &mbr);
+      if (err)
+	return err;
+
+      /* Check if it is valid.  */
+      if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
+	return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+
+      for (i = 0; i < 4; i++)
+	if (mbr.entries[i].flag & 0x7f)
+	  return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag");
+
+      /* Analyze DOS partitions.  */
+      for (index = 0; index < 4; index++)
+	{
+	  e = mbr.entries + index;
+
+	  if (!grub_pc_partition_is_empty (e->type)
+	      && end > offset + grub_le_to_cpu32 (e->start))
+	    end = offset + grub_le_to_cpu32 (e->start);
+
+	  /* If this is a GPT partition, this MBR is just a dummy.  */
+	  if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && index == 0)
+	    return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
+	}
+
+      /* Find an extended partition.  */
+      for (i = 0; i < 4; i++)
+	{
+	  e = mbr.entries + i;
+
+	  if (grub_pc_partition_is_extended (e->type))
+	    {
+	      offset = ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! ext_offset)
+		ext_offset = offset;
+
+	      break;
+	    }
+	}
+
+      /* If no extended partition, the end.  */
+      if (i == 4)
+	break;
+    }
+
+  if (end < nsectors + 1)
+    {
+      if (end <= 1)
+	return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+			   "This msdos-style partition label has no "
+			   "post-MBR gap; embedding won't be possible!");
+
+      if (nsectors > 62)
+	return grub_error (GRUB_ERR_OUT_OF_RANGE,
+			   "Your core.img is unusually large.  "
+			   "It won't fit in the embedding area.");
+
+
+      return grub_error (GRUB_ERR_OUT_OF_RANGE,
+			 "Your embedding area is unusually small.  "
+			 "core.img won't fit in it.");
+    }
+  for (i = 0; i < nsectors; i++)
+    sectors[i] = 1 + i;
+
+  return GRUB_ERR_NONE;
+}
+#endif
+
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_pc_partition_map =
@@ -306,7 +407,10 @@ static struct grub_partition_map grub_pc_partition_map =
     .name = "pc_partition_map",
     .iterate = pc_partition_map_iterate,
     .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
+    .get_name = pc_partition_map_get_name,
+#ifdef GRUB_UTIL
+    .embed = pc_partition_map_embed
+#endif
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 92c69ef..8f903c1 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -26,7 +26,6 @@
 #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/hostdisk.h>
 #include <grub/machine/boot.h>
@@ -35,8 +34,6 @@
 #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>
@@ -93,7 +90,7 @@ setup (const char *dir,
   size_t boot_size, core_size;
   grub_uint16_t core_sectors;
   grub_device_t root_dev, dest_dev;
-  const char *dest_partmap;
+  grub_partition_map_t dest_partmap;
   grub_uint8_t *boot_drive;
   grub_disk_addr_t *kernel_sector;
   grub_uint16_t *boot_drive_check;
@@ -108,52 +105,13 @@ setup (const char *dir,
   grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE;
   grub_file_t file;
   FILE *fp;
-  struct { grub_uint64_t start; grub_uint64_t end; } embed_region;
-  embed_region.start = embed_region.end = ~0UL;
+  grub_err_t err;
 
   auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset,
 			       unsigned length);
   auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset,
 			     unsigned length);
 
-  auto int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk,
-						      const grub_partition_t p);
-  int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)),
-						 const grub_partition_t p)
-    {
-      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)
-	  && embed_region.end > p->start)
-	embed_region.end = p->start;
-
-      return 0;
-    }
-
-  auto int NESTED_FUNC_ATTR find_usable_region_gpt (grub_disk_t disk,
-						    const grub_partition_t p);
-  int NESTED_FUNC_ATTR find_usable_region_gpt (grub_disk_t disk __attribute__ ((unused)),
-					       const grub_partition_t p)
-    {
-      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;
-    }
-
   void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset,
 			  unsigned length)
     {
@@ -307,6 +265,20 @@ setup (const char *dir,
   grub_util_info ("dos partition is %d, bsd partition is %d",
 		  dos_part, bsd_part);
 
+  /* Clean out the blocklists.  */
+  block = first_block;
+  while (block->len)
+    {
+      block->start = 0;
+      block->len = 0;
+      block->segment = 0;
+
+      block--;
+
+      if ((char *) block <= core_img)
+	grub_util_error ("No terminator in the core image");
+    }
+
   if (! dest_dev->disk->has_partitions)
     {
       grub_util_warn ("Attempting to install GRUB to a partitionless disk.  This is a BAD idea.");
@@ -326,7 +298,7 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)),
 					 const grub_partition_t p)
     {
-      dest_partmap = p->partmap->name;
+      dest_partmap = p->partmap;
       return 1;
     }
   dest_partmap = 0;
@@ -338,62 +310,52 @@ setup (const char *dir,
       goto unable_to_embed;
     }
 
-  grub_partition_iterate (dest_dev->disk, (strcmp (dest_partmap, "pc_partition_map") ?
-					   find_usable_region_gpt : find_usable_region_msdos));
+  if (strcmp (dest_partmap->name, "pc_partition_map") != 0
+      && strcmp (dest_partmap->name, "gpt_partition_map") != 0)
+    grub_util_error ("Can't install on '%s'", dest_partmap);
 
-  if (embed_region.end == embed_region.start)
+  if (!dest_partmap->embed)
     {
-      if (! strcmp (dest_partmap, "pc_partition_map"))
-	grub_util_warn ("This msdos-style partition label has no post-MBR gap; embedding won't be possible!");
-      else
-	grub_util_warn ("This GPT partition label has no BIOS Boot Partition; embedding won't be possible!");
+      grub_util_warn ("Partition style '%s' doesn't support embeding",
+		      dest_partmap->name);
       goto unable_to_embed;
     }
 
-  if ((unsigned long) core_sectors > embed_region.end - embed_region.start)
-    {
-      if (core_sectors > 62)
-	grub_util_warn ("Your core.img is unusually large.  It won't fit in the embedding area.");
-      else if (embed_region.end - embed_region.start < 62)
-	grub_util_warn ("Your embedding area is unusually small.  core.img won't fit in it.");
-      else
-	grub_util_warn ("Embedding area is too small for core.img.");
-      goto unable_to_embed;
-    }
-
-
-  grub_util_info ("will embed the core image at sector 0x%llx", embed_region.start);
-
-  *install_dos_part = grub_cpu_to_le32 (dos_part);
-  *install_bsd_part = grub_cpu_to_le32 (bsd_part);
-
-  /* The first blocklist contains the whole sectors.  */
-  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
-			+ (GRUB_DISK_SECTOR_SIZE >> 4));
-
-  /* Make sure that the second blocklist is a terminator.  */
-  block = first_block - 1;
-  block->start = 0;
-  block->len = 0;
-  block->segment = 0;
-
-  /* Write the core image onto the disk.  */
-  if (grub_disk_write (dest_dev->disk, embed_region.start, 0, core_size, core_img))
-    grub_util_error ("%s", grub_errmsg);
-
-  /* FIXME: can this be skipped?  */
-  *boot_drive = 0xFF;
-
-  *kernel_sector = grub_cpu_to_le64 (embed_region.start);
-
-  /* Write the boot image onto the disk.  */
-  if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE,
-		       boot_img))
-    grub_util_error ("%s", grub_errmsg);
-
+  {
+    grub_disk_addr_t sectors[core_sectors];
+    int i;
+
+    err = dest_partmap->embed (dest_dev->disk, core_sectors,
+			       GRUB_EMBED_PCBIOS, sectors);
+
+    if (err)
+      {
+	grub_util_warn ("%s", grub_errmsg);
+	grub_errno = GRUB_ERR_NONE;
+	goto unable_to_embed;
+      }
+
+    save_first_sector (sectors[0], 0, GRUB_DISK_SECTOR_SIZE);
+
+    block = first_block;
+    for (i = 1; i < core_sectors; i++)
+      save_blocklists (sectors[i], 0, GRUB_DISK_SECTOR_SIZE);
+
+    /* FIXME: can this be skipped?  */
+    *boot_drive = 0xFF;
+
+    *install_dos_part = grub_cpu_to_le32 (dos_part);
+    *install_bsd_part = grub_cpu_to_le32 (bsd_part);
+
+    /* Write the core image onto the disk.  */
+    for (i = 0; i < core_sectors; i++)
+      grub_disk_write (dest_dev->disk, sectors[i], 0,
+		       (core_size - i * GRUB_DISK_SECTOR_SIZE
+			< GRUB_DISK_SECTOR_SIZE) ? core_size
+		       - i * GRUB_DISK_SECTOR_SIZE
+		       : GRUB_DISK_SECTOR_SIZE,
+		       core_img + i * GRUB_DISK_SECTOR_SIZE);
+  }
   goto finish;
 
 unable_to_embed:
@@ -480,20 +442,6 @@ unable_to_embed:
   if (i == MAX_TRIES)
     grub_util_error ("Cannot read `%s' correctly", core_path_dev);
 
-  /* Clean out the blocklists.  */
-  block = first_block;
-  while (block->len)
-    {
-      block->start = 0;
-      block->len = 0;
-      block->segment = 0;
-
-      block--;
-
-      if ((char *) block <= core_img)
-	grub_util_error ("No terminator in the core image");
-    }
-
   /* Now read the core image to determine where the sectors are.  */
   file = grub_file_open (core_path_dev);
   if (! file)
@@ -515,8 +463,6 @@ unable_to_embed:
   free (core_path_dev);
   free (tmp_img);
 
-  *kernel_sector = grub_cpu_to_le64 (first_sector);
-
   /* FIXME: can this be skipped?  */
   *boot_drive = 0xFF;
 
@@ -532,12 +478,14 @@ unable_to_embed:
   grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp);
   fclose (fp);
 
+ finish:
+
+  *kernel_sector = grub_cpu_to_le64 (first_sector);
+
   /* Write the boot image onto the disk.  */
   if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, boot_img))
     grub_util_error ("%s", grub_errmsg);
 
- finish:
-
   /* Sync is a Good Thing.  */
   sync ();
 

^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2009-10-16 21:13 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-11 13:33 [RFT,PATCH] Move embedding to appropriate partmap files Vladimir 'phcoder' Serbinenko
2009-08-12  0:38 ` Robert Millan
2009-08-12  9:39   ` Michal Suchanek
2009-08-13 20:34     ` Robert Millan
2009-08-12 12:52   ` Vladimir 'phcoder' Serbinenko
2009-08-13 20:37     ` Robert Millan
2009-08-13 20:49       ` Seth Goldberg
2009-08-13 20:53       ` Vladimir 'phcoder' Serbinenko
2009-08-13 21:05         ` Robert Millan
2009-10-16 10:58           ` Vladimir 'phcoder' Serbinenko
2009-10-16 21:07             ` Robert Millan
2009-10-16 21:12               ` Vladimir 'phcoder' Serbinenko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.