grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC] Tagged mbi


From: Vladimir 'φ-coder/phcoder' Serbinenko
Subject: [RFC] Tagged mbi
Date: Mon, 04 Jan 2010 22:12:51 +0100
User-agent: Mozilla-Thunderbird 2.0.0.22 (X11/20091109)

Hello. Currently mbi contains a lot of pointers and substructures. It's
has various problems like:
-Unused fields occupy space if any subsequent fields is used.
-Difficult to relocate since it may be spilled all over the memory
-It's unstraightforward to e.g. specify 2 framebuffers
I propose to use tagged MBI. I attach proposed patch for multiboot and
grub2. Patch for grub2 is based on my efiboot branch
The patched branches are available under people/phcoder/mbtag-spec and
people/phcoder/taggedmbi.
The parts for which I haven't defined tagged equivalent yet:
-Symbols
-ROM information table
-Drives table
-APM table

-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko

=== modified file 'include/grub/i386/multiboot.h'
--- include/grub/i386/multiboot.h       2009-12-17 23:59:02 +0000
+++ include/grub/i386/multiboot.h       2010-01-02 02:04:52 +0000
@@ -39,4 +39,7 @@
 void grub_multiboot_set_bootdev (void);
 void grub_multiboot_set_accepts_video (int val);
 
+void grub_multiboot_set_tagged (int val);
+int grub_multiboot_get_tagged (void);
+
 #endif /* ! GRUB_MULTIBOOT_CPU_HEADER */

=== modified file 'include/multiboot.h'
--- include/multiboot.h 2010-01-02 17:50:06 +0000
+++ include/multiboot.h 2010-01-02 21:06:42 +0000
@@ -31,8 +31,11 @@
 /* This should be in %eax.  */
 #define MULTIBOOT_BOOTLOADER_MAGIC             0x2BADB002
 
+/* This should be in %eax.  */
+#define MULTIBOOT_BOOTLOADER_MAGIC_TAGGED      0x3BADB002
+
 /* The bits in the required part of flags field we don't support.  */
-#define MULTIBOOT_UNSUPPORTED                   0x0000fff8
+#define MULTIBOOT_UNSUPPORTED                   0x0000fff0
 
 /* Alignment of multiboot modules.  */
 #define MULTIBOOT_MOD_ALIGN                    0x00001000
@@ -51,6 +54,9 @@
 /* Must pass video information to OS.  */
 #define MULTIBOOT_VIDEO_MODE                   0x00000004
 
+/* Must pass tagged mbi to OS.  */
+#define MULTIBOOT_TAGGED_MBI                   0x00000008
+
 /* This flag indicates the use of the address fields in the header.  */
 #define MULTIBOOT_AOUT_KLUDGE                  0x00010000
 
@@ -254,6 +260,114 @@
 };
 typedef struct multiboot_mod_list multiboot_module_t;
 
+struct multiboot_tag
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+};
+
+struct multiboot_tag_string
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  char string[0];
+};
+
+struct multiboot_tag_module
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t mod_start;
+  multiboot_uint32_t mod_end;
+  char cmdline[0];
+};
+
+struct multiboot_tag_basic_meminfo
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t mem_lower;
+  multiboot_uint32_t mem_upper;
+};
+
+struct multiboot_tag_bootdev
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t biosdev;
+  multiboot_uint32_t slice;
+  multiboot_uint32_t part;
+};
+
+struct multiboot_tag_mmap
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  struct multiboot_mmap_entry entries[0];  
+};
+
+#include <grub/i386/pc/vbe.h>
+
+struct multiboot_tag_vbe
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+
+  multiboot_uint16_t vbe_mode;
+  multiboot_uint16_t vbe_interface_seg;
+  multiboot_uint16_t vbe_interface_off;
+  multiboot_uint16_t vbe_interface_len;
+
+  struct grub_vbe_info_block vbe_control_info;
+  struct grub_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;
+  multiboot_uint32_t framebuffer_height;
+  multiboot_uint8_t framebuffer_bpp;
+  multiboot_uint8_t framebuffer_type;
+};
+
+struct multiboot_tag_framebuffer
+{
+  struct multiboot_tag_framebuffer_common common;
+
+  union
+  {
+    struct
+    {
+      multiboot_uint16_t framebuffer_palette_num_colors;
+      struct multiboot_color framebuffer_palette[0];
+    };
+    struct
+    {
+      multiboot_uint8_t framebuffer_red_field_position;
+      multiboot_uint8_t framebuffer_red_mask_size;
+      multiboot_uint8_t framebuffer_green_field_position;
+      multiboot_uint8_t framebuffer_green_mask_size;
+      multiboot_uint8_t framebuffer_blue_field_position;
+      multiboot_uint8_t framebuffer_blue_mask_size;
+    };
+  };
+};
+
+#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
+
 #endif /* ! ASM_FILE */
 
 #endif /* ! MULTIBOOT_HEADER */

=== modified file 'loader/i386/multiboot.c'
--- loader/i386/multiboot.c     2010-01-02 17:50:06 +0000
+++ loader/i386/multiboot.c     2010-01-02 21:57:30 +0000
@@ -62,7 +62,6 @@
   grub_err_t err;
   struct grub_relocator32_state state =
     {
-      .eax = MULTIBOOT_BOOTLOADER_MAGIC,
       .ecx = 0,
       .edx = 0,
       .eip = grub_multiboot_payload_eip,
@@ -71,6 +70,11 @@
       .esp = 0x7ff00
     };
 
+  if (grub_multiboot_get_tagged ())
+    state.eax = MULTIBOOT_BOOTLOADER_MAGIC_TAGGED;
+  else
+    state.eax = MULTIBOOT_BOOTLOADER_MAGIC;
+
   mbi_size = grub_multiboot_get_mbi_size ();
   if (alloc_mbi < mbi_size)
     {
@@ -197,6 +201,9 @@
   /* Skip filename.  */
   grub_multiboot_init_mbi (argc - 1, argv + 1);
 
+  if (header->flags & MULTIBOOT_TAGGED_MBI)
+    grub_multiboot_set_tagged (1);
+
   if (header->flags & MULTIBOOT_AOUT_KLUDGE)
     {
       int offset = ((char *) header - buffer -

=== modified file 'loader/i386/multiboot_mbi.c'
--- loader/i386/multiboot_mbi.c 2010-01-02 20:54:52 +0000
+++ loader/i386/multiboot_mbi.c 2010-01-02 21:01:58 +0000
@@ -55,9 +55,10 @@
 static grub_size_t total_modcmd;
 static unsigned modcnt;
 static char *cmdline = NULL;
-static grub_uint32_t bootdev;
 static int bootdev_set;
 static int accepts_video;
+static int tagged;
+static grub_uint32_t biosdev, slice, part;
 
 void
 grub_multiboot_set_accepts_video (int val)
@@ -65,6 +66,18 @@
   accepts_video = val;
 }
 
+void
+grub_multiboot_set_tagged (int val)
+{
+  tagged = val;
+}
+
+int
+grub_multiboot_get_tagged (void)
+{
+  return tagged;
+}
+
 /* Return the length of the Multiboot mmap that will be needed to allocate
    our platform's map.  */
 static grub_uint32_t
@@ -89,12 +102,23 @@
 grub_size_t
 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 ()
-    + sizeof (struct grub_vbe_info_block)
-    + sizeof (struct grub_vbe_mode_info_block)
-    + 256 * sizeof (struct multiboot_color);
+  if (tagged)
+    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);
+  else
+    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 ()
+      + sizeof (struct grub_vbe_info_block)
+      + sizeof (struct grub_vbe_mode_info_block)
+      + 256 * sizeof (struct multiboot_color);
 }
 
 /* Fill previously allocated Multiboot mmap.  */
@@ -158,40 +182,67 @@
 
 #if HAS_VBE
 static grub_err_t
-fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig,
-              grub_uint32_t ptrdest)
+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;
-  grub_uint32_t vbe_mode;
   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.");
-  
-  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);
-  
+
+  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;
+  *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;
 
-  status = grub_vbe_bios_get_mode_info (vbe_mode, scratch);
+  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;
+}
+
+static grub_err_t
+fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig,
+              grub_uint32_t ptrdest)
+{
+  struct grub_vbe_info_block *vbe_control_info;
+  struct grub_vbe_mode_info_block *vbe_mode_info;
+  grub_err_t err;
+
+  vbe_control_info = (struct grub_vbe_info_block *) ptrorig;
+  mbi->vbe_control_info = ptrdest;
+  ptrorig += sizeof (struct grub_vbe_info_block);
+  ptrdest += sizeof (struct grub_vbe_info_block);
+
+  vbe_mode_info = (struct grub_vbe_mode_info_block *) ptrorig;  
   mbi->vbe_mode_info = ptrdest;
-  grub_memcpy (ptrorig, 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 = 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;
 
@@ -276,16 +327,221 @@
   mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
 
 #if HAS_VBE
+  fill_vbe_info (mbi, ptrorig, ptrdest);
+#endif
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+set_video_info_tagged (struct multiboot_tag_framebuffer *tag,
+#if HAS_VBE
+                      int *vbe_active
+#endif
+                      )
+{
+  struct grub_video_palette_data palette[256];
+  grub_err_t err;
+  struct grub_video_mode_info mode_info;
+  void *framebuffer;
+
+  tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
+  tag->common.size = 0;
+    
+  err = set_video_mode ();
+  if (err)
+    return err;
+
+  grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
+    
+#if HAS_VBE
+  {
+    const char *adapter_name;
+    adapter_name = grub_video_get_active_adapter_name ();
+    
+    *vbe_active = ((adapter_name
+                   && grub_strcmp (adapter_name,
+                                   "VESA BIOS Extension Video Driver") == 0)
+                  || (HAS_VGA_TEXT && !adapter_name));
+  }
+#endif
+
+  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
+  if (err)
+    return err;
+  
+  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;
+       }
+    }
+  else
+    {
+      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;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+make_mbi_tagged (void *orig, grub_uint32_t dest, grub_off_t buf_off)
+{
+  grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off;
+#if HAS_VBE
+  int vbe_active = 0;
+#endif
+  grub_err_t err;
+
+  {
+    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;
+    }
+
+  {
+    struct multiboot_tag_framebuffer *tag
+      = (struct multiboot_tag_framebuffer *) ptrorig;
+    err = set_video_info_tagged (tag,
+#if HAS_VBE
+                                &vbe_active
+#endif
+                                );
+    if (err)
+      {
+       grub_print_error ();
+       grub_errno = GRUB_ERR_NONE;
+      }
+    else
+      ptrorig += tag->common.size;
+  }
+
+#if HAS_VBE
   if (vbe_active)
-    fill_vbe_info (mbi, ptrorig, ptrdest);
+    {
+      struct multiboot_tag_vbe *tag = (struct multiboot_tag_vbe *) ptrorig;
+      tag->type = MULTIBOOT_TAG_TYPE_VBE;
+      tag->size = sizeof (struct multiboot_tag_vbe);
+      err = fill_vbe_info_real (&(tag->vbe_control_info),
+                               &(tag->vbe_mode_info),
+                               &(tag->vbe_mode),
+                               &(tag->vbe_interface_seg),
+                               &(tag->vbe_interface_off),
+                               &(tag->vbe_interface_len));
+      if (err)
+       {
+         grub_print_error ();
+         grub_errno = GRUB_ERR_NONE;
+       }
+      else
+       ptrorig += tag->size;
+    }
 #endif
+  
+  {
+    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;
 }
 
-grub_err_t
-grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
-                        grub_size_t bufsize)
+static grub_err_t
+make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off)
 {
   grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off;
   grub_uint32_t ptrdest = dest + buf_off;
@@ -296,9 +552,6 @@
   grub_size_t mmap_size;
   grub_err_t err;
 
-  if (bufsize < grub_multiboot_get_mbi_size ())
-    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small");
-
   mbi = (struct multiboot_info *) ptrorig;
   ptrorig += sizeof (*mbi);
   ptrdest += sizeof (*mbi);
@@ -356,7 +609,8 @@
 
   if (bootdev_set)
     {
-      mbi->boot_device = bootdev;
+      mbi->boot_device = (((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) 
+                         | ((part & 0xff) << 8) | 0xff);
       mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
     }
 
@@ -374,6 +628,19 @@
   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)
+{
+  if (bufsize < grub_multiboot_get_mbi_size ())
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small");
+
+  if (tagged)
+    return make_mbi_tagged (orig, dest, buf_off);
+  else
+    return make_mbi (orig, dest, buf_off);
+}
+
 void
 grub_multiboot_free_mbi (void)
 {
@@ -403,6 +670,7 @@
   char *p;
   int i;
 
+  tagged = 0;
   grub_multiboot_free_mbi ();
 
   for (i = 0; i < argc; i++)
@@ -486,9 +754,11 @@
 grub_multiboot_set_bootdev (void)
 {
   char *p;
-  grub_uint32_t biosdev, slice = ~0, part = ~0;
   grub_device_t dev;
 
+  slice = ~0;
+  part = ~0;
+
 #ifdef GRUB_MACHINE_PCBIOS
   biosdev = grub_get_root_biosnumber ();
 #else
@@ -517,7 +787,5 @@
   if (dev)
     grub_device_close (dev);
 
-  bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) 
-    | ((part & 0xff) << 8) | 0xff;
   bootdev_set = 1;
 }

=== modified file 'doc/boot.S'
--- doc/boot.S  2010-01-02 17:52:11 +0000
+++ doc/boot.S  2010-01-04 19:44:53 +0000
@@ -30,9 +30,9 @@
 
 /* The flags for the Multiboot header.  */
 #ifdef __ELF__
-# define MULTIBOOT_HEADER_FLAGS                0x00000007
+# define MULTIBOOT_HEADER_FLAGS                0x0000000f
 #else
-# define MULTIBOOT_HEADER_FLAGS                0x00010007
+# define MULTIBOOT_HEADER_FLAGS                0x0001000f
 #endif
        
        .text

=== modified file 'doc/kernel.c'
--- doc/kernel.c        2010-01-02 17:52:11 +0000
+++ doc/kernel.c        2010-01-04 19:43:33 +0000
@@ -47,6 +47,153 @@
 static void putchar (int c);
 void printf (const char *format, ...);
 
+static void
+tagged (unsigned long addr)
+{
+  struct multiboot_tag *tag;
+
+  for (tag = (struct multiboot_tag *) addr; tag->type != 
MULTIBOOT_TAG_TYPE_END;
+       tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag + tag->size))
+    {
+      printf ("Tag 0x%x, Size 0x%x\n", tag->type, tag->size);
+      switch (tag->type)
+       {
+       case MULTIBOOT_TAG_TYPE_CMDLINE:
+         printf ("Command line = %s\n",
+                 ((struct multiboot_tag_string *) tag)->string);
+         break;
+       case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
+         printf ("Boot loader name = %s\n",
+                 ((struct multiboot_tag_string *) tag)->string);
+         break;
+       case MULTIBOOT_TAG_TYPE_MODULE:
+         printf ("Module at 0x%x-0x%x. Command line %s\n",
+                 ((struct multiboot_tag_module *) tag)->mod_start,
+                 ((struct multiboot_tag_module *) tag)->mod_end,
+                 ((struct multiboot_tag_module *) tag)->cmdline);
+         break;
+       case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
+         printf ("mem_lower = %uKB, mem_upper = %uKB\n",
+                 ((struct multiboot_tag_basic_meminfo *) tag)->mem_lower,
+                 ((struct multiboot_tag_basic_meminfo *) tag)->mem_upper);
+         break;
+       case MULTIBOOT_TAG_TYPE_BOOTDEV:
+         printf ("Boot device 0x%x,%u,%u\n",
+                 ((struct multiboot_tag_bootdev *) tag)->biosdev,
+                 ((struct multiboot_tag_bootdev *) tag)->slice,
+                 ((struct multiboot_tag_bootdev *) tag)->part);
+         break;
+       case MULTIBOOT_TAG_TYPE_MMAP:
+         {
+           multiboot_memory_map_t *mmap;
+
+           printf ("mmap\n");
+      
+           for (mmap = ((struct multiboot_tag_mmap *) tag)->entries;
+                (multiboot_uint8_t *) mmap 
+                  < (multiboot_uint8_t *) tag + tag->size;
+                mmap = (multiboot_memory_map_t *) ((unsigned long) mmap
+                                                   + mmap->size
+                                                   + sizeof (mmap->size)))
+             printf (" size = 0x%x, base_addr = 0x%x%x,"
+                     " length = 0x%x%x, type = 0x%x\n",
+                     (unsigned) mmap->size,
+                     (unsigned) (mmap->addr >> 32),
+                     (unsigned) (mmap->addr & 0xffffffff),
+                     (unsigned) (mmap->len >> 32),
+                     (unsigned) (mmap->len & 0xffffffff),
+                     (unsigned) mmap->type);
+         }
+         break;
+       case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
+         {
+           multiboot_uint32_t color;
+           unsigned i;
+           struct multiboot_tag_framebuffer *tagfb
+             = (struct multiboot_tag_framebuffer *) tag;
+           void *fb = (void *) (unsigned long) tagfb->common.framebuffer_addr;
+
+           switch (tagfb->common.framebuffer_type)
+             {
+             case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
+               {
+                 unsigned best_distance, distance;
+                 struct multiboot_color *palette;
+           
+                 palette = tagfb->framebuffer_palette;
+
+                 color = 0;
+                 best_distance = 4*256*256;
+           
+                 for (i = 0; i < tagfb->framebuffer_palette_num_colors; i++)
+                   {
+                     distance = (0xff - palette[i].blue) 
+                       * (0xff - palette[i].blue)
+                       + palette[i].red * palette[i].red
+                       + palette[i].green * palette[i].green;
+                     if (distance < best_distance)
+                       {
+                         color = i;
+                         best_distance = distance;
+                       }
+                   }
+               }
+               break;
+
+             case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
+               color = ((1 << tagfb->framebuffer_blue_mask_size) - 1) 
+                 << tagfb->framebuffer_blue_field_position;
+               break;
+
+             default:
+               color = 0xffffffff;
+               break;
+             }
+           
+           for (i = 0; i < tagfb->common.framebuffer_width
+                  && i < tagfb->common.framebuffer_height; i++)
+             {
+               switch (tagfb->common.framebuffer_bpp)
+                 {
+                 case 8:
+                   {
+                     multiboot_uint8_t *pixel = fb
+                       + tagfb->common.framebuffer_pitch * i + i;
+                     *pixel = color;
+                   }
+                   break;
+                 case 15:
+                 case 16:
+                   {
+                     multiboot_uint16_t *pixel
+                       = fb + tagfb->common.framebuffer_pitch * i + 2 * i;
+                     *pixel = color;
+                   }
+                   break;
+                 case 24:
+                   {
+                     multiboot_uint32_t *pixel
+                       = fb + tagfb->common.framebuffer_pitch * i + 3 * i;
+                     *pixel = (color & 0xffffff) | (*pixel & 0xff000000);
+                   }
+                   break;
+
+                 case 32:
+                   {
+                     multiboot_uint32_t *pixel
+                       = fb + tagfb->common.framebuffer_pitch * i + 4 * i;
+                     *pixel = color;
+                   }
+                   break;
+                 }
+             }
+           break;
+         }
+       }
+    }
+}
+
+
 /* Check if MAGIC is valid and print the Multiboot information structure
    pointed by ADDR.  */
 void
@@ -57,6 +204,12 @@
   /* Clear the screen.  */
   cls ();
 
+  if (magic == MULTIBOOT_BOOTLOADER_MAGIC_TAGGED)
+    {
+      tagged (addr);
+      return;
+    }
+
   /* Am I booted by a Multiboot-compliant boot loader?  */
   if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
     {

=== modified file 'doc/multiboot.h'
--- doc/multiboot.h     2010-01-02 17:52:11 +0000
+++ doc/multiboot.h     2010-01-04 20:35:55 +0000
@@ -31,8 +31,11 @@
 /* This should be in %eax.  */
 #define MULTIBOOT_BOOTLOADER_MAGIC             0x2BADB002
 
+/* This should be in %eax.  */
+#define MULTIBOOT_BOOTLOADER_MAGIC_TAGGED      0x3BADB002
+
 /* The bits in the required part of flags field we don't support.  */
-#define MULTIBOOT_UNSUPPORTED                   0x0000fff8
+#define MULTIBOOT_UNSUPPORTED                   0x0000fff0
 
 /* Alignment of multiboot modules.  */
 #define MULTIBOOT_MOD_ALIGN                    0x00001000
@@ -51,6 +54,9 @@
 /* Must pass video information to OS.  */
 #define MULTIBOOT_VIDEO_MODE                   0x00000004
 
+/* Must pass tagged mbi to OS.  */
+#define MULTIBOOT_TAGGED_MBI                   0x00000008
+
 /* This flag indicates the use of the address fields in the header.  */
 #define MULTIBOOT_AOUT_KLUDGE                  0x00010000
 
@@ -254,6 +260,122 @@
 };
 typedef struct multiboot_mod_list multiboot_module_t;
 
+struct multiboot_tag
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+};
+
+struct multiboot_tag_string
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  char string[0];
+};
+
+struct multiboot_tag_module
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t mod_start;
+  multiboot_uint32_t mod_end;
+  char cmdline[0];
+};
+
+struct multiboot_tag_basic_meminfo
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t mem_lower;
+  multiboot_uint32_t mem_upper;
+};
+
+struct multiboot_tag_bootdev
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t biosdev;
+  multiboot_uint32_t slice;
+  multiboot_uint32_t part;
+};
+
+struct multiboot_tag_mmap
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  struct multiboot_mmap_entry entries[0];  
+};
+
+struct multiboot_vbe_info_block
+{
+  multiboot_uint8_t external_specification[512];
+};
+
+struct multiboot_vbe_mode_info_block
+{
+  multiboot_uint8_t external_specification[256];
+};
+
+struct multiboot_tag_vbe
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+
+  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;
+  multiboot_uint32_t framebuffer_height;
+  multiboot_uint8_t framebuffer_bpp;
+  multiboot_uint8_t framebuffer_type;
+};
+
+struct multiboot_tag_framebuffer
+{
+  struct multiboot_tag_framebuffer_common common;
+
+  union
+  {
+    struct
+    {
+      multiboot_uint16_t framebuffer_palette_num_colors;
+      struct multiboot_color framebuffer_palette[0];
+    };
+    struct
+    {
+      multiboot_uint8_t framebuffer_red_field_position;
+      multiboot_uint8_t framebuffer_red_mask_size;
+      multiboot_uint8_t framebuffer_green_field_position;
+      multiboot_uint8_t framebuffer_green_mask_size;
+      multiboot_uint8_t framebuffer_blue_field_position;
+      multiboot_uint8_t framebuffer_blue_mask_size;
+    };
+  };
+};
+
+#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
+
 #endif /* ! ASM_FILE */
 
 #endif /* ! MULTIBOOT_HEADER */

=== modified file 'doc/multiboot.texi'
--- doc/multiboot.texi  2010-01-04 19:44:39 +0000
+++ doc/multiboot.texi  2010-01-04 21:05:10 +0000
@@ -414,6 +414,9 @@
 mode table (@pxref{Boot information format}) must be available to the
 kernel.
 
+If bit 3 in the @samp{flags} word is set, the multiboot information 
+must be in tagged format.
+
 If bit 16 in the @samp{flags} word is set, then the fields at offsets
 12-28 in the Multiboot header are valid, and the boot loader should use
 them instead of the fields in the actual executable header to calculate
@@ -515,7 +518,7 @@
 
 @table @samp
 @item EAX
-Must contain the magic value @samp{0x2BADB002}; the presence of this
+Must contain the magic value @samp{0x2BADB002} if Boot info is non-tagged and 
@samp{0x3BADB002} otherwise; the presence of this
 value indicates to the operating system that it was loaded by a
 Multiboot-compliant boot loader (e.g. as opposed to another type of
 boot loader that the operating system can also be loaded from).
@@ -578,9 +581,8 @@
 
 
 @node Boot information format
address@hidden Boot information format
-
-FIXME: Split this chapter like the chapter ``OS image format''.
address@hidden Boot information
address@hidden Boot information format
 
 Upon entry to the operating system, the @code{EBX} register contains the
 physical address of a @dfn{Multiboot information} data structure,
@@ -595,6 +597,25 @@
 operating system's responsibility to avoid overwriting this memory until
 it is done using it.
 
address@hidden Basic tags structure
+Boot information can be passed in one of two formats: pointer-based
+or tag-based. Tag-based format must be used if and only it was requested
+in multiboot header. Every tag begins with following fields:
+
address@hidden
address@hidden
+        +-------------------+
+0       | type              |
+4-7     | size              |
+        +-------------------+
address@hidden group
address@hidden example
+
address@hidden contains an identifier of contents of the rest of the tag.
address@hidden contains the size of tag including header fields.
+Tags follow one another without any gaps. Tags are terminated by a tag of type 
@samp{0} and size @samp{8}.
+
address@hidden Basic non-tagged structure
 The format of the Multiboot information structure (as defined so far)
 follows:
 
@@ -655,6 +676,7 @@
 information structure to be expanded in the future without breaking
 anything.
 
address@hidden Basic memory information
 If bit 0 in the @samp{flags} word is set, then the @samp{mem_*} fields
 are valid. @samp{mem_lower} and @samp{mem_upper} indicate the amount of
 lower and upper memory, respectively, in kilobytes. Lower memory starts
@@ -663,6 +685,20 @@
 upper memory is maximally the address of the first upper memory hole
 minus 1 megabyte. It is not guaranteed to be this value.
 
+Corresponding tag is:
+
address@hidden
address@hidden
+        +-------------------+
+0       | type = 4          |
+4       | size = 16         |
+8       | mem_lower         |
+12-15   | mem_upper         |
+        +-------------------+
address@hidden group
address@hidden example
+
address@hidden BIOS Boot device
 If bit 1 in the @samp{flags} word is set, then the @samp{boot_device}
 field is valid, and indicates which @sc{bios} disk device the boot
 loader loaded the OS image from. If the OS image was not loaded from a
@@ -705,11 +741,39 @@
 @samp{part1} will be 5, and @samp{part2} and @samp{part3} will both be
 0xFF.
 
+Corresponding tag is:
address@hidden
address@hidden
+        +-------------------+
+0       | type = 5          |
+4       | size = 20         |
+8       | biosdev           |
+12      | partition         |
+16-19   | sub-parition      |
+        +-------------------+
address@hidden group
address@hidden example
+
address@hidden Boot command line
 If bit 2 of the @samp{flags} longword is set, the @samp{cmdline} field
 is valid, and contains the physical address of the command line to
 be passed to the kernel. The command line is a normal C-style
-zero-terminated string.
-
+UTF-8 zero-terminated string.
+
+Corresponding tag is:
address@hidden
address@hidden
+        +-------------------+
+0       | type = 1          |
+4       | size              |
+8-xx    | string            |
+        +-------------------+
address@hidden group
address@hidden example
+
address@hidden contains zero-terminated UTF-8 string padded to have length 
divisible by 4.
+
address@hidden Modules
 If bit 3 of the @samp{flags} is set, then the @samp{mods} fields
 indicate to the kernel what boot modules were loaded along with the
 kernel image, and where they can be found. @samp{mods_count} contains
@@ -734,7 +798,7 @@
 The first two fields contain the start and end addresses of the boot
 module itself. The @samp{string} field provides an arbitrary string to
 be associated with that particular boot module; it is a zero-terminated
-ASCII string, just like the kernel command line. The @samp{string} field
+UTF-8 string, just like the kernel command line. The @samp{string} field
 may be 0 if there is no string associated with the module. Typically the
 string might be a command line (e.g. if the operating system treats boot
 modules as executable programs), or a pathname (e.g. if the operating
@@ -742,6 +806,25 @@
 is specific to the operating system. The @samp{reserved} field must be
 set to 0 by the boot loader and ignored by the operating system.
 
+Corresponding tag is:
+
address@hidden
address@hidden
+        +-------------------+
+0       | type = 3          |
+4       | size              |
+8       | mod_start         |
+12      | mod_end           |
+16-xx   | string            |   
+        +-------------------+
address@hidden group
address@hidden example
+
+Tag is padded in the way to have size divisible by 4.
+
+One tag appears per module.
+
address@hidden Symbols
 @strong{Caution:} Bits 4 & 5 are mutually exclusive.
 
 If bit 4 in the @samp{flags} word is set, then the following fields in
@@ -795,6 +878,7 @@
 @samp{shdr_num} may be 0, indicating no symbols, even if bit 5 in the
 @samp{flags} word is set.
 
address@hidden Memory map
 If bit 6 in the @samp{flags} word is set, then the @samp{mmap_*} fields
 are valid, and indicate the address and length of a buffer containing a
 memory map of the machine provided by the @sc{bios}. @samp{mmap_addr} is
@@ -824,6 +908,18 @@
 The map provided is guaranteed to list all standard @sc{ram} that should
 be available for normal use.
 
+The corresponding tag is
address@hidden
address@hidden
+        +-------------------+
+0       | type = 6          |
+4       | size              |
+8-xx    | entries           |
+        +-------------------+
address@hidden group
address@hidden example
+
address@hidden Drives table
 If bit 7 in the @samp{flags} is set, then the @samp{drives_*} fields
 are valid, and indicate the address of the physical address of the first
 drive structure and the size of drive structures. @samp{drives_addr}
@@ -878,16 +974,32 @@
 array may contain any number of I/O ports that are not related to the
 drive actually (such as @sc{dma} controller's ports).
 
address@hidden Configuration table
 If bit 8 in the @samp{flags} is set, then the @samp{config_table} field
 is valid, and indicates the address of the @sc{rom} configuration table
 returned by the @dfn{GET CONFIGURATION} @sc{bios} call. If the @sc{bios}
 call fails, then the size of the table must be @emph{zero}.
 
address@hidden Boot loader name
 If bit 9 in the @samp{flags} is set, the @samp{boot_loader_name} field
 is valid, and contains the physical address of the name of a boot
 loader booting the kernel. The name is a normal C-style zero-terminated
 string.
 
+Corresponding tag is:
address@hidden
address@hidden
+        +-------------------+
+0       | type = 2          |
+4       | size              |
+8-xx    | string            |
+        +-------------------+
address@hidden group
address@hidden example
+
address@hidden contains zero-terminated UTF-8 string padded to have length 
divisible by 4.
+
address@hidden APM table
 If bit 10 in the @samp{flags} is set, the @samp{apm_table} field is
 valid, and contains the physical address of an @sc{apm} table defined as
 below:
@@ -920,6 +1032,7 @@
 @uref{http://www.microsoft.com/hwdev/busbios/amp_12.htm, Advanced Power
 Management (APM) BIOS Interface Specification}, for more information.
 
address@hidden VBE info
 If bit 11 in the @samp{flags} is set, the @sc{vbe} table is available.
 
 The fields @samp{vbe_control_info} and @samp{vbe_mode_info} contain
@@ -942,6 +1055,25 @@
 Multiboot boot loaders may simulate @sc{vbe} on address@hidden modes, as
 if they were @sc{vbe} modes.
 
+Corresponding tag is:
address@hidden
address@hidden
+        +-------------------+
+0       | type = 7          |
+4       | size = 784        |
+8       | vbe_mode          |
+10      | vbe_interface_seg |
+12      | vbe_interface_off |
+14      | vbe_interface_len |
+16      | vbe_control_info  |
+528-783 | vbe_mode_info     |
+        +-------------------+
address@hidden group
address@hidden example
+
+Notice that the tag contains VBE control and mode information structures 
directly rather than a pointer to them
+
address@hidden Framebuffer info
 If bit 12 in the @samp{flags} is set, the @sc{Framebuffer} table is available.
 
 The field @samp{framebuffer_addr} contains framebuffer physical address. This 
field is 64-bit wide but bootloader @dfn{should} set it under 4GiB if possible 
for compatibility with payloads which aren't aware of PAE or amd64. The field 
@samp{framebuffer_pitch} contains pitch in bytes. The fields 
@samp{framebuffer_width}, @samp{framebuffer_height} contain framebuffer 
dimensions in pixels. The field @samp{framebuffer_bpp} contains number of bits 
per pixel. If @samp{framebuffer_type} is set to 0 it means indexed color. In 
this case color_info is defined as follows:
@@ -959,7 +1091,7 @@
         +-------------+
 0       | red_value   |
 1       | green_value |
-2       | blue_value  |
+2-2     | blue_value  |
         +-------------+
 @end group
 @end example
@@ -981,6 +1113,40 @@
 If @samp{framebuffer_type} is set to 2 it means EGA text. In this case 
@samp{framebuffer_width} and @samp{framebuffer_height} are expressed in 
characters and not in pixels. @samp{framebuffer_bpp} is equal 16 (16 bits per 
character) and @samp{framebuffer_pitch} is expressed in bytes per text line.
 All further values of @samp{framebuffer_type} are reserved for future expansion
 
+Corresponding tag is:
address@hidden
address@hidden
+        +--------------------+
+0       | type = 8           |
+4       | size               |
+8       | framebuffer_addr   |
+16      | framebuffer_pitch  |
+20      | framebuffer_width  |
+24      | framebuffer_height |
+28      | framebuffer_bpp    |
+29      | framebuffer_type   |
+30      | color_info         |
+        +--------------------+
address@hidden group
address@hidden example
+
+If @samp{framebuffer_type} is @samp{0} color_info has the following format:
+
address@hidden
address@hidden
+        +---------------------------------+
+0       | framebuffer_palette_num_colors  |
+4-xx    | framebuffer_palette             |
+        +---------------------------------+
address@hidden group
address@hidden example
+
+With @samp{framebuffer_palette_num_colors} and @samp{framebuffer_palette} 
having the same format as in non-tagged version
+
+Note: @samp{framebuffer_palette} contains the palette and not its address.
+
+If @samp{framebuffer_type} is @samp{1} or @samp{2}  color_info has the same 
format as non-tagged version.
+
 @node Examples
 @chapter Examples
 

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]