Ok, new version of the patch here. Followed as many of your suggestions
as I could in one day: removed unused code, put verbose, unneeded
printfs under a conditional compilation DEBUG symbol, removed the .mk
file from the patch and moved everything out of the kernel and into the
drivemap module. What I didn't do is replacing the abort_on_error bit,
mostly because I don't know that to replace it with.

Cheers! (I hope I didn't leave anything out this time)

Habbit



Huge PS:

This patch may be useful, but in its current state it's no panacea. An
important feature is still unimplemented, and I have no clue as to how
to do so without breaking modularity: replacing the "boot drive number"
passed in DL to the booted OS with its mapped version. This is not
required for the system to work, but without it it's a bit tough to get
it functional. An example, booting FreeDOS in QEMU:

Disk 0x80 - 64 MiB, 1 primary partition (FAT16), some random data
Disk 0x81 - 2 GiB, 1 primary partition (FAT32), FreeDOS installation
            with MBR, VBR and system files

(note: remember that drivemap does not affect GRUB drive numbers)

Case #1: booting without drivemap
    set root=(hd1,1)
    chainloader +1
    boot
In order to just boot FreeDOS, drivemap isn't even needed, as its loader
obeys the 0x81 passed in DL by GRUB and loads KERNEL.SYS from the right
hard disk. However, the rest of the OS expects to get its system
partition as C:, which does not happen as (hd1,1) becomes D:. We get a
"enter command shell" prompt, which is not a completely borked system
(just entering d:\command.com solves it, though it doesn't load
CONFIG.SYS or AUTOEXEC.BAT) but isn't a pleasant view either.

Case #2: booting with drivemap, simplest
    drivemap (hd1) 0x80
    chainloader (hd1,1)+1
    boot
This works fine and boots FreeDOS: I don't know what the kernel gets in
DL when the root var is not set (FF, the code seems to say), but it
boots and loads the OS fine. The problem is we've lost access to our
first disk, since C: and D: are exactly the same partition (hd1,1) and
(hd0) is nowhere.

Case #3: booting with drivemap and both disks, first try
    drivemap (hd1) 0x80
    drivemap (hd0) 0x81
    chainloader (hd1,1)+1
    boot
This doesn't work, as the kernel tries to boot from 0x81 and doesn't
find KERNEL.SYS. However, as for why does it try this, I don't know,
since it seems to be getting FF in DL.

Case #4: booting with drivemap and both disks, second try
    drivemap (hd1) 0x80
    drivemap (hd0) 0x81
    set root=(hd0)
    chainloader (hd1,1)+1
    boot
This gets us what we wont: a working system with (hd1,1)=C: and
(hd0,1)=D:. The problem is that chainloader thinks that the true root is
(hd0), so it passes 0x80 in DL (good) but no pointer to the root
partition table entry as it would if root were (hd1,1). FreeDOS seems
not to use this pointer, but an OS using it would be either querying the
wrong table (if root=(hd0,1)) or no table at all (if root=(hd0) as in
this example). Obviously, the Good Thing (tm) would be to set root to
(hd1,1) and then modify the boot_drive stored by chainloader, setting it
to the mapped number. However, as I stated before, I don't know how to
do this without breaking modularity.


Index: commands/i386/pc/drivemap.c
===================================================================
RCS file: commands/i386/pc/drivemap.c
diff -N commands/i386/pc/drivemap.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ commands/i386/pc/drivemap.c	8 Jun 2008 18:09:14 -0000
@@ -0,0 +1,348 @@
+/* drivemap.c - command to manage the BIOS drive mappings.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/>.
+ */
+
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/loader.h>
+#include <grub/machine/loader.h>
+#include <grub/machine/biosdisk.h>
+
+/* Uncomment the following line to enable debugging output */
+/* #define DRIVEMAP_DEBUG */
+
+#ifdef DRIVEMAP_DEBUG
+# define DBG_PRINTF(...) grub_printf(__VA_ARGS__)
+#else
+# define DBG_PRINTF(...)
+#endif
+
+static const struct grub_arg_option options[] =
+  {
+    {"list", 'l', 0, "show the current mappings", 0, 0},
+    {"reset", 'r', 0, "reset all mappings to the default values", 0, 0},
+    {0, 0, 0, 0, 0, 0}
+  };
+
+/* ASSEMBLY SYMBOLS/VARS/FUNCS - start */
+
+/* realmode far ptr = 2 * 16b */
+extern grub_uint32_t EXPORT_VAR(grub_drivemap_int13_oldhandler);
+/* Size of the section to be copied */
+extern grub_uint16_t EXPORT_VAR(grub_drivemap_int13_size);
+
+/* NOT a typo - just need the symbol's address with &symbol */
+typedef void grub_symbol_t;
+extern grub_symbol_t EXPORT_VAR(grub_drivemap_int13_handler_base);
+extern grub_symbol_t EXPORT_VAR(grub_drivemap_int13_mapstart);
+
+void EXPORT_FUNC(grub_drivemap_int13_handler)(void);
+
+/* ASSEMBLY SYMBOLS/VARS/FUNCS - end */
+
+static grub_preboot_hookid insthandler_hook = 0;
+
+typedef struct drivemap_node
+{
+  grub_uint8_t newdrive;
+  grub_uint8_t redirto;
+  struct drivemap_node *next;
+} drivemap_node_t;
+
+static drivemap_node_t *drivemap = 0;
+static grub_err_t drivemap_install_int13_handler(void);
+
+static grub_err_t
+drivemap_set (grub_uint8_t newdrive, grub_uint8_t redirto)
+  /* Puts the specified mapping into the table, replacing an existing mapping
+   * for newdrive or adding a new one if required. */
+{
+  drivemap_node_t *mapping = 0, *search = drivemap;
+  while (search)
+    {
+      if (search->newdrive == newdrive)
+        {
+          mapping = search;
+          break;
+        }
+      search = search->next;
+    }
+
+  if (mapping)  /* There was a mapping already in place, modify it */
+    mapping->redirto = redirto;
+  else  /* Create a new mapping and add it to the head of the list */
+    {
+      mapping = grub_malloc (sizeof (drivemap_node_t));
+      if (!mapping)
+        return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate map entry");
+      mapping->newdrive = newdrive;
+      mapping->redirto = redirto;
+      mapping->next = drivemap;
+      drivemap = mapping;
+    }
+  return GRUB_ERR_NONE;
+}
+
+static void
+drivemap_remove (grub_uint8_t newdrive)
+  /* Removes the mapping for newdrive from the table. If there is no mapping,
+   * then this function behaves like a no-op on the map. */
+{
+  drivemap_node_t *mapping = 0, *search = drivemap, *previous = 0;
+  while (search)
+    {
+      if (search->newdrive == newdrive)
+        {
+          mapping = search;
+          break;
+        }
+      previous = search;
+      search = search->next;
+    }
+  if (mapping) /* Found */
+    {
+      if (previous)
+        previous->next = mapping->next;
+      else drivemap = mapping->next; /* Entry was head of list */
+      grub_free (mapping);
+    }
+}
+
+static grub_err_t parse_biosdisk (const char *name, grub_uint8_t *disknum)
+{
+  if (!name) return GRUB_ERR_BAD_ARGUMENT;
+  if (name[0] == '(')
+    name++; /* Skip the first ( in (hd0) - disk_open wants just the name! */
+  grub_disk_t disk = grub_disk_open (name);
+  if (!disk)
+    return GRUB_ERR_UNKNOWN_DEVICE;
+  else
+    {
+      enum grub_disk_dev_id id = disk->dev->id;
+      if (disknum)
+        *disknum = disk->id;   /* Only valid, of course if it's a biosdisk */
+      grub_disk_close (disk);
+      return (GRUB_DISK_DEVICE_BIOSDISK_ID != id) ?
+          GRUB_ERR_BAD_DEVICE : GRUB_ERR_NONE;
+    }
+}
+
+static grub_err_t revparse_biosdisk(const grub_uint8_t dnum, const char **output)
+{
+  grub_err_t retval = GRUB_ERR_UNKNOWN_DEVICE;
+  auto int find (const char *name);
+  int find (const char *name)
+  {
+    grub_disk_t disk = grub_disk_open (name);
+    if (!disk)
+      return 0;
+    else
+      {
+        int found = 0;
+        if (dnum == disk->id && GRUB_DISK_DEVICE_BIOSDISK_ID == disk->dev->id)
+          {
+            found = 1;
+            *output = name;
+            retval = GRUB_ERR_NONE;
+          }
+        grub_disk_close (disk);
+        return found;
+      }
+  }
+
+  grub_disk_dev_iterate (&find);
+  return retval;
+}
+
+static grub_err_t
+grub_cmd_drivemap (struct grub_arg_list *state, int argc, char **args)
+{
+  if (state[0].set) /* Show: list mappings */
+    {
+      if (!drivemap)
+        grub_printf ("No drives have been remapped");
+      else
+        {
+          grub_printf ("Showing only remapped drives. Drives that have had "
+                       "their slot assigned to another one and have not been "
+                       "themselves remapped will become inaccessible through "
+                       "the BIOS routines to the booted OS.\n\n");
+          grub_printf ("Mapped\tGRUB\n");
+          drivemap_node_t *curnode = drivemap;
+          while (curnode)
+            {
+              const char *dname = 0;
+              grub_err_t err = revparse_biosdisk (curnode->redirto, &dname);
+              if (err != GRUB_ERR_NONE)
+                return grub_error (err, "invalid mapping: non-existent disk or"
+                                        "not managed by the BIOS");
+              grub_printf("0x%02x\t%4s\n", curnode->newdrive, dname);
+              curnode = curnode->next;
+            }
+        }
+    }
+  else if (state[1].set) /* Reset: just delete all mappings */
+    {
+      if (drivemap)
+        {
+          drivemap_node_t *curnode = drivemap, *prevnode = 0;
+          while (curnode)
+            {
+              prevnode = curnode;
+              curnode = curnode->next;
+              grub_free (prevnode);
+            }
+          drivemap = 0;
+        }
+    }
+  else
+    {
+      if (argc != 2)
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments required");
+      grub_uint8_t mapfrom = 0;
+      grub_err_t err = parse_biosdisk (args[0], &mapfrom);
+      if (err != GRUB_ERR_NONE)
+        return grub_error (err, "invalid disk or not managed by the BIOS");
+
+      grub_errno = GRUB_ERR_NONE;
+      unsigned long mapto = grub_strtoul (args[1], 0, 0);
+      if (grub_errno != GRUB_ERR_NONE)
+        return grub_error (grub_errno,
+                          "BIOS disk number must be between 0 and 255");
+      else if (mapto == mapfrom)  /* Reset to default */      
+        {
+          DBG_PRINTF ("Removing the mapping for %s (%02x)", args[0], mapfrom);
+          drivemap_remove (mapfrom);
+        }
+      else  /* Map */
+        {
+          DBG_PRINTF ("Mapping %s (%02x) to %02x\n", args[0], mapfrom, mapto);
+          return drivemap_set ((grub_uint8_t)mapto, mapfrom);
+        }
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+typedef struct __attribute__ ((packed)) int13map_node
+{
+  grub_uint8_t disknum;
+  grub_uint8_t mapto;
+} int13map_node_t;
+
+/* The min amount of mem that must remain free after installing the handler.
+ * 32 KiB is just above 0x7C00-0x7E00, where the bootsector is loaded.  */
+#define MIN_FREE_MEM_KB 32
+#define INT13H_OFFSET(x) ( ((grub_uint8_t*)(x)) - ((grub_uint8_t*)&grub_drivemap_int13_handler_base) )
+#define INT13H_REBASE(x) ( (void*) (((grub_uint8_t*)handler_base) + (x)) )
+#define INT13H_TONEWADDR(x) INT13H_REBASE( INT13H_OFFSET( x ) )
+/* Int13h handler installer - reserves conventional memory for the handler,
+ * copies it over and sets the IVT entry for int13h.
+ * This code rests on the assumption that GRUB does not activate any kind of
+ * memory mapping, since it accesses realmode structures by their absolute
+ * addresses, like the IVT at 0 or the BDA at 0x400 */
+static grub_err_t drivemap_install_int13_handler(void)
+{
+  grub_size_t entries = 0;
+  drivemap_node_t *curentry = drivemap;
+  while (curentry)  /* Count entries to prepare a contiguous map block */
+    {
+      entries++;
+      curentry = curentry->next;
+    }
+  if (0 == entries)
+    {
+      DBG_PRINTF ("drivemap: No drives remapped, int13h handler not installed");
+      return GRUB_ERR_NONE;  /* No need to install the int13h handler */
+    }
+  else
+    {
+      DBG_PRINTF ("drivemap: Installing int13h handler...\n");
+      grub_uint32_t *ivtslot = (grub_uint32_t*)0x0000004c;
+      
+      /* Save the pointer to the old int13h handler */    
+      grub_drivemap_int13_oldhandler = *ivtslot;
+      DBG_PRINTF ("Old int13 handler at %04x:%04x\n",
+                  (grub_drivemap_int13_oldhandler >> 16) & 0x0ffff,
+                  grub_drivemap_int13_oldhandler & 0x0ffff);
+
+      /* Reserve a section of conventional memory as "BIOS memory" for handler:
+       * BDA offset 0x13 contains the top of such memory */
+      grub_uint16_t *bpaMemInKb = (grub_uint16_t*)0x00000413;
+      DBG_PRINTF ("Top of conventional memory: %u KiB\n", *bpaMemInKb);
+      grub_size_t totalSize = grub_drivemap_int13_size
+                            + (entries + 1) * sizeof(int13map_node_t);
+      grub_uint16_t payloadSizeKb = (totalSize >> 10) +
+                                    (((totalSize % 1024) == 0) ? 0 : 1);
+      if ((*bpaMemInKb - payloadSizeKb) < MIN_FREE_MEM_KB)
+        return grub_error (GRUB_ERR_OUT_OF_MEMORY, "refusing to install int13 handler, not enough free memory after");
+      DBG_PRINTF ("Payload is %u b long, reserving %u Kb\n", totalSize, payloadSizeKb);
+      *bpaMemInKb -= payloadSizeKb;
+
+      /* Copy int13h handler chunk to reserved area */
+      grub_uint8_t *handler_base = (grub_uint8_t*)(*bpaMemInKb << 10);
+      DBG_PRINTF ("Copying int13 handler to: %p\n", handler_base);
+      grub_memcpy (handler_base, &grub_drivemap_int13_handler_base, grub_drivemap_int13_size);
+
+      /* Copy the mappings to the reserved area */
+      curentry = drivemap;
+      grub_size_t i;
+      int13map_node_t *handler_map = (int13map_node_t*) INT13H_TONEWADDR(&grub_drivemap_int13_mapstart);
+      DBG_PRINTF ("Target map at %p, copying mappings...\n", handler_map);
+      for (i = 0; i < entries && curentry; i++, curentry = curentry->next)
+        {
+          handler_map[i].disknum = curentry->newdrive;
+          handler_map[i].mapto = curentry->redirto;
+          DBG_PRINTF ("\t#%d: 0x%02x <- 0x%02x\n", i, handler_map[i].disknum, handler_map[i].mapto);
+        }
+      /* Signal end-of-map */
+      handler_map[i].disknum = 0;
+      handler_map[i].mapto = 0;
+      DBG_PRINTF ("\t#%d: 0x%02x <- 0x%02x (end)\n", i, handler_map[i].disknum, handler_map[i].mapto);
+
+      /* Install our function as the int13h handler in the IVT */
+      grub_uint32_t ivtentry = ((grub_uint32_t)handler_base) << 12; /* Segment address */
+      ivtentry |= (grub_uint16_t) INT13H_OFFSET(grub_drivemap_int13_handler);
+      DBG_PRINTF ("New int13 handler IVT pointer: %04x:%04x\n",
+                  (ivtentry >> 16) & 0x0ffff, ivtentry & 0x0ffff);
+      *ivtslot = ivtentry;
+      
+      return GRUB_ERR_NONE;
+    }
+}
+#undef INT13H_TONEWADDR
+#undef INT13H_REBASE
+#undef INT13H_OFFSET
+
+GRUB_MOD_INIT(drivemap)
+{
+  (void)mod;			/* To stop warning. */
+  grub_register_command ("drivemap", grub_cmd_drivemap, GRUB_COMMAND_FLAG_BOTH,
+			 "drivemap -s | -r | (hdX) newdrivenum", "Manage the BIOS drive mappings", options);
+  insthandler_hook = grub_loader_register_preboot (&drivemap_install_int13_handler, 1);
+}
+
+GRUB_MOD_FINI(drivemap)
+{
+  grub_loader_unregister_preboot (insthandler_hook);
+  insthandler_hook = 0;
+  grub_unregister_command ("drivemap");
+}
Index: commands/i386/pc/drivemap_int13h.S
===================================================================
RCS file: commands/i386/pc/drivemap_int13h.S
diff -N commands/i386/pc/drivemap_int13h.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ commands/i386/pc/drivemap_int13h.S	8 Jun 2008 18:09:14 -0000
@@ -0,0 +1,128 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,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/>.
+ */
+
+
+/*
+ * Note: These functions defined in this file may be called from C.
+ *       Be careful of that you must not modify some registers. Quote
+ *       from gcc-2.95.2/gcc/config/i386/i386.h:
+
+   1 for registers not available across function calls.
+   These must include the FIXED_REGISTERS and also any
+   registers that can be used without being saved.
+   The latter must include the registers where values are returned
+   and the register where structure-value addresses are passed.
+   Aside from that, you can include as many other registers as you like.
+
+  ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
+{  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1 }
+ */
+
+/*
+ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
+ *       So the first three arguments are passed in %eax, %edx, and %ecx,
+ *       respectively, and if a function has a fixed number of arguments
+ *       and the number if greater than three, the function must return
+ *       with "ret $N" where N is ((the number of arguments) - 3) * 4.
+ */
+
+/*
+ *  This is the area for all of the special variables.
+ */
+
+#include <grub/symbol.h>
+
+#define GRUB_DRIVEMAP_INT13H_OFFSET(x) ((x) - grub_drivemap_int13_handler_base)
+
+/* Copy starts here. When deployed, this label must be segment-aligned */
+VARIABLE(grub_drivemap_int13_handler_base)  
+
+VARIABLE(grub_drivemap_int13_oldhandler)
+  .word 0xdead, 0xbeef
+/* Drivemap module - INT 13h handler - BIOS HD map */
+/* We need to use relative addressing, and with CS to top it all, since we
+ * must make as few changes to the registers as possible. Pity we're not on
+ * amd64: rIP-relative addressing would make life easier here.
+ */
+.code16
+FUNCTION(grub_drivemap_int13_handler)
+  push %bp
+  mov %sp, %bp
+  push %ax  /* We'll need it later to determine the used BIOS function */
+
+  /* Map the drive number (always in DL?) */
+  push %ax
+  push %bx
+  push %si
+  mov $GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_mapstart), %bx
+  xor %si, %si
+1:movw %cs:(%bx,%si), %ax
+  cmp %ah, %al
+  jz 3f /* DRV=DST => map end - drive not remapped, leave DL as-is */
+  cmp %dl, %al
+  jz 2f /* Found - drive remapped, modify DL */
+  add $2, %si
+  jmp 1b /* Not found, but more remaining, loop  */
+2:mov %ah, %dl
+3:pop %si
+  pop %bx
+  xchgw %ax, -4(%bp) /* Recover the old AX and save the map entry for later */
+  
+  push %bp  
+  /* Simulate interrupt call: push flags and do a far call in order to set
+   * the stack the way the old handler expects it so that its iret works */
+  push 6(%bp)
+  movw (%bp), %bp  /* Restore the caller BP (is this needed and/or sensible?) */
+  lcall *%cs:GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_oldhandler)
+  pop %bp /* The pushed flags were removed by iret */
+  /* Set the saved flags to what the int13h handler returned */
+  push %ax
+  pushf
+  pop %ax
+  movw %ax, 6(%bp)
+  pop %ax
+
+  /* Reverse map any returned drive number if the data returned includes it.
+   * The only func that does this seems to be origAH = 0x08, but many BIOS
+   * refs say retDL = # of drives connected. However, the GRUB Legacy code
+   * treats this as the _drive number_ and "undoes" the remapping. Thus,
+   * this section has been disabled for testing if it's required */
+#  cmpb $0x08, -1(%bp) /* Caller's AH */
+#  jne 4f
+#  push %es
+#  pushal
+#  mov $0, %di
+#  mov $0xb800, %bx
+#  mov %bx, %es
+#  xchgw %ax, -4(%bp) /* Map entry used */
+#  cmp %ah, %al  /* DRV=DST => drive not remapped */
+#  je 4f
+#  mov %ah, %dl  /* Undo remap */
+
+4:mov %bp, %sp
+  pop %bp
+  iret
+/* This label MUST be at the end of the copied block, since the installer code
+ * reserves additional space for mappings at runtime and copies them over it */
+.align 2
+VARIABLE(grub_drivemap_int13_mapstart)
+  .space 0
+.code32 /* Copy stops here */
+VARIABLE(grub_drivemap_int13_size)
+  .word GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_size)
+#undef GRUB_DRIVEMAP_INT13H_OFFSET
Index: conf/i386-pc.rmk
===================================================================
RCS file: /sources/grub/grub2/conf/i386-pc.rmk,v
retrieving revision 1.119
diff -u -p -r1.119 i386-pc.rmk
--- conf/i386-pc.rmk	30 May 2008 04:20:47 -0000	1.119
+++ conf/i386-pc.rmk	8 Jun 2008 18:09:22 -0000
@@ -152,7 +152,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod
 	vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
 	videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod	\
 	ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \
-	aout.mod _bsd.mod bsd.mod
+	aout.mod _bsd.mod bsd.mod drivemap.mod
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -319,4 +319,11 @@ bsd_mod_SOURCES = loader/i386/bsd_normal
 bsd_mod_CFLAGS = $(COMMON_CFLAGS)
 bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For drivemap.mod.
+drivemap_mod_SOURCES = commands/i386/pc/drivemap.c \
+                       commands/i386/pc/drivemap_int13h.S
+drivemap_mod_ASFLAGS = $(COMMON_ASFLAGS)
+drivemap_mod_CFLAGS = $(COMMON_CFLAGS)
+drivemap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 include $(srcdir)/conf/common.mk
Index: include/grub/loader.h
===================================================================
RCS file: /sources/grub/grub2/include/grub/loader.h,v
retrieving revision 1.9
diff -u -p -r1.9 loader.h
--- include/grub/loader.h	21 Jul 2007 23:32:22 -0000	1.9
+++ include/grub/loader.h	8 Jun 2008 18:09:22 -0000
@@ -37,6 +37,19 @@ void EXPORT_FUNC(grub_loader_set) (grub_
 /* Unset current loader, if any.  */
 void EXPORT_FUNC(grub_loader_unset) (void);
 
+typedef struct hooklist_node *grub_preboot_hookid;
+
+/* Register a function to be called before the boot hook. Returns an id that
+   can be later used to unregister the preboot (i.e. if module unloaded). If
+   abort_on_error is set, the boot sequence will abort if any of the registered
+   functions return anything else than GRUB_ERR_NONE */
+grub_preboot_hookid EXPORT_FUNC(grub_loader_register_preboot)
+           (grub_err_t (*hook) (void), int abort_on_error); 
+
+/* Unregister a preboot hook by the id returned by loader_register_preboot.
+   This functions becomes a no-op if no such function is registered */
+void EXPORT_FUNC(grub_loader_unregister_preboot) (grub_preboot_hookid id);
+
 /* Call the boot hook in current loader. This may or may not return,
    depending on the setting by grub_loader_set.  */
 grub_err_t EXPORT_FUNC(grub_loader_boot) (void);
Index: kern/loader.c
===================================================================
RCS file: /sources/grub/grub2/kern/loader.c,v
retrieving revision 1.9
diff -u -p -r1.9 loader.c
--- kern/loader.c	21 Jul 2007 23:32:26 -0000	1.9
+++ kern/loader.c	8 Jun 2008 18:09:22 -0000
@@ -61,11 +61,78 @@ grub_loader_unset(void)
   grub_loader_loaded = 0;
 }
 
+struct hooklist_node
+{
+  grub_err_t (*hook) (void);
+  int abort_on_error;
+  struct hooklist_node *next;
+};
+
+static struct hooklist_node *preboot_hooks = 0;
+
+grub_preboot_hookid
+grub_loader_register_preboot(grub_err_t (*hook) (void), int abort_on_error)
+{
+  if (0 == hook)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "preboot hoook must not be null");
+      return 0;
+    }
+  grub_preboot_hookid newentry = grub_malloc (sizeof (struct hooklist_node));
+  if (!newentry)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot alloc a hookinfo structure");
+      return 0;
+    }
+  else
+    {
+      newentry->hook = hook;
+      newentry->abort_on_error = abort_on_error;
+      newentry->next = preboot_hooks;
+      preboot_hooks = newentry;
+      return newentry;
+    }
+}
+
+void
+grub_loader_unregister_preboot(grub_preboot_hookid id)
+{
+  if (0 == id)
+    return;
+  grub_preboot_hookid entry = 0, search = preboot_hooks, previous = 0;
+  while (search)
+    {
+      if (search == id)
+        {
+          entry = search;
+          break;
+        }
+      previous = search;
+      search = search->next;
+    }
+  if (entry) /* Found */
+    {
+      if (previous)
+        previous->next = entry->next;
+      else preboot_hooks = entry->next; /* Entry was head of list */
+      grub_free (entry);
+    }
+}
+
 grub_err_t
 grub_loader_boot (void)
 {
   if (! grub_loader_loaded)
     return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel");
+  
+  grub_preboot_hookid entry = preboot_hooks;
+  while (entry)
+    {
+      grub_err_t retVal = entry->hook();
+      if (retVal != GRUB_ERR_NONE && entry->abort_on_error)
+        return retVal;
+      entry = entry->next;
+    }
 
   if (grub_loader_noreturn)
     grub_machine_fini ();

Attachment: signature.asc
Description: Esta parte del mensaje está firmada digitalmente

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to