All of lore.kernel.org
 help / color / mirror / Atom feed
From: Colin Watson <cjwatson@ubuntu.com>
To: grub-devel@gnu.org
Subject: Re: Which partitioning schemes should be supported by GRUB?
Date: Tue, 15 Jun 2010 12:21:11 +0100	[thread overview]
Message-ID: <20100615112111.GW21862@riva.ucam.org> (raw)
In-Reply-To: <4C166306.2030405@gmail.com>

On Mon, Jun 14, 2010 at 07:12:38PM +0200, Grégoire Sutre wrote:
> On 06/14/2010 18:43, Colin Watson wrote:
>> Do you have any suggestions on how to deal with that?  I'm not familiar
>> with multiboot and need guidance.
>
> A possible solution would be to use the multiboot-command line.  AFAIK,
> the boot_device field of the multiboot information structure is supposed
> to pass this kind of partition information, but you cannot specify the
> partmaps in this field, hence its interpretation is ambiguous.

That would potentially allow a user to override things, but doesn't help
with users who don't change their configuration.  Unless the user
explicitly configures things, boot_device is all we've got.

Thus, I guess we end up with a two-part fix:

  1) Honour key=value pairs in the multiboot command line when booting
     GRUB itself as a multiboot image.  These would simply become
     environment variables.  Presumably this goes in grub_machine_init,
     by analogy with kern/ieee1275/init.c.  This allows users to
     override the prefix on the command line as if they had changed the
     image itself.

  2) If multiboot_trampoline needs to change install_dos_part or
     install_bsd_part based on the value of boot_device in the MBI, then
     we know that the drive/partition part of prefix (which was
     calculated in the same way as install_dos_part and install_bsd_part
     when grub-setup was run) is now invalid and should be ignored.
     This fact needs to be passed on to make_install_device.

Something like this?  I'm afraid I have no idea how to test this (GRUB's
multiboot command doesn't seem to accept command-line arguments?), not
to mention that this is the first time I've been anywhere near most of
this code.  I would greatly appreciate advice and review.

2010-06-15  Colin Watson  <cjwatson@ubuntu.com>

	Fix i386-pc prefix handling with nested partitions (Debian bug
	#585068).

	* include/grub/i386/pc/kernel.h (grub_multiboot_change_prefix): New
	declaration.
	* kern/i386/pc/startup.S (multiboot_entry): Save a pointer to the
	MBI in startup_multiboot_info.
	(multiboot_trampoline): If the new partition numbers differ from the
	previous ones, then set grub_multiboot_change_prefix.
	(grub_multiboot_change_prefix): New definition.
	* kern/i386/pc/init.c (make_install_device): Invalidate any
	drive/partition part of the prefix if grub_multiboot_change_prefix
	is set.  After that, if the prefix starts with "(,", fill the boot
	drive in between those two characters, but expect that a full
	partition specification including partition map names will follow.
	(grub_parse_multiboot_cmdline): New function.
	(grub_machine_init): If we have an MBI, copy it, then call
	grub_parse_multiboot_cmdline.
	* util/i386/pc/grub-setup.c (setup): Unless an explicit prefix was
	specified, write a prefix without the drive name but including a
	full partition specification.

=== modified file 'include/grub/i386/pc/kernel.h'
--- include/grub/i386/pc/kernel.h	2010-04-26 19:11:16 +0000
+++ include/grub/i386/pc/kernel.h	2010-06-15 11:02:34 +0000
@@ -44,6 +44,10 @@ extern grub_int32_t grub_install_bsd_par
 /* The boot BIOS drive number.  */
 extern grub_uint8_t EXPORT_VAR(grub_boot_drive);
 
+/* Set if multiboot changed the partition numbers, so grub_prefix is now
+   invalid.  */
+extern grub_uint8_t grub_multiboot_change_prefix;
+
 #endif /* ! ASM_FILE */
 
 #endif /* ! KERNEL_MACHINE_HEADER */

=== modified file 'kern/i386/pc/init.c'
--- kern/i386/pc/init.c	2010-05-21 18:08:48 +0000
+++ kern/i386/pc/init.c	2010-06-15 11:06:20 +0000
@@ -32,6 +32,7 @@
 #include <grub/cache.h>
 #include <grub/time.h>
 #include <grub/cpu/tsc.h>
+#include <grub/multiboot.h>
 
 struct mem_region
 {
@@ -47,12 +48,29 @@ static int num_regions;
 grub_addr_t grub_os_area_addr;
 grub_size_t grub_os_area_size;
 
+/* A pointer to the MBI in its initial location.  */
+struct multiboot_info *startup_multiboot_info = NULL;
+
+/* The MBI has to be copied to our BSS so that it won't be
+   overwritten.  This is its final location.  */
+static struct multiboot_info kern_multiboot_info;
+
 static char *
 make_install_device (void)
 {
   /* XXX: This should be enough.  */
   char dev[100], *ptr = dev;
 
+  if (grub_prefix[0] == '(' && grub_multiboot_change_prefix)
+    {
+      /* The multiboot information invalidated our hardcoded prefix because
+         partition numbers differed.  Eliminate the drive/partition part of
+         the prefix, if possible.  */
+      char *ket = grub_strchr (grub_prefix, ')');
+      if (ket)
+	grub_memmove (grub_prefix, ket + 1, grub_strlen (ket));
+    }
+
   if (grub_prefix[0] != '(')
     {
       /* No hardcoded root partition - make it from the boot drive and the
@@ -83,6 +101,14 @@ make_install_device (void)
       grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix);
       grub_strcpy (grub_prefix, dev);
     }
+  else if (grub_prefix[1] == ',' || grub_prefix[1] == ')')
+    {
+      /* We have a prefix, but still need to fill in the boot drive.  */
+      grub_snprintf (dev, sizeof (dev),
+		     "(%cd%u%s", (grub_boot_drive & 0x80) ? 'h' : 'f',
+		     grub_boot_drive & 0x7f, grub_prefix + 1);
+      grub_strcpy (grub_prefix, dev);
+    }
 
   return grub_prefix;
 }
@@ -134,6 +160,45 @@ compact_mem_regions (void)
       }
 }
 
+static void
+grub_parse_multiboot_cmdline (void)
+{
+  char *cmdline;
+  char *p;
+
+  if (! (kern_multiboot_info.flags & MULTIBOOT_INFO_CMDLINE))
+    return;
+
+  p = cmdline = grub_strdup ((char *) kern_multiboot_info.cmdline);
+
+  while (*p)
+    {
+      char *command = p;
+      char *end;
+      char *val;
+
+      end = grub_strchr (command, ' ');
+      if (end)
+	{
+	  *end = '\0';
+	  p = end + 1;
+	  while (*p == ' ')
+	    ++p;
+	}
+
+      /* Process command.  */
+      val = grub_strchr (command, '=');
+      if (val)
+	{
+	  *val = '\0';
+	  grub_env_set (command, val + 1);
+
+	  if (grub_strcmp (command, "prefix") == 0)
+	    grub_multiboot_change_prefix = 0;
+	}
+    }
+}
+
 void
 grub_machine_init (void)
 {
@@ -214,6 +279,15 @@ grub_machine_init (void)
   if (! grub_os_area_addr)
     grub_fatal ("no upper memory");
 
+  if (startup_multiboot_info)
+    {
+      /* Move MBI to a safe place.  */
+      grub_memmove (&kern_multiboot_info, startup_multiboot_info,
+		    sizeof (struct multiboot_info));
+
+      grub_parse_multiboot_cmdline ();
+    }
+
   grub_tsc_init ();
 }
 

=== modified file 'kern/i386/pc/startup.S'
--- kern/i386/pc/startup.S	2010-04-05 13:59:32 +0000
+++ kern/i386/pc/startup.S	2010-06-15 11:02:19 +0000
@@ -142,6 +142,8 @@ multiboot_header:
 
 multiboot_entry:
 	.code32
+	movl	%ebx, EXT_C(startup_multiboot_info)
+
 	/* obtain the boot device */
 	movl	12(%ebx), %edx
 
@@ -161,20 +163,38 @@ multiboot_entry:
 	jmp	*%eax
 
 multiboot_trampoline:
+	/* remember the original boot information */
+	movl	EXT_C(grub_install_dos_part), %eax
+	orl	%eax, %eax
+	jns	1f
+	movb	$0xFF, %al
+1:
+	movl	EXT_C(grub_install_bsd_part), %ebx
+	orl	%ebx, %ebx
+	jns	2f
+	movb	$0xFF, %bl
+2:
+	movb	%al, %bh
+
 	/* fill the boot information */
 	movl	%edx, %eax
 	shrl	$8, %eax
+	cmpw	%ax, %bx
+	je	3f
+	/* doesn't match the original */
+	movb	$1, EXT_C(grub_multiboot_change_prefix)
+3:
 	xorl	%ebx, %ebx
 	cmpb	$0xFF, %ah
-	je	1f
+	je	4f
 	movb	%ah, %bl
 	movl	%ebx, EXT_C(grub_install_dos_part)
-1:
+4:
 	cmpb	$0xFF, %al
-	je	2f
+	je	5f
 	movb	%al, %bl
 	movl	%ebx, EXT_C(grub_install_bsd_part)
-2:
+5:
 	shrl	$24, %edx
         movb    $0xFF, %dh
 	/* enter the usual booting */
@@ -285,6 +305,8 @@ LOCAL (codestart):
 
 VARIABLE(grub_boot_drive)
 	.byte	0
+VARIABLE(grub_multiboot_change_prefix)
+	.byte	0
 
 	.p2align	2	/* force 4-byte alignment */
 

=== modified file 'util/i386/pc/grub-setup.c'
--- util/i386/pc/grub-setup.c	2010-06-11 20:31:16 +0000
+++ util/i386/pc/grub-setup.c	2010-06-14 16:29:54 +0000
@@ -99,6 +99,7 @@ setup (const char *dir,
   struct grub_boot_blocklist *first_block, *block;
   grub_int32_t *install_dos_part, *install_bsd_part;
   grub_int32_t dos_part, bsd_part;
+  char *prefix;
   char *tmp_img;
   int i;
   grub_disk_addr_t first_sector;
@@ -230,6 +231,8 @@ setup (const char *dir,
 				       + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART);
   install_bsd_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE
 				       + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART);
+  prefix = (char *) (core_img + GRUB_DISK_SECTOR_SIZE +
+		     GRUB_KERNEL_MACHINE_PREFIX);
 
   /* Open the root device and the destination device.  */
   root_dev = grub_device_open (root);
@@ -305,6 +308,18 @@ setup (const char *dir,
 	      dos_part = root_dev->disk->partition->number;
  	      bsd_part = -1;
  	    }
+
+	  if (prefix[0] != '(')
+	    {
+	      char *root_part_name, *new_prefix;
+
+	      root_part_name =
+		grub_partition_get_name (root_dev->disk->partition);
+	      new_prefix = xasprintf ("(,%s)%s", root_part_name, prefix);
+	      strcpy (prefix, new_prefix);
+	      free (new_prefix);
+	      free (root_part_name);
+	    }
 	}
       else
 	dos_part = bsd_part = -1;

Thanks,

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


  reply	other threads:[~2010-06-15 11:21 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-06 18:02 Which partitioning schemes should be supported by GRUB? Grégoire Sutre
2010-06-07 20:46 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-06-09 22:45   ` Grégoire Sutre
2010-06-09 23:03     ` C. P. Ghost
2010-06-12 16:32   ` Grégoire Sutre
2010-06-12 17:26     ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-06-13 16:16       ` Grégoire Sutre
2010-06-14 11:37         ` Colin Watson
2010-06-14 13:07           ` richardvoigt
2010-06-14 13:25             ` Colin Watson
2010-06-14 15:02               ` Colin Watson
2010-06-14 15:58                 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-06-14 16:43                   ` Colin Watson
2010-06-14 16:55                     ` Seth Goldberg
2010-06-14 17:33                       ` Colin Watson
2010-06-14 17:12                     ` Grégoire Sutre
2010-06-15 11:21                       ` Colin Watson [this message]
2010-06-15 21:07                         ` Grégoire Sutre
2010-06-16 13:01                           ` Colin Watson
2010-06-16 23:31                             ` Grégoire Sutre
2010-06-17  0:47                         ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-06-17 11:29                           ` Colin Watson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100615112111.GW21862@riva.ucam.org \
    --to=cjwatson@ubuntu.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.