]> git.proxmox.com Git - grub2.git/commitdiff
Multiboot 2 tags support
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 16 Jan 2010 15:25:43 +0000 (16:25 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 16 Jan 2010 15:25:43 +0000 (16:25 +0100)
ChangeLog.tag [new file with mode: 0644]
conf/i386.rmk
include/grub/i386/multiboot.h
include/grub/multiboot.h
include/multiboot2.h
loader/i386/multiboot.c
loader/i386/multiboot_mbi.c
loader/i386/multiboot_mbi2.c [new file with mode: 0644]

diff --git a/ChangeLog.tag b/ChangeLog.tag
new file mode 100644 (file)
index 0000000..dbeea10
--- /dev/null
@@ -0,0 +1,40 @@
+2010-01-16  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Multiboot2 tag support
+
+       * conf/i386.rmk (multiboot2_mod_SOURCES): Replace
+       loader/i386/multiboot_mbi.c with loader/i386/multiboot_mbi2.c.
+       * include/grub/i386/multiboot.h (grub_multiboot_real_boot): Removed.
+       (grub_multiboot2_real_boot): Likewise.
+       * include/grub/multiboot.h (grub_multiboot_set_accepts_video): Removed.
+       (grub_get_multiboot_mmap_len): New proto.
+       (grub_fill_multiboot_mmap): Likewise.
+       (grub_multiboot_set_video_mode): Likewise.
+       (grub_multiboot_fill_vbe_info_real): Likewise.
+       * include/multiboot2.h: Resynced with specification.
+       * loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): Moved from here...
+       * loader/i386/multiboot.c (DEFAULT_VIDEO_MODE): ... here.
+       * loader/i386/multiboot_mbi.c (HAS_VGA_TEXT): Moved from here ..
+       * include/grub/multiboot.h (GRUB_MACHINE_HAS_VGA_TEXT): ... here. All
+       users updated.
+       * loader/i386/multiboot_mbi.c (HAS_VBE): Moved from here ..
+       * include/grub/multiboot.h (GRUB_MACHINE_HAS_VBE): ... here. All
+       users updated.
+       * loader/i386/multiboot_mbi.c (accepts_video): Moved from here...
+       * loader/i386/multiboot.c (accepts_video): ... here. All users updated.
+       * loader/i386/multiboot_mbi.c (grub_multiboot_set_accepts_video):
+       Removed.
+       * loader/i386/multiboot_mbi.c (grub_get_multiboot_mmap_len):
+       Moved from here...
+       * loader/i386/multiboot.c (grub_get_multiboot_mmap_len): ... here.
+       * loader/i386/multiboot_mbi.c (grub_fill_multiboot_mmap):
+       Moved from here...
+       * loader/i386/multiboot.c (grub_fill_multiboot_mmap): ... here.
+       * loader/i386/multiboot_mbi.c (set_video_mode): Moved from here...
+       * loader/i386/multiboot.c (grub_multiboot_set_video_mode): ... here.
+       All users updated.
+       * loader/i386/multiboot_mbi.c (fill_vbe_info): Moved generic parts
+       from here...
+       * loader/i386/multiboot.c (grub_multiboot_fill_vbe_info_real): ... here.
+       All users updated.
+       * loader/i386/multiboot_mbi2.c: New file.
index 7ef337c612724601dd4af4715e5437ec624e46a3..064ee3ab4c5a728bdda7e2db88ea73a100fdd5d7 100644 (file)
@@ -36,7 +36,7 @@ multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 pkglib_MODULES += multiboot2.mod
 multiboot2_mod_SOURCES = loader/i386/multiboot.c \
-                        loader/i386/multiboot_mbi.c \
+                        loader/i386/multiboot_mbi2.c \
                          loader/multiboot_loader.c
 multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2
 multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS)
index 584955449bb7ec4e733420c8c0cc60cbb6fcf657..8131e9477ed1df46479a4027cfceea95f8170877 100644 (file)
 #ifndef GRUB_MULTIBOOT_CPU_HEADER
 #define GRUB_MULTIBOOT_CPU_HEADER      1
 
-/* The asm part of the multiboot loader.  */
-void grub_multiboot_real_boot (grub_addr_t entry,
-                              struct multiboot_info *mbi)
-     __attribute__ ((noreturn));
-void grub_multiboot2_real_boot (grub_addr_t entry,
-                               struct multiboot_info *mbi)
-     __attribute__ ((noreturn));
-
 extern grub_uint32_t grub_multiboot_payload_eip;
 extern char *grub_multiboot_payload_orig;
 extern grub_addr_t grub_multiboot_payload_dest;
index 665292e330425267bfcb1ee1ca2579f67a18b62a..8a7289820537c3e1db91f7720232103e203a2b50 100644 (file)
@@ -35,8 +35,6 @@
 void grub_multiboot (int argc, char *argv[]);
 void grub_module (int argc, char *argv[]);
 
-void grub_multiboot_set_accepts_video (int val);
-
 grub_size_t grub_multiboot_get_mbi_size (void);
 grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest,
                                    grub_off_t buf_off, grub_size_t bufsize);
@@ -46,5 +44,24 @@ grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
                                      int argc, char *argv[]);
 void grub_multiboot_set_bootdev (void);
 
+grub_uint32_t grub_get_multiboot_mmap_len (void);
+void grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry);
+grub_err_t grub_multiboot_set_video_mode (void);
+
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
+#include <grub/i386/pc/vbe.h>
+grub_err_t
+grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info,
+                                  struct grub_vbe_mode_info_block *vbe_mode_info,
+                                  multiboot_uint16_t *vbe_mode,
+                                  multiboot_uint16_t *vbe_interface_seg,
+                                  multiboot_uint16_t *vbe_interface_off,
+                                  multiboot_uint16_t *vbe_interface_len);
+#define GRUB_MACHINE_HAS_VBE 1
+#define GRUB_MACHINE_HAS_VGA_TEXT 1
+#else
+#define GRUB_MACHINE_HAS_VBE 0
+#define GRUB_MACHINE_HAS_VGA_TEXT 0
+#endif
 
 #endif /* ! GRUB_MULTIBOOT_HEADER */
index a241a70ad2311ad41beaf641fd073a7d1d3e6ad1..a76364fa7b3738a2545cea3c6c0aa2f258ceb298 100644 (file)
 /* This flag indicates the use of the address fields in the header.  */
 #define MULTIBOOT_AOUT_KLUDGE                  0x00010000
 
-/* Flags to be set in the 'flags' member of the multiboot info structure.  */
-
-/* is there basic lower/upper memory information? */
-#define MULTIBOOT_INFO_MEMORY                  0x00000001
-/* is there a boot device set? */
-#define MULTIBOOT_INFO_BOOTDEV                 0x00000002
-/* is the command-line defined? */
-#define MULTIBOOT_INFO_CMDLINE                 0x00000004
-/* are there modules to do something with? */
-#define MULTIBOOT_INFO_MODS                    0x00000008
-
-/* These next two are mutually exclusive */
-
-/* is there a symbol table loaded? */
-#define MULTIBOOT_INFO_AOUT_SYMS               0x00000010
-/* is there an ELF section header table? */
-#define MULTIBOOT_INFO_ELF_SHDR                        0X00000020
-
-/* is there a full memory map? */
-#define MULTIBOOT_INFO_MEM_MAP                 0x00000040
-
-/* Is there drive info?  */
-#define MULTIBOOT_INFO_DRIVE_INFO              0x00000080
-
-/* Is there a config table?  */
-#define MULTIBOOT_INFO_CONFIG_TABLE            0x00000100
-
-/* Is there a boot loader name?  */
-#define MULTIBOOT_INFO_BOOT_LOADER_NAME                0x00000200
-
-/* Is there a APM table?  */
-#define MULTIBOOT_INFO_APM_TABLE               0x00000400
-
-/* Is there video information?  */
-#define MULTIBOOT_INFO_VBE_INFO                        0x00000800
-#define MULTIBOOT_INFO_FRAMEBUFFER_INFO                0x00001000
+#define MULTIBOOT_TAG_TYPE_END               0
+#define MULTIBOOT_TAG_TYPE_CMDLINE           1
+#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME  2
+#define MULTIBOOT_TAG_TYPE_MODULE            3
+#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO     4
+#define MULTIBOOT_TAG_TYPE_BOOTDEV           5
+#define MULTIBOOT_TAG_TYPE_MMAP              6
+#define MULTIBOOT_TAG_TYPE_VBE               7
+#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER       8
 
 #ifndef ASM_FILE
 
@@ -120,76 +93,99 @@ struct multiboot_header
   multiboot_uint32_t depth;
 };
 
-/* The symbol table for a.out.  */
-struct multiboot_aout_symbol_table
+struct multiboot_color
+{
+  multiboot_uint8_t red;
+  multiboot_uint8_t green;
+  multiboot_uint8_t blue;
+};
+
+struct multiboot_mmap_entry
+{
+  multiboot_uint32_t size;
+  multiboot_uint64_t addr;
+  multiboot_uint64_t len;
+#define MULTIBOOT_MEMORY_AVAILABLE             1
+#define MULTIBOOT_MEMORY_RESERVED              2
+  multiboot_uint32_t type;
+} __attribute__((packed));
+typedef struct multiboot_mmap_entry multiboot_memory_map_t;
+
+struct multiboot_tag
 {
-  multiboot_uint32_t tabsize;
-  multiboot_uint32_t strsize;
-  multiboot_uint32_t addr;
-  multiboot_uint32_t reserved;
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
 };
-typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
 
-/* The section header table for ELF.  */
-struct multiboot_elf_section_header_table
+struct multiboot_tag_string
 {
-  multiboot_uint32_t num;
+  multiboot_uint32_t type;
   multiboot_uint32_t size;
-  multiboot_uint32_t addr;
-  multiboot_uint32_t shndx;
+  char string[0];
 };
-typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
 
-struct multiboot_info
+struct multiboot_tag_module
 {
-  /* Multiboot info version number */
-  multiboot_uint32_t flags;
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t mod_start;
+  multiboot_uint32_t mod_end;
+  char cmdline[0];
+};
 
-  /* Available memory from BIOS */
+struct multiboot_tag_basic_meminfo
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
   multiboot_uint32_t mem_lower;
   multiboot_uint32_t mem_upper;
+};
 
-  /* "root" partition */
-  multiboot_uint32_t boot_device;
-
-  /* Kernel command line */
-  multiboot_uint32_t cmdline;
-
-  /* Boot-Module list */
-  multiboot_uint32_t mods_count;
-  multiboot_uint32_t mods_addr;
-
-  union
-  {
-    multiboot_aout_symbol_table_t aout_sym;
-    multiboot_elf_section_header_table_t elf_sec;
-  } u;
-
-  /* Memory Mapping buffer */
-  multiboot_uint32_t mmap_length;
-  multiboot_uint32_t mmap_addr;
+struct multiboot_tag_bootdev
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t biosdev;
+  multiboot_uint32_t slice;
+  multiboot_uint32_t part;
+};
 
-  /* Drive Info buffer */
-  multiboot_uint32_t drives_length;
-  multiboot_uint32_t drives_addr;
+struct multiboot_tag_mmap
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  struct multiboot_mmap_entry entries[0];  
+};
 
-  /* ROM configuration table */
-  multiboot_uint32_t config_table;
+struct multiboot_vbe_info_block
+{
+  multiboot_uint8_t external_specification[512];
+};
 
-  /* Boot Loader Name */
-  multiboot_uint32_t boot_loader_name;
+struct multiboot_vbe_mode_info_block
+{
+  multiboot_uint8_t external_specification[256];
+};
 
-  /* APM table */
-  multiboot_uint32_t apm_table;
+struct multiboot_tag_vbe
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
 
-  /* Video */
-  multiboot_uint32_t vbe_control_info;
-  multiboot_uint32_t vbe_mode_info;
   multiboot_uint16_t vbe_mode;
   multiboot_uint16_t vbe_interface_seg;
   multiboot_uint16_t vbe_interface_off;
   multiboot_uint16_t vbe_interface_len;
 
+  struct multiboot_vbe_info_block vbe_control_info;
+  struct multiboot_vbe_mode_info_block vbe_mode_info;
+};
+
+struct multiboot_tag_framebuffer_common
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+
   multiboot_uint64_t framebuffer_addr;
   multiboot_uint32_t framebuffer_pitch;
   multiboot_uint32_t framebuffer_width;
@@ -199,12 +195,18 @@ struct multiboot_info
 #define MULTIBOOT_FRAMEBUFFER_TYPE_RGB     1
 #define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT    2
   multiboot_uint8_t framebuffer_type;
+};
+
+struct multiboot_tag_framebuffer
+{
+  struct multiboot_tag_framebuffer_common common;
+
   union
   {
     struct
     {
-      multiboot_uint32_t framebuffer_palette_addr;
       multiboot_uint16_t framebuffer_palette_num_colors;
+      struct multiboot_color framebuffer_palette[0];
     };
     struct
     {
@@ -217,39 +219,6 @@ struct multiboot_info
     };
   };
 };
-typedef struct multiboot_info multiboot_info_t;
-
-struct multiboot_color
-{
-  multiboot_uint8_t red;
-  multiboot_uint8_t green;
-  multiboot_uint8_t blue;
-};
-
-struct multiboot_mmap_entry
-{
-  multiboot_uint32_t size;
-  multiboot_uint64_t addr;
-  multiboot_uint64_t len;
-#define MULTIBOOT_MEMORY_AVAILABLE             1
-#define MULTIBOOT_MEMORY_RESERVED              2
-  multiboot_uint32_t type;
-} __attribute__((packed));
-typedef struct multiboot_mmap_entry multiboot_memory_map_t;
-
-struct multiboot_mod_list
-{
-  /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
-  multiboot_uint32_t mod_start;
-  multiboot_uint32_t mod_end;
-
-  /* Module command line */
-  multiboot_uint32_t cmdline;
-
-  /* padding to take it to 16 bytes (must be zero) */
-  multiboot_uint32_t pad;
-};
-typedef struct multiboot_mod_list multiboot_module_t;
 
 #endif /* ! ASM_FILE */
 
index 0ac3ca33971c0e253c81f9a7c6343c86c9d937b9..86bb91ec8b7b398b9634f02e780c851378bdc4b1 100644 (file)
 #include <grub/env.h>
 #include <grub/i386/relocator.h>
 #include <grub/video.h>
+#include <grub/memory.h>
 
 #ifdef GRUB_MACHINE_EFI
 #include <grub/efi/efi.h>
 #endif
 
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
+#define DEFAULT_VIDEO_MODE "text"
+#else
+#define DEFAULT_VIDEO_MODE "auto"
+#endif
+
 extern grub_dl_t my_mod;
 static grub_size_t code_size, alloc_mbi;
 
@@ -56,6 +63,135 @@ char *grub_multiboot_payload_orig;
 grub_addr_t grub_multiboot_payload_dest;
 grub_size_t grub_multiboot_pure_size;
 grub_uint32_t grub_multiboot_payload_eip;
+static int accepts_video;
+
+/* Return the length of the Multiboot mmap that will be needed to allocate
+   our platform's map.  */
+grub_uint32_t
+grub_get_multiboot_mmap_len (void)
+{
+  grub_size_t count = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)),
+                            grub_uint64_t size __attribute__ ((unused)),
+                            grub_uint32_t type __attribute__ ((unused)))
+    {
+      count++;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+
+  return count * sizeof (struct multiboot_mmap_entry);
+}
+
+/* Fill previously allocated Multiboot mmap.  */
+void
+grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
+{
+  struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+    {
+      mmap_entry->addr = addr;
+      mmap_entry->len = size;
+      switch (type)
+       {
+       case GRUB_MACHINE_MEMORY_AVAILABLE:
+         mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE;
+         break;
+         
+       default:
+         mmap_entry->type = MULTIBOOT_MEMORY_RESERVED;
+         break;
+       }
+      mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size);
+      mmap_entry++;
+
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+}
+
+grub_err_t
+grub_multiboot_set_video_mode (void)
+{
+  grub_err_t err;
+  const char *modevar;
+
+  if (accepts_video || !GRUB_MACHINE_HAS_VGA_TEXT)
+    {
+      modevar = grub_env_get ("gfxpayload");
+      if (! modevar || *modevar == 0)
+       err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0);
+      else
+       {
+         char *tmp;
+         tmp = grub_malloc (grub_strlen (modevar)
+                            + sizeof (DEFAULT_VIDEO_MODE) + 1);
+         if (! tmp)
+           return grub_errno;
+         grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
+         err = grub_video_set_mode (tmp, 0);
+         grub_free (tmp);
+       }
+    }
+  else
+    err = grub_video_set_mode ("text", 0);
+
+  return err;
+}
+
+#if GRUB_MACHINE_HAS_VBE
+grub_err_t
+grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info,
+                                  struct grub_vbe_mode_info_block *vbe_mode_info,
+                                  multiboot_uint16_t *vbe_mode,
+                                  multiboot_uint16_t *vbe_interface_seg,
+                                  multiboot_uint16_t *vbe_interface_off,
+                                  multiboot_uint16_t *vbe_interface_len)
+{
+  grub_vbe_status_t status;
+  void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+    
+  status = grub_vbe_bios_get_controller_info (scratch);
+  if (status != GRUB_VBE_STATUS_OK)
+    return grub_error (GRUB_ERR_IO, "Can't get controller info.");  
+  grub_memcpy (vbe_control_info, scratch, sizeof (struct grub_vbe_info_block));
+  
+  status = grub_vbe_bios_get_mode (scratch);
+  *vbe_mode = *(grub_uint32_t *) scratch;
+  if (status != GRUB_VBE_STATUS_OK)
+    return grub_error (GRUB_ERR_IO, "can't get VBE mode");
+
+  /* get_mode_info isn't available for mode 3.  */
+  if (*vbe_mode == 3)
+    {
+      grub_memset (vbe_mode_info, 0, sizeof (struct grub_vbe_mode_info_block));
+      vbe_mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT;
+      vbe_mode_info->x_resolution = 80;
+      vbe_mode_info->y_resolution = 25;
+    }
+  else
+    {
+      status = grub_vbe_bios_get_mode_info (*vbe_mode, scratch);
+      if (status != GRUB_VBE_STATUS_OK)
+       return grub_error (GRUB_ERR_IO, "can't get mode info");
+      grub_memcpy (vbe_mode_info, scratch,
+                  sizeof (struct grub_vbe_mode_info_block));
+    }
+      
+  /* FIXME: retrieve those.  */
+  *vbe_interface_seg = 0;
+  *vbe_interface_off = 0;
+  *vbe_interface_len = 0;
+  
+  return GRUB_ERR_NONE;
+}
+#endif
 
 static grub_err_t
 grub_multiboot_boot (void)
@@ -265,7 +401,7 @@ grub_multiboot (int argc, char *argv[])
        }
     }
 
-  grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE));
+  accepts_video = !!(header->flags & MULTIBOOT_VIDEO_MODE);
 
   grub_multiboot_set_bootdev ();
 
index ddbbf3cfd3133ce7dd6c8a4382d4e2071c094aef..9c45b335233b9f35b777c805c8151b7947459d60 100644 (file)
 #include <grub/env.h>
 #include <grub/video.h>
 
-#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
-#include <grub/i386/pc/vbe.h>
-#define DEFAULT_VIDEO_MODE "text"
-#define HAS_VGA_TEXT 1
-#define HAS_VBE 1
-#else
-#define DEFAULT_VIDEO_MODE "auto"
-#define HAS_VGA_TEXT 0
-#define HAS_VBE 0
-#endif
-
 struct module
 {
   struct module *next;
@@ -58,34 +47,6 @@ static unsigned modcnt;
 static char *cmdline = NULL;
 static grub_uint32_t bootdev;
 static int bootdev_set;
-static int accepts_video;
-
-void
-grub_multiboot_set_accepts_video (int val)
-{
-  accepts_video = val;
-}
-
-/* Return the length of the Multiboot mmap that will be needed to allocate
-   our platform's map.  */
-static grub_uint32_t
-grub_get_multiboot_mmap_len (void)
-{
-  grub_size_t count = 0;
-
-  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
-  int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)),
-                            grub_uint64_t size __attribute__ ((unused)),
-                            grub_uint32_t type __attribute__ ((unused)))
-    {
-      count++;
-      return 0;
-    }
-
-  grub_mmap_iterate (hook);
-
-  return count * sizeof (struct multiboot_mmap_entry);
-}
 
 grub_size_t
 grub_multiboot_get_mbi_size (void)
@@ -93,142 +54,45 @@ grub_multiboot_get_mbi_size (void)
   return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4)
     + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd
     + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_len ()
-#if HAS_VBE
+#if GRUB_MACHINE_HAS_VBE
     + sizeof (struct grub_vbe_info_block)
     + sizeof (struct grub_vbe_mode_info_block)
 #endif
     + 256 * sizeof (struct multiboot_color);
 }
 
-/* Fill previously allocated Multiboot mmap.  */
-static void
-grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
-{
-  struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry;
-
-  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
-  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
-    {
-      mmap_entry->addr = addr;
-      mmap_entry->len = size;
-      switch (type)
-       {
-       case GRUB_MACHINE_MEMORY_AVAILABLE:
-         mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE;
-         break;
-         
-       default:
-         mmap_entry->type = MULTIBOOT_MEMORY_RESERVED;
-         break;
-       }
-      mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size);
-      mmap_entry++;
-
-      return 0;
-    }
-
-  grub_mmap_iterate (hook);
-}
-
+#if GRUB_MACHINE_HAS_VBE
 static grub_err_t
-set_video_mode (void)
+fill_vbe_info (struct multiboot_info *mbi,
+              struct grub_vbe_mode_info_block **vbe_mode_info_out,
+              grub_uint8_t *ptrorig, grub_addr_t ptrdest)
 {
+  struct grub_vbe_info_block *vbe_control_info;
+  struct grub_vbe_mode_info_block *vbe_mode_info;
   grub_err_t err;
-  const char *modevar;
-
-  if (accepts_video || !HAS_VGA_TEXT)
-    {
-      modevar = grub_env_get ("gfxpayload");
-      if (! modevar || *modevar == 0)
-       err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0);
-      else
-       {
-         char *tmp;
-         tmp = grub_malloc (grub_strlen (modevar)
-                            + sizeof (DEFAULT_VIDEO_MODE) + 1);
-         if (! tmp)
-           return grub_errno;
-         grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
-         err = grub_video_set_mode (tmp, 0);
-         grub_free (tmp);
-       }
-    }
-  else
-    err = grub_video_set_mode ("text", 0);
-
-  return err;
-}
 
-#if HAS_VBE
-static grub_err_t
-fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig,
-              grub_uint32_t ptrdest, int fill_generic)
-{
-  grub_vbe_status_t status;
-  grub_uint32_t vbe_mode;
-  void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
-  struct grub_vbe_mode_info_block *mode_info;
-    
-  status = grub_vbe_bios_get_controller_info (scratch);
-  if (status != GRUB_VBE_STATUS_OK)
-    return grub_error (GRUB_ERR_IO, "Can't get controller info.");
-  
+  vbe_control_info = (struct grub_vbe_info_block *) ptrorig;
   mbi->vbe_control_info = ptrdest;
-  grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_info_block));
   ptrorig += sizeof (struct grub_vbe_info_block);
   ptrdest += sizeof (struct grub_vbe_info_block);
-  
-  status = grub_vbe_bios_get_mode (scratch);
-  vbe_mode = *(grub_uint32_t *) scratch;
-  if (status != GRUB_VBE_STATUS_OK)
-    return grub_error (GRUB_ERR_IO, "can't get VBE mode");
-  mbi->vbe_mode = vbe_mode;
-
-  mode_info = (struct grub_vbe_mode_info_block *) ptrorig;
+  vbe_mode_info = (struct grub_vbe_mode_info_block *) ptrorig;
   mbi->vbe_mode_info = ptrdest;
-  /* get_mode_info isn't available for mode 3.  */
-  if (vbe_mode == 3)
-    {
-      grub_memset (mode_info, 0, sizeof (struct grub_vbe_mode_info_block));
-      mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT;
-      mode_info->x_resolution = 80;
-      mode_info->y_resolution = 25;
-    }
-  else
-    {
-      status = grub_vbe_bios_get_mode_info (vbe_mode, scratch);
-      if (status != GRUB_VBE_STATUS_OK)
-       return grub_error (GRUB_ERR_IO, "can't get mode info");
-      grub_memcpy (mode_info, scratch,
-                  sizeof (struct grub_vbe_mode_info_block));
-    }
   ptrorig += sizeof (struct grub_vbe_mode_info_block);
   ptrdest += sizeof (struct grub_vbe_mode_info_block);
-      
-  /* FIXME: retrieve those.  */
-  mbi->vbe_interface_seg = 0;
-  mbi->vbe_interface_off = 0;
-  mbi->vbe_interface_len = 0;
   
+  err = grub_multiboot_fill_vbe_info_real (vbe_control_info, vbe_mode_info,
+                                          &mbi->vbe_mode,
+                                          &mbi->vbe_interface_seg,
+                                          &mbi->vbe_interface_off,
+                                          &mbi->vbe_interface_len);
+  if (err)
+    return err;
   mbi->flags |= MULTIBOOT_INFO_VBE_INFO;
-
-  if (fill_generic && mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
-    {
-      mbi->framebuffer_addr = 0xb8000;
-
-      mbi->framebuffer_pitch = 2 * mode_info->x_resolution;    
-      mbi->framebuffer_width = mode_info->x_resolution;
-      mbi->framebuffer_height = mode_info->y_resolution;
-
-      mbi->framebuffer_bpp = 16;
-
-      mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
-
-      mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
-    }
-
+  if (vbe_mode_info_out)
+    *vbe_mode_info_out = vbe_mode_info;
   return GRUB_ERR_NONE;
 }
+
 #endif
 
 static grub_err_t
@@ -241,7 +105,7 @@ retrieve_video_parameters (struct multiboot_info *mbi,
   grub_video_driver_id_t driv_id;
   struct grub_video_palette_data palette[256];
 
-  err = set_video_mode ();
+  err = grub_multiboot_set_video_mode ();
   if (err)
     {
       grub_print_error ();
@@ -251,9 +115,29 @@ retrieve_video_parameters (struct multiboot_info *mbi,
   grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
 
   driv_id = grub_video_get_driver_id ();
-#if HAS_VGA_TEXT
+#if GRUB_MACHINE_HAS_VGA_TEXT
   if (driv_id == GRUB_VIDEO_DRIVER_NONE)
-    return fill_vbe_info (mbi, ptrorig, ptrdest, 1);
+    {
+      struct grub_vbe_mode_info_block *vbe_mode_info;
+      err = fill_vbe_info (mbi, &vbe_mode_info, ptrorig, ptrdest);
+      if (err)
+       return err;
+      if (vbe_mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
+       {
+         mbi->framebuffer_addr = 0xb8000;
+         
+         mbi->framebuffer_pitch = 2 * vbe_mode_info->x_resolution;     
+         mbi->framebuffer_width = vbe_mode_info->x_resolution;
+         mbi->framebuffer_height = vbe_mode_info->y_resolution;
+
+         mbi->framebuffer_bpp = 16;
+         
+         mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
+
+         mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
+       }
+      return GRUB_ERR_NONE;
+    }
 #else
   if (driv_id == GRUB_VIDEO_DRIVER_NONE)
     return GRUB_ERR_NONE;
@@ -305,9 +189,13 @@ retrieve_video_parameters (struct multiboot_info *mbi,
 
   mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
 
-#if HAS_VBE
+#if GRUB_MACHINE_HAS_VBE
   if (driv_id == GRUB_VIDEO_DRIVER_VBE)
-    return fill_vbe_info (mbi, ptrorig, ptrdest, 0);
+    {
+      err = fill_vbe_info (mbi, NULL, ptrorig, ptrdest);
+      if (err)
+       return err;
+    }
 #endif
 
   return GRUB_ERR_NONE;
@@ -396,7 +284,7 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
       grub_print_error ();
       grub_errno = GRUB_ERR_NONE;
     }
-#if HAS_VBE
+#if GRUB_MACHINE_HAS_VBE
   ptrorig += sizeof (struct grub_vbe_info_block);
   ptrdest += sizeof (struct grub_vbe_info_block);
   ptrorig += sizeof (struct grub_vbe_mode_info_block);
diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c
new file mode 100644 (file)
index 0000000..031d4c0
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009  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/memory.h>
+#include <grub/memory.h>
+#ifdef GRUB_MACHINE_PCBIOS
+#include <grub/machine/biosnum.h>
+#endif
+#include <grub/multiboot.h>
+#include <grub/cpu/multiboot.h>
+#include <grub/disk.h>
+#include <grub/device.h>
+#include <grub/partition.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/video.h>
+
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
+#include <grub/i386/pc/vbe.h>
+#define DEFAULT_VIDEO_MODE "text"
+#define HAS_VGA_TEXT 1
+#define HAS_VBE 1
+#else
+#define DEFAULT_VIDEO_MODE "auto"
+#define HAS_VGA_TEXT 0
+#define HAS_VBE 0
+#endif
+
+struct module
+{
+  struct module *next;
+  grub_addr_t start;
+  grub_size_t size;
+  char *cmdline;
+  int cmdline_size;
+};
+
+struct module *modules, *modules_last;
+static grub_size_t cmdline_size;
+static grub_size_t total_modcmd;
+static unsigned modcnt;
+static char *cmdline = NULL;
+static int bootdev_set;
+static grub_uint32_t biosdev, slice, part;
+
+grub_size_t
+grub_multiboot_get_mbi_size (void)
+{
+  return sizeof (struct multiboot_tag)
+    + (sizeof (struct multiboot_tag_string) + ALIGN_UP (cmdline_size, 4))
+    + (sizeof (struct multiboot_tag_string)
+       + ALIGN_UP (sizeof (PACKAGE_STRING), 4))
+    + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd)
+    + sizeof (struct multiboot_tag_basic_meminfo)
+    + sizeof (struct multiboot_tag_bootdev)
+    + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_len ())
+    + sizeof (struct multiboot_tag_vbe);
+}
+
+#ifdef GRUB_MACHINE_HAS_VBE
+
+static grub_err_t
+fill_vbe_info (struct grub_vbe_mode_info_block **vbe_mode_info_out,
+              grub_uint8_t **ptrorig)
+{
+  struct multiboot_tag_vbe *tag = (struct multiboot_tag_vbe *) *ptrorig;
+  grub_err_t err;
+
+  tag->type = MULTIBOOT_TAG_TYPE_VBE;
+  tag->size = 0;
+  err = grub_multiboot_fill_vbe_info_real ((struct grub_vbe_info_block *)
+                                          &(tag->vbe_control_info),
+                                          (struct grub_vbe_mode_info_block *) 
+                                          &(tag->vbe_mode_info),
+                                          &(tag->vbe_mode),
+                                          &(tag->vbe_interface_seg),
+                                          &(tag->vbe_interface_off),
+                                          &(tag->vbe_interface_len));
+  if (err)
+    return err;
+  if (vbe_mode_info_out)
+    *vbe_mode_info_out = (struct grub_vbe_mode_info_block *) 
+      &(tag->vbe_mode_info);
+  tag->size = sizeof (struct multiboot_tag_vbe);
+  *ptrorig += tag->size;
+  return GRUB_ERR_NONE;
+}
+
+#endif
+
+static grub_err_t
+retrieve_video_parameters (grub_uint8_t **ptrorig)
+{
+  grub_err_t err;
+  struct grub_video_mode_info mode_info;
+  void *framebuffer;
+  grub_video_driver_id_t driv_id;
+  struct grub_video_palette_data palette[256];
+  struct multiboot_tag_framebuffer *tag
+    = (struct multiboot_tag_framebuffer *) *ptrorig;
+
+  err = grub_multiboot_set_video_mode ();
+  if (err)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+    }
+
+  grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
+
+  driv_id = grub_video_get_driver_id ();
+#if HAS_VGA_TEXT
+  if (driv_id == GRUB_VIDEO_DRIVER_NONE)
+    {
+      struct grub_vbe_mode_info_block *vbe_mode_info;
+      err = fill_vbe_info (&vbe_mode_info, ptrorig);
+      if (err)
+       return err;
+      if (vbe_mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
+       {
+         tag = (struct multiboot_tag_framebuffer *) *ptrorig;
+         tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
+         tag->common.size = 0;
+
+         tag->common.framebuffer_addr = 0xb8000;
+         
+         tag->common.framebuffer_pitch = 2 * vbe_mode_info->x_resolution;      
+         tag->common.framebuffer_width = vbe_mode_info->x_resolution;
+         tag->common.framebuffer_height = vbe_mode_info->y_resolution;
+
+         tag->common.framebuffer_bpp = 16;
+         
+         tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
+         tag->common.size = sizeof (tag->common);
+         *ptrorig += tag->common.size;
+       }
+      return GRUB_ERR_NONE;
+    }
+#else
+  if (driv_id == GRUB_VIDEO_DRIVER_NONE)
+    return GRUB_ERR_NONE;
+#endif
+
+  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
+  if (err)
+    return err;
+
+  tag = (struct multiboot_tag_framebuffer *) *ptrorig;
+  tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
+  tag->common.size = 0;
+
+  tag->common.framebuffer_addr = (grub_addr_t) framebuffer;
+  tag->common.framebuffer_pitch = mode_info.pitch;
+
+  tag->common.framebuffer_width = mode_info.width;
+  tag->common.framebuffer_height = mode_info.height;
+
+  tag->common.framebuffer_bpp = mode_info.bpp;
+      
+  if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
+    {
+      unsigned i;
+      tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
+      tag->framebuffer_palette_num_colors = mode_info.number_of_colors;
+      if (tag->framebuffer_palette_num_colors > ARRAY_SIZE (palette))
+       tag->framebuffer_palette_num_colors = ARRAY_SIZE (palette);
+      tag->common.size = sizeof (struct multiboot_tag_framebuffer_common)
+       + sizeof (multiboot_uint16_t) + tag->framebuffer_palette_num_colors
+       * sizeof (struct multiboot_color);
+      for (i = 0; i < tag->framebuffer_palette_num_colors; i++)
+       {
+         tag->framebuffer_palette[i].red = palette[i].r;
+         tag->framebuffer_palette[i].green = palette[i].g;
+         tag->framebuffer_palette[i].blue = palette[i].b;
+       }
+      *ptrorig += tag->common.size;
+    }
+  else
+    {
+      tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
+      tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
+      tag->framebuffer_red_field_position = mode_info.green_field_pos;
+      tag->framebuffer_red_mask_size = mode_info.green_mask_size;
+      tag->framebuffer_green_field_position = mode_info.green_field_pos;
+      tag->framebuffer_green_mask_size = mode_info.green_mask_size;
+      tag->framebuffer_blue_field_position = mode_info.blue_field_pos;
+      tag->framebuffer_blue_mask_size = mode_info.blue_mask_size;
+
+      tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + 6;
+    }
+
+#if HAS_VBE
+  if (driv_id == GRUB_VIDEO_DRIVER_VBE)
+    {
+      err = fill_vbe_info (NULL, ptrorig);
+      if (err)
+       return err;
+    }
+#endif
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
+                        grub_size_t bufsize)
+{
+  grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off;
+  grub_err_t err;
+
+  if (bufsize < grub_multiboot_get_mbi_size ())
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small");
+
+  {
+    struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig;
+    tag->type = MULTIBOOT_TAG_TYPE_CMDLINE;
+    tag->size = sizeof (struct multiboot_tag_string)
+      + ALIGN_UP (cmdline_size, 4); 
+    grub_memcpy (tag->string, cmdline, cmdline_size);
+    ptrorig += tag->size;
+  }
+
+  {
+    struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig;
+    tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;
+    tag->size = sizeof (struct multiboot_tag_string)
+      + ALIGN_UP (sizeof (PACKAGE_STRING), 4); 
+    grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING));
+    ptrorig += tag->size;
+  }
+
+  {
+    unsigned i;
+    struct module *cur;
+
+    for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next)
+      {
+       struct multiboot_tag_module *tag
+         = (struct multiboot_tag_module *) ptrorig;
+       tag->type = MULTIBOOT_TAG_TYPE_MODULE;
+       tag->size = sizeof (struct multiboot_tag_module)
+         + ALIGN_UP (sizeof (cur->cmdline_size), 4); 
+
+       tag->mod_start = dest + cur->start;
+       tag->mod_end = tag->mod_start + cur->size;
+       grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size);
+       ptrorig += tag->size;
+      }
+  }
+
+  {
+    struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig;
+    tag->type = MULTIBOOT_TAG_TYPE_MMAP;
+    tag->size = sizeof (struct multiboot_tag_mmap) 
+      + grub_get_multiboot_mmap_len (); 
+    grub_fill_multiboot_mmap (tag->entries);
+    ptrorig += tag->size;
+  }
+
+  {
+    struct multiboot_tag_basic_meminfo *tag
+      = (struct multiboot_tag_basic_meminfo *) ptrorig;
+    tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO;
+    tag->size = sizeof (struct multiboot_tag_basic_meminfo); 
+
+    /* Convert from bytes to kilobytes.  */
+    tag->mem_lower = grub_mmap_get_lower () / 1024;
+    tag->mem_upper = grub_mmap_get_upper () / 1024;
+    ptrorig += tag->size;
+  }
+
+  if (bootdev_set)
+    {
+      struct multiboot_tag_bootdev *tag
+       = (struct multiboot_tag_bootdev *) ptrorig;
+      tag->type = MULTIBOOT_TAG_TYPE_BOOTDEV;
+      tag->size = sizeof (struct multiboot_tag_bootdev); 
+
+      tag->biosdev = biosdev;
+      tag->slice = slice;
+      tag->part = part;
+      ptrorig += tag->size;
+    }
+
+  {
+    err = retrieve_video_parameters (&ptrorig);
+    if (err)
+      {
+       grub_print_error ();
+       grub_errno = GRUB_ERR_NONE;
+      }
+  }
+  
+  {
+    struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig;
+    tag->type = MULTIBOOT_TAG_TYPE_END;
+    tag->size = sizeof (struct multiboot_tag);
+    ptrorig += tag->size;
+  }
+
+  return GRUB_ERR_NONE;
+}
+
+void
+grub_multiboot_free_mbi (void)
+{
+  struct module *cur, *next;
+
+  cmdline_size = 0;
+  total_modcmd = 0;
+  modcnt = 0;
+  grub_free (cmdline);
+  cmdline = NULL;
+  bootdev_set = 0;
+
+  for (cur = modules; cur; cur = next)
+    {
+      next = cur->next;
+      grub_free (cur->cmdline);
+      grub_free (cur);
+    }
+  modules = NULL;
+  modules_last = NULL;
+}
+
+grub_err_t
+grub_multiboot_init_mbi (int argc, char *argv[])
+{
+  grub_ssize_t len = 0;
+  char *p;
+  int i;
+
+  grub_multiboot_free_mbi ();
+
+  for (i = 0; i < argc; i++)
+    len += grub_strlen (argv[i]) + 1;
+  if (len == 0)
+    len = 1;
+
+  cmdline = p = grub_malloc (len);
+  if (! cmdline)
+    return grub_errno;
+  cmdline_size = len;
+
+  for (i = 0; i < argc; i++)
+    {
+      p = grub_stpcpy (p, argv[i]);
+      *(p++) = ' ';
+    }
+
+  /* Remove the space after the last word.  */
+  if (p != cmdline)
+    p--;
+  *p = '\0';
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
+                          int argc, char *argv[])
+{
+  struct module *newmod;
+  char *p;
+  grub_ssize_t len = 0;
+  int i;
+
+  newmod = grub_malloc (sizeof (*newmod));
+  if (!newmod)
+    return grub_errno;
+  newmod->start = start;
+  newmod->size = size;
+
+  for (i = 0; i < argc; i++)
+    len += grub_strlen (argv[i]) + 1;
+
+  if (len == 0)
+    len = 1;
+
+  newmod->cmdline = p = grub_malloc (len);
+  if (! newmod->cmdline)
+    {
+      grub_free (newmod);
+      return grub_errno;
+    }
+  newmod->cmdline_size = len;
+  total_modcmd += ALIGN_UP (len, 4);
+
+  for (i = 0; i < argc; i++)
+    {
+      p = grub_stpcpy (p, argv[i]);
+      *(p++) = ' ';
+    }
+
+  /* Remove the space after the last word.  */
+  if (p != newmod->cmdline)
+    p--;
+  *p = '\0';
+
+  if (modules_last)
+    modules_last->next = newmod;
+  else
+    {
+      modules = newmod;
+      modules_last->next = NULL;
+    }
+  modules_last = newmod;
+
+  modcnt++;
+
+  return GRUB_ERR_NONE;
+}
+
+void
+grub_multiboot_set_bootdev (void)
+{
+  char *p;
+  grub_device_t dev;
+
+  slice = ~0;
+  part = ~0;
+
+#ifdef GRUB_MACHINE_PCBIOS
+  biosdev = grub_get_root_biosnumber ();
+#else
+  biosdev = 0xffffffff;
+#endif
+
+  dev = grub_device_open (0);
+  if (dev && dev->disk && dev->disk->partition)
+    {
+
+      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
+      if (p)
+       {
+         if ((p[0] >= '0') && (p[0] <= '9'))
+           {
+             slice = grub_strtoul (p, &p, 0) - 1;
+
+             if ((p) && (p[0] == ','))
+               p++;
+           }
+
+         if ((p[0] >= 'a') && (p[0] <= 'z'))
+           part = p[0] - 'a';
+       }
+    }
+  if (dev)
+    grub_device_close (dev);
+
+  bootdev_set = 1;
+}