In this reply-to-myself hoping to keep the thread continuity, I put
forth the new "version 7" of the patch with the following changes:

  - A new switch -s/--swap has been implemented, so that running
"drivemap -s hd0 hd1" is equivalent to issuing the command twice with
the arguments normal, then reversed. There is one exception: if the
first mapping fails or the second drive does not exist, no mapping is
performed, whereas hand-performing the swap would have successfully
assigned BIOS disk #1 to hd0, then failed to assign bd#0 to non-existent
hd1.
  - Raw BIOS disk number parsing has been removed: the syntax "drivemap
hd1 0x80" is no longer legal. However, one can still map non-existent
BIOS disk numbers with "drivemap hd0 hd42" for example and (more
controversially, maybe I'll add a check eventually) assign a floppy to
an HD and back.

The only file changed from the last patch ("version 6") is drivemap.c:
the rest of it should be the same, so if anyone was reviewing it you can
seamlessly "jump" to version 7. In particular, the functional changes
are localized in the drivemap_cmd function proper, and there are
cosmetic changes elsewhere (spurious tabs removed, etc.).

-Habbit
Index: commands/i386/pc/drivemap.c
===================================================================
--- commands/i386/pc/drivemap.c	(revisión: 0)
+++ commands/i386/pc/drivemap.c	(revisión: 0)
@@ -0,0 +1,433 @@
+/* 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/machine/drivemap.h>
+#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>
+
+#define MODNAME "drivemap"
+
+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},
+  {"swap", 's', 0, "perform both direct and reverse mappings", 0, 0},
+  {0, 0, 0, 0, 0, 0}
+};
+
+enum opt_idxs {
+  OPTIDX_LIST = 0,
+  OPTIDX_RESET,
+  OPTIDX_SWAP,
+};
+
+typedef struct drivemap_node
+{
+  grub_uint8_t newdrive;
+  grub_uint8_t redirto;
+  struct drivemap_node *next;
+} drivemap_node_t;
+
+static drivemap_node_t *drivemap;
+static grub_preboot_hookid insthandler_hook;
+static grub_err_t install_int13_handler (void);
+
+/* Puts the specified mapping into the table, replacing an existing mapping
+   for newdrive or adding a new one if required.  */
+static grub_err_t
+drivemap_set (grub_uint8_t newdrive, grub_uint8_t redirto)
+{
+  drivemap_node_t *mapping = 0;
+  drivemap_node_t *search = drivemap;
+  while (search)
+    {
+      if (search->newdrive == newdrive)
+        {
+          mapping = search;
+          break;
+        }
+      search = search->next;
+    }
+
+  
+  /* Check for pre-existing mappings to modify before creating a new one.  */
+  if (mapping)
+    mapping->redirto = redirto;
+  else 
+    {
+      mapping = grub_malloc (sizeof (drivemap_node_t));
+      if (!mapping)
+        return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                           "cannot allocate map entry, not enough memory");
+      mapping->newdrive = newdrive;
+      mapping->redirto = redirto;
+      mapping->next = drivemap;
+      drivemap = mapping;
+    }
+  return GRUB_ERR_NONE;
+}
+
+/* Removes the mapping for newdrive from the table.  If there is no mapping,
+   then this function behaves like a no-op on the map.  */
+static void
+drivemap_remove (grub_uint8_t newdrive)
+{
+  drivemap_node_t *mapping = 0;
+  drivemap_node_t *search = drivemap;
+  drivemap_node_t *previous = 0;
+
+  while (search)
+    {
+      if (search->newdrive == newdrive)
+        {
+          mapping = search;
+          break;
+        }
+      previous = search;
+      search = search->next;
+    }
+
+  if (mapping)
+    {
+      if (previous)
+        previous->next = mapping->next;
+      else /* Entry was head of list.  */
+        drivemap = mapping->next;
+      grub_free (mapping);
+    }
+}
+
+/* Given a device name, resolves its BIOS disk number and stores it in the
+   passed location, which should only be trusted if ERR_NONE is returned.  */
+static grub_err_t
+parse_biosdisk (const char *name, grub_uint8_t *disknum)
+{
+  grub_disk_t disk;
+  if (!name || *name == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name empty");
+  /* Skip the first ( in (hd0) - disk_open wants just the name.  */
+  if (*name == '(')
+    name++;
+  
+  disk = grub_disk_open (name);
+  if (!disk)
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown device \"%s\"", name);
+  else
+    {
+      const enum grub_disk_dev_id id = disk->dev->id;
+      /* The following assignment is only sound if the device is indeed a
+         biosdisk.  The caller must check the return value.  */
+      if (disknum)
+        *disknum = disk->id;
+      grub_disk_close (disk);
+      if (id == GRUB_DISK_DEVICE_BIOSDISK_ID)
+        return GRUB_ERR_NONE;
+      else return grub_error (GRUB_ERR_BAD_DEVICE, "%s is not a BIOS disk", name);
+    }
+}
+
+/* Given a BIOS disk number, returns its GRUB device name if it exists.
+   For nonexisting BIOS disk numbers, this function returns
+   GRUB_ERR_UNKNOWN_DEVICE.  */
+static grub_err_t
+revparse_biosdisk(const grub_uint8_t dnum, const char **output)
+{
+  int found = 0;
+  auto int find (const char *name);
+  int find (const char *name)
+  {
+    const grub_disk_t disk = grub_disk_open (name);
+    if (!disk)
+      return 0;
+    else
+      {
+        if (disk->id == dnum && disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID)
+          {
+            found = 1;
+            if (output)
+              *output = name;
+          }
+        grub_disk_close (disk);
+        return found;
+      }
+  }
+
+  grub_disk_dev_iterate (find);
+  if (found)
+    return GRUB_ERR_NONE;
+  else
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "BIOS disk %02x not found", dnum);
+}
+
+/* Given a GRUB-like device name and a convenient location, stores the related
+   BIOS disk number.  Accepts devices like \((f|h)dN\), with 0 <= N < 128.  */
+static grub_err_t
+tryparse_diskstring (const char *str, grub_uint8_t *output)
+{
+  if (!str || *str == 0)
+    goto fail;
+  /* Skip opening paren in order to allow both (hd0) and hd0.  */
+  if (*str == '(')
+    str++;
+  if ((str[0] == 'f' || str[0] == 'h') && str[1] == 'd')
+    {
+      grub_uint8_t bios_num = (str[0] == 'h')? 0x80 : 0x00;
+      grub_errno = GRUB_ERR_NONE;
+      unsigned long drivenum = grub_strtoul (str + 2, 0, 0);
+      if (grub_errno != GRUB_ERR_NONE || drivenum > 127)
+        {
+          /* N not a number or out of range.  */
+          goto fail;
+        }
+      else
+        {
+          bios_num |= drivenum;
+          if (output)
+            *output = bios_num;
+          return GRUB_ERR_NONE;
+        }
+    }
+  else
+    goto fail;
+
+fail:
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "device format \"%s\" invalid: must"
+                     "be (f|h)dN, with 0 <= N < 128", str);
+}
+
+static grub_err_t
+grub_cmd_drivemap (struct grub_arg_list *state, int argc, char **args)
+{
+  if (state[OPTIDX_LIST].set)
+    {
+      /* Show: list mappings.  */
+      if (!drivemap)
+        grub_printf ("No drives have been remapped");
+      else
+        {
+          grub_printf ("Showing only remapped drives.\n");
+          grub_printf ("BIOS disk #num ----> GRUB device\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("%cD #%-3u (0x%02x)       %s\n",
+                          (curnode->newdrive & 0x80) ? 'H' : 'F',
+                          curnode->newdrive & 0x7F, curnode->newdrive, dname);
+              curnode = curnode->next;
+            }
+        }
+    }
+  else if (state[OPTIDX_RESET].set)
+    {
+      /* Reset: just delete all mappings, freeing their memory.  */
+      drivemap_node_t *curnode = drivemap;
+      drivemap_node_t *prevnode = 0;
+      while (curnode)
+        {
+          prevnode = curnode;
+          curnode = curnode->next;
+          grub_free (prevnode);
+        }
+      drivemap = 0;
+    }
+  else
+    {
+      /* Neither flag: put mapping.  */
+      grub_uint8_t mapfrom = 0;
+      grub_uint8_t mapto = 0xFF;
+      grub_err_t err;
+      
+      if (argc != 2)
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments required");
+
+      err = parse_biosdisk (args[0], &mapfrom);
+      if (err != GRUB_ERR_NONE)
+        return err;
+      
+      /* When swapping we require both devices to be BIOS disks, but when
+         performing direct mappings we only require the 2nd argument to look
+         like a BIOS disk in order to resolve it into a BIOS disk number.  */
+      if (state[OPTIDX_SWAP].set)
+        err = parse_biosdisk (args[1], &mapto);
+      else
+        err = tryparse_diskstring (args[1], &mapto);
+      if (err != GRUB_ERR_NONE)
+        return err;
+      
+      if (mapto == mapfrom)
+        {
+          /* Reset to default.  */
+          grub_dprintf (MODNAME, "Removing the mapping for %s (%02x)", args[0], mapfrom);
+          drivemap_remove (mapfrom);
+        }
+      else
+        {
+          /* Set the mapping for the disk (overwrites any existing mapping).  */
+          grub_dprintf (MODNAME, "%s %s (%02x) = %s (%02x)\n",
+                        state[OPTIDX_SWAP].set ? "Swapping" : "Mapping",
+                        args[1], mapto, args[0], mapfrom);
+          err = drivemap_set (mapto, mapfrom);
+          /* If -s, perform the reverse mapping too (only if the first was OK).  */
+          if (state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE)
+            err = drivemap_set (mapfrom, mapto);
+          return err;
+        }
+    }
+
+  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 apart from identity paging, since it accesses realmode
+   structures by their absolute addresses, like the IVT at 0 or the BDA at
+   0x400; and transforms a pmode pointer into a rmode seg:off far ptr.  */
+static grub_err_t
+install_int13_handler (void)
+{
+  grub_size_t entries = 0;
+  drivemap_node_t *curentry = drivemap;
+  /* Count entries to prepare a contiguous map block.  */
+  while (curentry)
+    {
+      entries++;
+      curentry = curentry->next;
+    }
+  if (entries == 0)
+    {
+      /* No need to install the int13h handler.  */
+      grub_dprintf (MODNAME, "No drives marked as remapped, installation of"
+                    "an int13h handler is not required.");
+      return GRUB_ERR_NONE;
+    }
+  else
+    {
+      /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13.  */
+      grub_uint32_t *ivtslot = (grub_uint32_t*)0x0000004c;
+      /* BDA offset 0x13 contains the top of conventional memory, in kiB.  */
+      grub_uint16_t *bpa_freekb = (grub_uint16_t*)0x00000413;
+      /* Size of the full int13 handler "bundle", including code and map.  */
+      grub_size_t total_size;
+      /* The former, ceil-rounded to KiB.  */
+      grub_uint16_t payload_sizekb;
+      /* Base address of the space reserved for the handler bundle.  */
+      grub_uint8_t *handler_base;
+      /* Address of the map within the deployed bundle.  */
+      int13map_node_t *handler_map;
+      /* Real mode IVT entry (seg:off far pointer) for the new handler.  */
+      grub_uint32_t ivtentry;
+
+      grub_dprintf (MODNAME, "Installing int13h handler...\n");
+      
+      /* Save the pointer to the old handler.  */
+      grub_drivemap_int13_oldhandler = *ivtslot;
+      grub_dprintf (MODNAME, "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.  */
+      grub_dprintf (MODNAME, "Top of conventional memory: %u KiB\n", *bpa_freekb);
+      total_size = grub_drivemap_int13_size
+                   + (entries + 1) * sizeof(int13map_node_t);
+      payload_sizekb = (total_size >> 10) +
+                       (((total_size % 1024) == 0) ? 0 : 1);
+      if ((*bpa_freekb - payload_sizekb) < MIN_FREE_MEM_KB)
+        return grub_error (GRUB_ERR_OUT_OF_MEMORY, "refusing to install"
+                           "int13 handler, not enough free memory after");
+      grub_dprintf (MODNAME, "Payload is %u b long, reserving %u Kb\n",
+                    total_size, payload_sizekb);
+      *bpa_freekb -= payload_sizekb;
+
+      /* Copy int13h handler bundle to reserved area.  */
+      handler_base = (grub_uint8_t*)(*bpa_freekb << 10);
+      grub_dprintf (MODNAME, "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;
+      handler_map = (int13map_node_t*)
+                    INT13H_TONEWADDR (&grub_drivemap_int13_mapstart);
+      grub_dprintf (MODNAME, "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;
+          grub_dprintf (MODNAME, "\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;
+      grub_dprintf (MODNAME, "\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.  */
+      ivtentry = ((grub_uint32_t)handler_base) << 12; /* Segment address.  */
+      ivtentry |= (grub_uint16_t) INT13H_OFFSET(&grub_drivemap_int13_handler);
+      grub_dprintf (MODNAME, "New int13 handler IVT pointer: %04x:%04x\n",
+                    (ivtentry >> 16) & 0x0ffff, ivtentry & 0x0ffff);
+      *ivtslot = ivtentry;
+      
+      return GRUB_ERR_NONE;
+    }
+}
+
+GRUB_MOD_INIT (drivemap)
+{
+  (void) mod;			/* Stop warning.  */
+  grub_register_command (MODNAME, grub_cmd_drivemap,
+                         GRUB_COMMAND_FLAG_BOTH,
+                         MODNAME " -l | -r | [-s] grubdev biosdisk",
+                         "Manage the BIOS drive mappings", options);
+  insthandler_hook = grub_loader_register_preboot (&install_int13_handler, 1);
+}
+
+GRUB_MOD_FINI (drivemap)
+{
+  grub_loader_unregister_preboot (insthandler_hook);
+  insthandler_hook = 0;
+  grub_unregister_command (MODNAME);
+}
+
Index: commands/i386/pc/drivemap_int13h.S
===================================================================
--- commands/i386/pc/drivemap_int13h.S	(revisión: 0)
+++ commands/i386/pc/drivemap_int13h.S	(revisión: 0)
@@ -0,0 +1,121 @@
+/*
+ *  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.
+ */
+
+#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)
+
+/* Far pointer to the old handler.  Stored as a CS:IP in the style of real-mode
+   IVT entries (thus PI:SC in mem).  */
+VARIABLE(grub_drivemap_int13_oldhandler)
+  .word 0xdead, 0xbeef
+
+/* Drivemap module bundle - 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.  IP-relative
+   addressing like on amd64 would make life way 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
+#  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)
+/* Copy stops here.  */
+.code32
+VARIABLE(grub_drivemap_int13_size)
+  .word GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_size)
+
Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk	(revisión: 1798)
+++ conf/i386-pc.rmk	(copia de trabajo)
@@ -163,7 +163,7 @@
 	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 pxe.mod pxecmd.mod
+	aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod drivemap.mod
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -340,4 +340,12 @@
 pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
 pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For drivemap.mod.
+drivemap_mod_HEADERS = machine/drivemap.h
+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
===================================================================
--- include/grub/loader.h	(revisión: 1798)
+++ include/grub/loader.h	(copia de trabajo)
@@ -37,7 +37,23 @@
 /* Unset current loader, if any.  */
 void EXPORT_FUNC(grub_loader_unset) (void);
 
-/* Call the boot hook in current loader. This may or may not return,
+typedef struct hooklist_node *grub_preboot_hookid;
+
+/* Register a function to be called before the loader "boot" function.  Returns
+   an id that can be later used to unregister the preboot (i.e. on module
+   unload).  If ABORT_ON_ERROR is set, the boot sequence will abort if any of
+   the registered functions return anything else than GRUB_ERR_NONE.
+   On error, the return value will compare equal to 0 and the error information
+   will be available in grub_errno.  However, if the call is successful that
+   variable is _not_ modified. */
+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: include/grub/i386/pc/drivemap.h
===================================================================
--- include/grub/i386/pc/drivemap.h	(revisión: 0)
+++ include/grub/i386/pc/drivemap.h	(revisión: 0)
@@ -0,0 +1,37 @@
+/* drivemap.h - 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/types.h>
+
+/* Realmode far ptr (2 * 16b) to the previous INT13h handler.  */
+extern grub_uint32_t grub_drivemap_int13_oldhandler;
+/* Size of the INT13h handler bundle (code+data) to be deployed.  */
+extern grub_uint16_t grub_drivemap_int13_size;
+
+/* This type is used for imported assembly labels, takes no storage and is only
+   used to take the symbol address with &label.  Do NOT put void* here.  */
+typedef void grub_symbol_t;
+
+/* Start of the handler bundle.  */
+extern grub_symbol_t grub_drivemap_int13_handler_base;
+/* Start of the drive mappings area (space reserved at runtime).  */
+extern grub_symbol_t grub_drivemap_int13_mapstart;
+/* The assembly function to replace the old INT13h handler. It should not be
+   called because it does not follow any C callspecs and returns with IRET.  */
+extern grub_symbol_t grub_drivemap_int13_handler;
Index: kern/loader.c
===================================================================
--- kern/loader.c	(revisión: 1798)
+++ kern/loader.c	(copia de trabajo)
@@ -61,11 +61,85 @@
   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)
+{
+  grub_preboot_hookid newentry;
+  if (!hook)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "preboot hook must not be NULL");
+      return 0;
+    }
+  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)
+{
+  grub_preboot_hookid entry = 0;
+  grub_preboot_hookid search = preboot_hooks;
+  grub_preboot_hookid previous = 0;
+
+  if (id == 0)
+    return;
+
+  while (search)
+    {
+      if (search == id)
+        {
+          entry = search;
+          break;
+        }
+      previous = search;
+      search = search->next;
+    }
+
+  if (entry)
+    {
+      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)
 {
+  grub_preboot_hookid entry = preboot_hooks;
+
   if (! grub_loader_loaded)
     return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel");
+  
+  while (entry)
+    {
+      grub_err_t possible_error = entry->hook();
+      if (possible_error != GRUB_ERR_NONE && entry->abort_on_error)
+        return possible_error;
+      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