grub-devel
[Top][All Lists]
Advanced

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

Re: [RFC] Multiboot ammendment: non-VBE video


From: Vladimir 'φ-coder/phcoder' Serbinenko
Subject: Re: [RFC] Multiboot ammendment: non-VBE video
Date: Sat, 02 Jan 2010 19:26:08 +0100
User-agent: Mozilla-Thunderbird 2.0.0.22 (X11/20091109)

Robert Millan wrote:
> On Mon, Dec 28, 2009 at 01:07:10PM +0100, Vladimir 'φ-coder/phcoder' 
> Serbinenko wrote:
>   
>> Robert Millan wrote:
>>     
>>> On Tue, Sep 01, 2009 at 05:37:11PM +0200, Vladimir 'phcoder' Serbinenko 
>>> wrote:
>>>   
>>>       
>>>> Hello. I'm implementing video part of multiboot specification.
>>>> Currently the only defined interface is for providing VBE info. I
>>>> propose following way to set fields if video is non VBE:
>>>> vbe_control_info=0xffffffff
>>>> When vbe_control_info is set to 0xffffffff all VBE-specific fields are 
>>>> invalid
>>>> vbe_mode set to 0xffff
>>>> vbe_interface_seg=0xffff
>>>> vbe_interface_off=0xffff
>>>> vbe_interface_len=0xff
>>>> vbe_mode_info points to structure similar to vbe_mode_info but with
>>>> all vbe-specific fields set to zero. Remaining (valid) fields are
>>>> (full structur is in include/grub/i386/pc/vbe.h)
>>>>     
>>>>         
>>> This seems like one of these cases in which legacy gets in the way.  Why
>>> don't we just replace the legacy structure with something that doesn't need
>>> dummy fields?
>>>   
>>>       
>> Actually it seems like we already define possible dummy fields if
>> vbe_interface isn't available.
>>     
>
> Yes.  That's the case for vbe_interface_* fields.  But extending this to
> vbe_control_info and vbe_mode_info is backward-incompatible.
>
> I don't object to backward-incompatible changes, but I would expect that
> when we make one, we get the benefit of a clean, legacy-free interface.  In
> this case we carry on with legacy baggage to archieve half-way backward
> compatibility.
>
> In purely practical terms, all of this only has a minimal effect.  GRUB Legacy
> didn't implement these extensions, and GRUB 2 hasn't yet, so use of this
> feature in loadees isn't widespread.  But it has a major impact when it comes
> to reputation.  If we make incompatible changes in the text, we should be
> honest about it.  I don't want people to think they can't rely on Multiboot
> because its maintainers sometimes stretch the definitions in ways not
> permitted by the text.
>
> Since it's obvious we want to change something (rather than implement
> VBE-specific extensions), I propose we start with:
>
> -If bit 11 in the @samp{flags} is set, the graphics table is available.
> +If bit 12 in the @samp{flags} is set, the graphics table is available.
>
> at this point, we can change anything we like.
>
>   
I followed your suggestions. I attach new draft together with drawing of
a blue diagonal line in example kernel (it would be way better to make
it use it for output but it's intended to just show how to use passed
info). I also attach an implementation of multiboot on EFI which uses
this draft. Note that this ammendment is nothing EFI-specific and can be
used with any linear framebuffer driver. The only reason it's in the
same patch is because it was the branch in which I was working on
multiboot improvements and haven't yet splitted individual changes yet

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

=== modified file 'doc/boot.S'
--- doc/boot.S  2009-12-24 13:34:49 +0000
+++ doc/boot.S  2010-01-02 17:13:52 +0000
@@ -30,9 +30,9 @@
 
 /* The flags for the Multiboot header.  */
 #ifdef __ELF__
-# define MULTIBOOT_HEADER_FLAGS                0x00000003
+# define MULTIBOOT_HEADER_FLAGS                0x00000007
 #else
-# define MULTIBOOT_HEADER_FLAGS                0x00010003
+# define MULTIBOOT_HEADER_FLAGS                0x00010007
 #endif
        
        .text
@@ -64,7 +64,17 @@
        .long   _end
        /* entry_addr */
        .long   multiboot_entry
-#endif /* ! __ELF__ */
+#else /* ! __ELF__ */
+       .long   0
+       .long   0
+       .long   0
+       .long   0
+       .long   0       
+#endif /* __ELF__ */
+       .long 0
+       .long 1024
+       .long 768
+       .long 32
 
 multiboot_entry:
        /* Initialize the stack pointer.  */

=== modified file 'doc/kernel.c'
--- doc/kernel.c        2009-12-24 14:25:44 +0000
+++ doc/kernel.c        2010-01-02 17:04:15 +0000
@@ -150,6 +150,87 @@
                mmap->len & 0xffffffff,
                (unsigned) mmap->type);
     }
+
+  /* Draw diagonal blue line.  */
+  if (CHECK_FLAG (mbi->flags, 12))
+    {
+      multiboot_uint32_t color;
+      unsigned i;
+      void *fb = (void *) (unsigned long) mbi->framebuffer_addr;
+
+      switch (mbi->framebuffer_type)
+       {
+       case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
+         {
+           unsigned best_distance, distance;
+           struct multiboot_color *palette;
+           
+           palette = (struct multiboot_color *) mbi->framebuffer_palette_addr;
+
+           color = 0;
+           best_distance = 4*256*256;
+           
+           for (i = 0; i < mbi->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 << mbi->framebuffer_blue_mask_size) - 1) 
+           << mbi->framebuffer_blue_field_position;
+         break;
+
+       default:
+         color = 0xffffffff;
+         break;
+       }
+      for (i = 0; i < mbi->framebuffer_width
+            && i < mbi->framebuffer_height; i++)
+       {
+         switch (mbi->framebuffer_bpp)
+           {
+           case 8:
+             {
+               multiboot_uint8_t *pixel = fb + mbi->framebuffer_pitch * i + i;
+               *pixel = color;
+             }
+             break;
+           case 15:
+           case 16:
+             {
+               multiboot_uint16_t *pixel
+                 = fb + mbi->framebuffer_pitch * i + 2 * i;
+               *pixel = color;
+             }
+             break;
+           case 24:
+             {
+               multiboot_uint32_t *pixel
+                 = fb + mbi->framebuffer_pitch * i + 3 * i;
+               *pixel = (color & 0xffffff) | (*pixel & 0xff000000);
+             }
+             break;
+
+           case 32:
+             {
+               multiboot_uint32_t *pixel
+                 = fb + mbi->framebuffer_pitch * i + 4 * i;
+               *pixel = color;
+             }
+             break;
+           }
+       }
+    }
+
 }    
 
 /* Clear the screen and initialize VIDEO, XPOS and YPOS.  */

=== modified file 'doc/multiboot.h'
--- doc/multiboot.h     2009-12-24 14:25:44 +0000
+++ doc/multiboot.h     2010-01-02 12:58:41 +0000
@@ -32,7 +32,7 @@
 #define MULTIBOOT_BOOTLOADER_MAGIC             0x2BADB002
 
 /* The bits in the required part of flags field we don't support.  */
-#define MULTIBOOT_UNSUPPORTED                  0x0000fffc
+#define MULTIBOOT_UNSUPPORTED                   0x0000fff8
 
 /* Alignment of multiboot modules.  */
 #define MULTIBOOT_MOD_ALIGN                    0x00001000
@@ -88,10 +88,12 @@
 #define MULTIBOOT_INFO_APM_TABLE               0x00000400
 
 /* Is there video information?  */
-#define MULTIBOOT_INFO_VIDEO_INFO              0x00000800
+#define MULTIBOOT_INFO_VBE_INFO                        0x00000800
+#define MULTIBOOT_INFO_FRAMEBUFFER_INFO                0x00001000
 
 #ifndef ASM_FILE
 
+typedef unsigned char          multiboot_uint8_t;
 typedef unsigned short         multiboot_uint16_t;
 typedef unsigned int           multiboot_uint32_t;
 typedef unsigned long long     multiboot_uint64_t;
@@ -190,9 +192,43 @@
   multiboot_uint16_t vbe_interface_seg;
   multiboot_uint16_t vbe_interface_off;
   multiboot_uint16_t vbe_interface_len;
+
+  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;
+  union
+  {
+    struct
+    {
+      multiboot_uint32_t framebuffer_palette_addr;
+      multiboot_uint16_t framebuffer_palette_num_colors;
+    };
+    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;
+    };
+  };
+};
+
+struct multiboot_color
+{
+  multiboot_uint8_t red;
+  multiboot_uint8_t green;
+  multiboot_uint8_t blue;
 };
 typedef struct multiboot_info multiboot_info_t;
 
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB     1
+
 struct multiboot_mmap_entry
 {
   multiboot_uint32_t size;

=== modified file 'doc/multiboot.texi'
--- doc/multiboot.texi  2010-01-01 20:02:24 +0000
+++ doc/multiboot.texi  2010-01-02 16:58:33 +0000
@@ -479,7 +479,8 @@
 preferred graphics mode. Note that that is only a @emph{recommended}
 mode by the OS image. If the mode exists, the boot loader should set
 it, when the user doesn't specify a mode explicitly. Otherwise, the
-boot loader should fall back to a similar mode, if available.
+boot loader should fall back to a similar mode, if available. Boot loader
+may also choose another mode if it sees fit.
 
 The meaning of each is as follows:
 
@@ -488,7 +489,9 @@
 Contains @samp{0} for linear graphics mode or @samp{1} for
 EGA-standard text mode. Everything else is reserved for future
 expansion. Note that the boot loader may set a text mode, even if this
-field contains @samp{0}.
+field contains @samp{0}. If video adapter doesn't support EGA text mode or
+bootloader doesn't know how to initialise this mode it may set video
+mode even if field contains @samp{1}
 
 @item width
 Contains the number of the columns. This is specified in pixels in a
@@ -635,6 +638,15 @@
 84      | vbe_interface_off |
 86      | vbe_interface_len |
         +-------------------+
+88      | framebuffer_addr  |    (present if flags[12] is set)
+96      | framebuffer_pitch |
+100     | framebuffer_width |
+104     | framebuffer_height|
+108     | framebuffer_bpp   |
+109     | framebuffer_type  |
+110-115 | color_info        |
+        +-------------------+
+
 @end group
 @end example
 
@@ -911,9 +923,7 @@
 @uref{http://www.microsoft.com/hwdev/busbios/amp_12.htm, Advanced Power
 Management (APM) BIOS Interface Specification}, for more information.
 
-If bit 11 in the @samp{flags} is set, the graphics table is available.
-This must only be done if the kernel has indicated in the
address@hidden Header} that it accepts a graphics mode.
+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
 the physical addresses of @sc{vbe} control information returned by the
@@ -935,6 +945,42 @@
 Multiboot boot loaders may simulate @sc{vbe} on address@hidden modes, as
 if they were @sc{vbe} modes.
 
+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 following:
address@hidden
address@hidden
+        +----------------------------------+
+110     | framebuffer_palette_addr         |
+114     | framebuffer_palette_num_colors   |
+        +----------------------------------+
address@hidden group
address@hidden example
address@hidden contains address of array of 
@samp{framebuffer_palette_num_colors} following structures:
address@hidden
address@hidden
+        +-------------+
+0       | red_value   |
+1       | green_value |
+2       | blue_value  |
+        +-------------+
address@hidden group
address@hidden example
+If @samp{framebuffer_type} is set to 1 it direct RGB color. Then color_type is 
defined as following:
+
address@hidden
address@hidden
+        +----------------------------------+
+110     | framebuffer_red_field_position   |
+111     | framebuffer_red_mask_size        |
+112     | framebuffer_green_field_position |
+113     | framebuffer_green_mask_size      |
+114     | framebuffer_blue_field_position  |
+115     | framebuffer_blue_mask_size       |
+        +----------------------------------+
address@hidden group
address@hidden example
+All further values of @samp{framebuffer_type} are reserved for future expansion
 
 @node Examples
 @chapter Examples

=== added file 'ChangeLog.efiboot'
--- ChangeLog.efiboot   1970-01-01 00:00:00 +0000
+++ ChangeLog.efiboot   2010-01-02 01:48:33 +0000
@@ -0,0 +1,19 @@
+2009-11-28  Vladimir Serbinenko  <address@hidden>
+
+       Multiboot support on i386-efi.
+
+       * conf/i386-efi.rmk (pkglib_MODULES): Add multiboot.mod.
+       (multiboot_mod_SOURCES): New variable.
+       (multiboot_mod_CFLAGS): Likewise.
+       (multiboot_mod_LDFLAGS): Likewise.
+       (multiboot_mod_ASFLAGS): Likewise.
+       * include/grub/i386/multiboot.h (grub_multiboot_real_boot): Explicitly
+       declare as regparm (3).
+       (grub_multiboot2_real_boot): Likewise.
+       (grub_multiboot_boot): Finish boot services.
+       (grub_fill_multiboot_mmap): Explicitly parse memory map types.
+       (grub_multiboot): Declare as noreturn to avoid finishing console.
+       * loader/multiboot_loader.c (grub_cmd_multiboot_loader): Enable
+       multiboot1 on i386-efi and disable multiboot2 on this platform.
+       (grub_cmd_module_loader): Likewise.
+

=== modified file 'conf/i386-coreboot.rmk'
--- conf/i386-coreboot.rmk      2009-12-25 22:06:52 +0000
+++ conf/i386-coreboot.rmk      2010-01-02 01:48:37 +0000
@@ -142,6 +142,7 @@
 
 # For multiboot.mod.
 multiboot_mod_SOURCES = loader/i386/multiboot.c \
+                       loader/i386/multiboot_mbi.c \
                        loader/i386/multiboot_helper.S \
                          loader/i386/pc/multiboot2.c \
                          loader/multiboot2.c \

=== modified file 'conf/i386-efi.rmk'
--- conf/i386-efi.rmk   2009-12-25 22:06:52 +0000
+++ conf/i386-efi.rmk   2010-01-02 01:48:37 +0000
@@ -33,7 +33,15 @@
 pkglib_MODULES = kernel.img chain.mod appleldr.mod \
        linux.mod halt.mod reboot.mod pci.mod lspci.mod \
        datetime.mod date.mod datehook.mod loadbios.mod \
-       fixvideo.mod mmap.mod acpi.mod
+       fixvideo.mod mmap.mod acpi.mod multiboot.mod
+
+# For multiboot.mod.
+multiboot_mod_SOURCES = loader/i386/multiboot.c \
+                       loader/i386/multiboot_mbi.c \
+                        loader/multiboot_loader.c
+multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
+multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
+multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For kernel.img.
 kernel_img_EXPORTS = no

=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk    2009-12-25 22:06:52 +0000
+++ conf/i386-pc.rmk    2010-01-02 01:48:37 +0000
@@ -206,6 +206,7 @@
 
 # For multiboot.mod.
 multiboot_mod_SOURCES = loader/i386/multiboot.c \
+                       loader/i386/multiboot_mbi.c \
                        loader/i386/multiboot_helper.S \
                         loader/i386/pc/multiboot2.c \
                         loader/multiboot2.c \

=== modified file 'conf/x86_64-efi.rmk'
--- conf/x86_64-efi.rmk 2009-12-25 22:06:52 +0000
+++ conf/x86_64-efi.rmk 2010-01-02 01:48:37 +0000
@@ -172,4 +172,13 @@
 relocator_mod_ASFLAGS = $(COMMON_ASFLAGS)
 relocator_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For multiboot.mod.
+pkglib_MODULES += multiboot.mod
+multiboot_mod_SOURCES = loader/i386/multiboot.c \
+                        loader/multiboot_loader.c \
+                       loader/i386/multiboot_mbi.c
+multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
+multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
+multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS)
+
 include $(srcdir)/conf/common.mk

=== modified file 'include/grub/i386/multiboot.h'
--- include/grub/i386/multiboot.h       2009-12-13 18:37:44 +0000
+++ include/grub/i386/multiboot.h       2010-01-02 01:48:33 +0000
@@ -20,16 +20,23 @@
 #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));
+     __attribute__ ((noreturn,regparm (3)));
 
 extern grub_uint32_t grub_multiboot_payload_eip;
 extern char *grub_multiboot_payload_orig;
 extern grub_addr_t grub_multiboot_payload_dest;
-extern grub_size_t grub_multiboot_payload_size;
+extern grub_size_t grub_multiboot_pure_size;
+
+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);
+void grub_multiboot_free_mbi (void);
+grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]);
+grub_err_t grub_multiboot_add_module (grub_off_t start, grub_size_t size,
+                                     int argc, char *argv[]);
+void grub_multiboot_set_bootdev (void);
+void grub_multiboot_set_accepts_video (int val);
 
 #endif /* ! GRUB_MULTIBOOT_CPU_HEADER */

=== modified file 'include/grub/video.h'
--- include/grub/video.h        2009-08-14 12:41:58 +0000
+++ include/grub/video.h        2010-01-02 01:48:33 +0000
@@ -234,6 +234,8 @@
 };
 typedef struct grub_video_adapter *grub_video_adapter_t;
 
+const char *grub_video_get_active_adapter_name (void);
+
 void grub_video_register (grub_video_adapter_t adapter);
 void grub_video_unregister (grub_video_adapter_t adapter);
 void grub_video_iterate (int (*hook) (grub_video_adapter_t adapter));

=== added file 'include/grub/x86_64/multiboot.h'
--- include/grub/x86_64/multiboot.h     1970-01-01 00:00:00 +0000
+++ include/grub/x86_64/multiboot.h     2010-01-02 01:48:33 +0000
@@ -0,0 +1,1 @@
+#include <grub/i386/multiboot.h>

=== modified file 'include/multiboot.h'
--- include/multiboot.h 2009-12-24 14:19:22 +0000
+++ include/multiboot.h 2010-01-02 12:38:41 +0000
@@ -32,7 +32,7 @@
 #define MULTIBOOT_BOOTLOADER_MAGIC             0x2BADB002
 
 /* The bits in the required part of flags field we don't support.  */
-#define MULTIBOOT_UNSUPPORTED                  0x0000fffc
+#define MULTIBOOT_UNSUPPORTED                   0x0000fff8
 
 /* Alignment of multiboot modules.  */
 #define MULTIBOOT_MOD_ALIGN                    0x00001000
@@ -88,10 +88,12 @@
 #define MULTIBOOT_INFO_APM_TABLE               0x00000400
 
 /* Is there video information?  */
-#define MULTIBOOT_INFO_VIDEO_INFO              0x00000800
+#define MULTIBOOT_INFO_VBE_INFO                        0x00000800
+#define MULTIBOOT_INFO_FRAMEBUFFER_INFO                0x00001000
 
 #ifndef ASM_FILE
 
+typedef unsigned char          multiboot_uint8_t;
 typedef unsigned short         multiboot_uint16_t;
 typedef unsigned int           multiboot_uint32_t;
 typedef unsigned long long     multiboot_uint64_t;
@@ -190,9 +192,43 @@
   multiboot_uint16_t vbe_interface_seg;
   multiboot_uint16_t vbe_interface_off;
   multiboot_uint16_t vbe_interface_len;
+
+  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;
+  union
+  {
+    struct
+    {
+      multiboot_uint32_t framebuffer_palette_addr;
+      multiboot_uint16_t framebuffer_palette_num_colors;
+    };
+    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;
+    };
+  };
+};
+
+struct multiboot_color
+{
+  multiboot_uint8_t red;
+  multiboot_uint8_t green;
+  multiboot_uint8_t blue;
 };
 typedef struct multiboot_info multiboot_info_t;
 
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB     1
+
 struct multiboot_mmap_entry
 {
   multiboot_uint32_t size;

=== modified file 'loader/i386/multiboot.c'
--- loader/i386/multiboot.c     2009-12-25 11:43:20 +0000
+++ loader/i386/multiboot.c     2010-01-02 17:12:40 +0000
@@ -20,7 +20,6 @@
 /*
  *  FIXME: The following features from the Multiboot specification still
  *         need to be implemented:
- *  - VBE support
  *  - symbol table
  *  - drives table
  *  - ROM configuration table
@@ -30,8 +29,6 @@
 #include <grub/loader.h>
 #include <grub/machine/loader.h>
 #include <grub/multiboot.h>
-#include <grub/machine/init.h>
-#include <grub/machine/memory.h>
 #include <grub/cpu/multiboot.h>
 #include <grub/elf.h>
 #include <grub/aout.h>
@@ -42,31 +39,30 @@
 #include <grub/misc.h>
 #include <grub/gzio.h>
 #include <grub/env.h>
-#ifdef GRUB_MACHINE_PCBIOS
-#include <grub/machine/biosnum.h>
-#include <grub/disk.h>
-#include <grub/device.h>
-#include <grub/partition.h>
-#endif
 #include <grub/i386/relocator.h>
 
+#include <grub/cpu/multiboot.h>
+
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#endif
+
 extern grub_dl_t my_mod;
-static struct multiboot_info *mbi, *mbi_dest;
-
-static grub_size_t code_size;
+static grub_size_t code_size, alloc_mbi;
 
 char *grub_multiboot_payload_orig;
 grub_addr_t grub_multiboot_payload_dest;
-grub_size_t grub_multiboot_payload_size;
+grub_size_t grub_multiboot_pure_size;
 grub_uint32_t grub_multiboot_payload_eip;
 
 static grub_err_t
 grub_multiboot_boot (void)
 {
+  grub_size_t mbi_size;
+  grub_err_t err;
   struct grub_relocator32_state state =
     {
       .eax = MULTIBOOT_BOOTLOADER_MAGIC,
-      .ebx = PTR_TO_UINT32 (mbi_dest),
       .ecx = 0,
       .edx = 0,
       .eip = grub_multiboot_payload_eip,
@@ -75,6 +71,29 @@
       .esp = 0x7ff00
     };
 
+  mbi_size = grub_multiboot_get_mbi_size ();
+  if (alloc_mbi < mbi_size)
+    {
+      grub_multiboot_payload_orig
+       = grub_relocator32_realloc (grub_multiboot_payload_orig,
+                                   grub_multiboot_pure_size + mbi_size);
+      if (!grub_multiboot_payload_orig)
+       return grub_errno;
+      alloc_mbi = mbi_size;
+    }
+
+  state.ebx = grub_multiboot_payload_dest + grub_multiboot_pure_size;
+  err = grub_multiboot_make_mbi (grub_multiboot_payload_orig,
+                                grub_multiboot_payload_dest,
+                                grub_multiboot_pure_size, mbi_size);
+  if (err)
+    return err;
+
+#ifdef GRUB_MACHINE_EFI
+  if (! grub_efi_finish_boot_services ())
+     grub_fatal ("cannot exit boot services");
+#endif
+
   grub_relocator32_boot (grub_multiboot_payload_orig,
                         grub_multiboot_payload_dest,
                         state);
@@ -86,69 +105,18 @@
 static grub_err_t
 grub_multiboot_unload (void)
 {
-  if (mbi)
-    {
-      unsigned int i;
-      for (i = 0; i < mbi->mods_count; i++)
-       {
-         grub_free ((void *)
-                    ((struct multiboot_mod_list *) 
mbi->mods_addr)[i].mod_start);
-         grub_free ((void *)
-                    ((struct multiboot_mod_list *) mbi->mods_addr)[i].cmdline);
-       }
-      grub_free ((void *) mbi->mods_addr);
-    }
+  grub_multiboot_free_mbi ();
+
   grub_relocator32_free (grub_multiboot_payload_orig);
 
-  mbi = NULL;
+  alloc_mbi = 0;
+
   grub_multiboot_payload_orig = NULL;
   grub_dl_unref (my_mod);
 
   return GRUB_ERR_NONE;
 }
 
-/* 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);
-}
-
-/* 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;
-      mmap_entry->type = type;
-      mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof 
(mmap_entry->size);
-      mmap_entry++;
-
-      return 0;
-    }
-
-  grub_mmap_iterate (hook);
-}
-
 #define MULTIBOOT_LOAD_ELF64
 #include "multiboot_elfxx.c"
 #undef MULTIBOOT_LOAD_ELF64
@@ -169,58 +137,13 @@
   return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
 }
 
-static int
-grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
-{
-#ifdef GRUB_MACHINE_PCBIOS
-  char *p;
-  grub_uint32_t biosdev, slice = ~0, part = ~0;
-  grub_device_t dev;
-
-  biosdev = grub_get_root_biosnumber ();
-
-  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 = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16)
-    | ((part & 0xff) << 8) | 0xff;
-  return (biosdev != ~0UL);
-#else
-  *bootdev = 0xffffffff;
-  return 0;
-#endif
-}
-
 void
 grub_multiboot (int argc, char *argv[])
 {
   grub_file_t file = 0;
-  char buffer[MULTIBOOT_SEARCH], *cmdline = 0, *p;
+  char buffer[MULTIBOOT_SEARCH];
   struct multiboot_header *header;
-  grub_ssize_t len, cmdline_length, boot_loader_name_length;
-  grub_uint32_t mmap_length;
-  int i;
-  int cmdline_argc;
-  char **cmdline_argv;
+  grub_ssize_t len;
 
   grub_loader_unset ();
 
@@ -271,31 +194,8 @@
   grub_relocator32_free (grub_multiboot_payload_orig);
   grub_multiboot_payload_orig = NULL;
 
-  mmap_length = grub_get_multiboot_mmap_len ();
-
-  /* Figure out cmdline length.  */
   /* Skip filename.  */
-  cmdline_argc = argc - 1;
-  cmdline_argv = argv + 1;
-
-  for (i = 0, cmdline_length = 0; i < cmdline_argc; i++)
-    cmdline_length += grub_strlen (cmdline_argv[i]) + 1;
-
-  if (cmdline_length == 0)
-    cmdline_length = 1;
-
-  boot_loader_name_length = sizeof(PACKAGE_STRING);
-
-#define cmdline_addr(x)                ((void *) ((x) + code_size))
-#define boot_loader_name_addr(x) \
-                               ((void *) ((x) + code_size + cmdline_length))
-#define mbi_addr(x)            ((void *) ((x) + code_size + cmdline_length + 
boot_loader_name_length))
-#define mmap_addr(x)           ((void *) ((x) + code_size + cmdline_length + 
boot_loader_name_length + sizeof (struct multiboot_info)))
-
-  grub_multiboot_payload_size = cmdline_length
-    /* boot_loader_name_length might need to grow for mbi,etc to be aligned 
(see below) */
-    + boot_loader_name_length + 3
-    + sizeof (struct multiboot_info) + mmap_length;
+  grub_multiboot_init_mbi (argc - 1, argv + 1);
 
   if (header->flags & MULTIBOOT_AOUT_KLUDGE)
     {
@@ -310,10 +210,11 @@
        code_size = load_size;
       grub_multiboot_payload_dest = header->load_addr;
 
-      grub_multiboot_payload_size += code_size;
+      grub_multiboot_pure_size += code_size;
 
+      alloc_mbi = grub_multiboot_get_mbi_size ();
       grub_multiboot_payload_orig
-       = grub_relocator32_alloc (grub_multiboot_payload_size);
+       = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi);
 
       if (! grub_multiboot_payload_orig)
        goto fail;
@@ -335,53 +236,37 @@
   else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
     goto fail;
 
-  /* This provides alignment for the MBI, the memory map and the backward 
relocator.  */
-  boot_loader_name_length += (0x04 - ((unsigned long) mbi_addr 
(grub_multiboot_payload_dest) & 0x03));
-
-  mbi = mbi_addr (grub_multiboot_payload_orig);
-  mbi_dest = mbi_addr (grub_multiboot_payload_dest);
-  grub_memset (mbi, 0, sizeof (struct multiboot_info));
-  mbi->mmap_length = mmap_length;
-
-  grub_fill_multiboot_mmap (mmap_addr (grub_multiboot_payload_orig));
-
-  /* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated
-     by the spec.  Is there something we can do about it?  */
-  mbi->mmap_addr = (grub_uint32_t) mmap_addr (grub_multiboot_payload_dest);
-  mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
-
-  /* Convert from bytes to kilobytes.  */
-  mbi->mem_lower = grub_mmap_get_lower () / 1024;
-  mbi->mem_upper = grub_mmap_get_upper () / 1024;
-  mbi->flags |= MULTIBOOT_INFO_MEMORY;
-
-  cmdline = p = cmdline_addr (grub_multiboot_payload_orig);
-  if (! cmdline)
-    goto fail;
-
-  for (i = 0; i < cmdline_argc; i++)
+  if (header->flags & MULTIBOOT_VIDEO_MODE)
     {
-      p = grub_stpcpy (p, cmdline_argv[i]);
-      *(p++) = ' ';
+      switch (header->mode_type)
+       {
+       case 1:
+         grub_env_set ("gfxpayload", "text");
+         break;
+
+       case 0:
+         {
+           char buf[sizeof 
("XXXXXXXXXXxXXXXXXXXXXxXXXXXXXXXX,XXXXXXXXXXxXXXXXXXXXX,auto")];
+           if (header->depth && header->width && header->height)
+             grub_sprintf (buf, "%dx%dx%d,%dx%d,auto", header->width,
+                           header->height, header->depth, header->width,
+                           header->height);
+           else if (header->width && header->height)
+             grub_sprintf (buf, "%dx%d,auto", header->width, header->height);
+           else
+             grub_sprintf (buf, "auto");
+
+           grub_env_set ("gfxpayload", buf);
+           break;
+         }
+       }
     }
 
-  /* Remove the space after the last word.  */
-  if (p != cmdline)
-    p--;
-  *p = 0;
-
-  mbi->flags |= MULTIBOOT_INFO_CMDLINE;
-  mbi->cmdline = (grub_uint32_t) cmdline_addr (grub_multiboot_payload_dest);
-
-
-  grub_strcpy (boot_loader_name_addr (grub_multiboot_payload_orig), 
PACKAGE_STRING);
-  mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
-  mbi->boot_loader_name = (grub_uint32_t) boot_loader_name_addr 
(grub_multiboot_payload_dest);
-
-  if (grub_multiboot_get_bootdev (&mbi->boot_device))
-    mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
-
-  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1);
+  grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE));
+
+  grub_multiboot_set_bootdev ();
+
+  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
 
  fail:
   if (file)
@@ -389,22 +274,19 @@
 
   if (grub_errno != GRUB_ERR_NONE)
     {
-      grub_free (cmdline);
-      grub_free (mbi);
+      grub_relocator32_free (grub_multiboot_payload_orig);
       grub_dl_unref (my_mod);
     }
 }
 
-
 void
 grub_module  (int argc, char *argv[])
 {
   grub_file_t file = 0;
-  grub_ssize_t size, len = 0;
-  char *module = 0, *cmdline = 0, *p;
-  int i;
-  int cmdline_argc;
-  char **cmdline_argv;
+  grub_ssize_t size;
+  char *module = 0;
+  grub_size_t mbi_size;
+  grub_err_t err;
 
   if (argc == 0)
     {
@@ -412,7 +294,7 @@
       goto fail;
     }
 
-  if (!mbi)
+  if (!grub_multiboot_payload_orig)
     {
       grub_error (GRUB_ERR_BAD_ARGUMENT,
                  "you need to load the multiboot kernel first");
@@ -424,9 +306,24 @@
     goto fail;
 
   size = grub_file_size (file);
-  module = grub_memalign (MULTIBOOT_MOD_ALIGN, size);
-  if (! module)
-    goto fail;
+  mbi_size = grub_multiboot_get_mbi_size ();
+
+  /* Skip module name.  */
+  err = grub_multiboot_add_module (grub_multiboot_pure_size, size,
+                                  argc - 1, argv + 1);
+  if (err)
+    goto fail;
+
+  /* Allocate space on relocator for both module and its descriptor.  */
+  grub_multiboot_payload_orig
+    = grub_relocator32_realloc (grub_multiboot_payload_orig,
+                               grub_multiboot_pure_size + size);
+  if (!grub_multiboot_payload_orig)
+    goto fail;
+  alloc_mbi = mbi_size;
+
+  module = grub_multiboot_payload_orig + grub_multiboot_pure_size;
+  grub_multiboot_pure_size += size;
 
   if (grub_file_read (file, module, size) != size)
     {
@@ -434,67 +331,8 @@
       goto fail;
     }
 
-  /* Skip module name.  */
-  cmdline_argc = argc - 1;
-  cmdline_argv = argv + 1;
-
-  for (i = 0; i < cmdline_argc; i++)
-    len += grub_strlen (cmdline_argv[i]) + 1;
-
-  if (len == 0)
-    len = 1;
-
-  cmdline = p = grub_malloc (len);
-  if (! cmdline)
-    goto fail;
-
-  for (i = 0; i < cmdline_argc; i++)
-    {
-      p = grub_stpcpy (p, cmdline_argv[i]);
-      *(p++) = ' ';
-    }
-
-  /* Remove the space after the last word.  */
-  if (p != cmdline)
-    p--;
-  *p = '\0';
-
-  if (mbi->flags & MULTIBOOT_INFO_MODS)
-    {
-      struct multiboot_mod_list *modlist = (struct multiboot_mod_list *) 
mbi->mods_addr;
-
-      modlist = grub_realloc (modlist, (mbi->mods_count + 1)
-                                      * sizeof (struct multiboot_mod_list));
-      if (! modlist)
-       goto fail;
-      mbi->mods_addr = (grub_uint32_t) modlist;
-      modlist += mbi->mods_count;
-      modlist->mod_start = (grub_uint32_t) module;
-      modlist->mod_end = (grub_uint32_t) module + size;
-      modlist->cmdline = (grub_uint32_t) cmdline;
-      modlist->pad = 0;
-      mbi->mods_count++;
-    }
-  else
-    {
-      struct multiboot_mod_list *modlist = grub_zalloc (sizeof (struct 
multiboot_mod_list));
-      if (! modlist)
-       goto fail;
-      modlist->mod_start = (grub_uint32_t) module;
-      modlist->mod_end = (grub_uint32_t) module + size;
-      modlist->cmdline = (grub_uint32_t) cmdline;
-      mbi->mods_count = 1;
-      mbi->mods_addr = (grub_uint32_t) modlist;
-      mbi->flags |= MULTIBOOT_INFO_MODS;
-    }
-
  fail:
   if (file)
     grub_file_close (file);
-
-  if (grub_errno != GRUB_ERR_NONE)
-    {
-      grub_free (module);
-      grub_free (cmdline);
-    }
 }
+

=== modified file 'loader/i386/multiboot_elfxx.c'
--- loader/i386/multiboot_elfxx.c       2009-12-13 18:29:15 +0000
+++ loader/i386/multiboot_elfxx.c       2010-01-02 01:48:33 +0000
@@ -100,10 +100,11 @@
   code_size = (phdr(highest_segment)->p_paddr + 
phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
   grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr;
 
-  grub_multiboot_payload_size += code_size;
+  grub_multiboot_pure_size += code_size;
 
+  alloc_mbi = grub_multiboot_get_mbi_size ();
   grub_multiboot_payload_orig
-    = grub_relocator32_alloc (grub_multiboot_payload_size);
+    = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi);
 
   if (!grub_multiboot_payload_orig)
     return grub_errno;

=== added file 'loader/i386/multiboot_mbi.c'
--- loader/i386/multiboot_mbi.c 1970-01-01 00:00:00 +0000
+++ loader/i386/multiboot_mbi.c 2010-01-02 12:12:35 +0000
@@ -0,0 +1,518 @@
+/*
+ *  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/i386/pc/vbe.h>
+#include <grub/env.h>
+
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || 
defined (GRUB_MACHINE_QEMU)
+#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_off_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 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)
+{
+  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.  */
+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);
+}
+
+static grub_err_t
+set_video_mode (void)
+{
+  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)
+{
+  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);
+  
+  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;
+
+  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.");
+  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;
+  
+  mbi->flags |= MULTIBOOT_INFO_VBE_INFO;
+
+  return GRUB_ERR_NONE;
+}
+#endif
+
+static grub_err_t
+retrieve_video_parameters (struct multiboot_info *mbi,
+                          grub_uint8_t *ptrorig, grub_uint32_t ptrdest)
+{
+  grub_err_t err;
+  struct grub_video_mode_info mode_info;
+  void *framebuffer;
+#if HAS_VBE
+  int vbe_active;
+#endif
+  struct grub_video_palette_data palette[256];
+
+  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;
+
+  mbi->framebuffer_addr = (grub_addr_t) framebuffer;
+  mbi->framebuffer_pitch = mode_info.pitch;
+
+  mbi->framebuffer_width = mode_info.width;
+  mbi->framebuffer_height = mode_info.height;
+
+  mbi->framebuffer_bpp = mode_info.bpp;
+      
+  if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
+    {
+      struct multiboot_color *mb_palette;
+      unsigned i;
+      mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
+      mbi->framebuffer_palette_addr = ptrdest;
+      mb_palette = (struct multiboot_color *) ptrorig;
+      for (i = 0; i < ARRAY_SIZE (palette); i++)
+       {
+         mb_palette[i].red = palette[i].r;
+         mb_palette[i].green = palette[i].g;
+         mb_palette[i].blue = palette[i].b;
+       }
+      ptrorig += ARRAY_SIZE (palette) * sizeof (struct multiboot_color);
+      ptrdest += ARRAY_SIZE (palette) * sizeof (struct multiboot_color);
+    }
+  else
+    {
+      mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
+      mbi->framebuffer_red_field_position = mode_info.green_field_pos;
+      mbi->framebuffer_red_mask_size = mode_info.green_mask_size;
+      mbi->framebuffer_green_field_position = mode_info.green_field_pos;
+      mbi->framebuffer_green_mask_size = mode_info.green_mask_size;
+      mbi->framebuffer_blue_field_position = mode_info.blue_field_pos;
+      mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size;
+  
+      mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
+    }
+
+#if HAS_VBE
+  if (vbe_active)
+    fill_vbe_info (mbi, ptrorig, ptrdest);
+#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_uint32_t ptrdest = dest + buf_off;
+  struct multiboot_info *mbi;
+  struct multiboot_mod_list *modlist;
+  unsigned i;
+  struct module *cur;
+  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);
+  grub_memset (mbi, 0, sizeof (*mbi));
+
+  grub_memcpy (ptrorig, cmdline, cmdline_size);
+  mbi->flags |= MULTIBOOT_INFO_CMDLINE;
+  mbi->cmdline = ptrdest;
+  ptrorig += ALIGN_UP (cmdline_size, 4);
+  ptrdest += ALIGN_UP (cmdline_size, 4);
+
+  grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING));
+  mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;
+  mbi->boot_loader_name = ptrdest;
+  ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4);
+  ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4);
+
+  if (modcnt)
+    {
+      mbi->flags |= MULTIBOOT_INFO_MODS;
+      mbi->mods_addr = ptrdest;
+      mbi->mods_count = modcnt;
+      modlist = (struct multiboot_mod_list *) ptrorig;
+      ptrorig += modcnt * sizeof (struct multiboot_mod_list);
+      ptrdest += modcnt * sizeof (struct multiboot_mod_list);
+
+      for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next)
+       {
+         modlist[i].mod_start = ptrdest + cur->start;
+         modlist[i].mod_end = modlist[i].mod_start + cur->size;
+         modlist[i].cmdline = ptrdest;
+         grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size);
+         ptrorig += ALIGN_UP (cur->cmdline_size, 4);
+         ptrdest += ALIGN_UP (cur->cmdline_size, 4);
+       }
+    }
+  else
+    {
+      mbi->mods_addr = 0;
+      mbi->mods_count = 0;
+    }
+
+  mmap_size = grub_get_multiboot_mmap_len (); 
+  grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig);
+  mbi->mmap_length = mmap_size;
+  mbi->mmap_addr = ptrdest;
+  mbi->flags |= MULTIBOOT_INFO_MEM_MAP;
+  ptrorig += mmap_size;
+  ptrdest += mmap_size;
+
+  /* Convert from bytes to kilobytes.  */
+  mbi->mem_lower = grub_mmap_get_lower () / 1024;
+  mbi->mem_upper = grub_mmap_get_upper () / 1024;
+  mbi->flags |= MULTIBOOT_INFO_MEMORY;
+
+  if (bootdev_set)
+    {
+      mbi->boot_device = bootdev;
+      mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
+    }
+
+  err = retrieve_video_parameters (mbi, ptrorig, ptrdest);
+  if (err)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+    }
+  ptrorig += sizeof (struct grub_vbe_info_block);
+  ptrdest += sizeof (struct grub_vbe_info_block);
+  ptrorig += sizeof (struct grub_vbe_mode_info_block);
+  ptrdest += sizeof (struct grub_vbe_mode_info_block);
+
+  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_off_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;
+
+  return GRUB_ERR_NONE;
+}
+
+void
+grub_multiboot_set_bootdev (void)
+{
+  char *p;
+  grub_uint32_t biosdev, slice = ~0, part = ~0;
+  grub_device_t dev;
+
+#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 = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) 
+    | ((part & 0xff) << 8) | 0xff;
+  bootdev_set = 1;
+}

=== modified file 'loader/i386/pc/xnu.c'
--- loader/i386/pc/xnu.c        2009-10-15 12:40:13 +0000
+++ loader/i386/pc/xnu.c        2010-01-02 01:48:33 +0000
@@ -43,7 +43,8 @@
 {
   struct grub_video_mode_info mode_info;
   int ret;
-  char *tmp, *modevar;
+  char *tmp;
+  const char *modevar;
   void *framebuffer;
   grub_err_t err;
 
@@ -55,8 +56,7 @@
       tmp = grub_malloc (grub_strlen (modevar)
                         + sizeof (DEFAULT_VIDEO_MODE) + 1);
       if (! tmp)
-       return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                          "couldn't allocate temporary storag");
+       return grub_errno;
       grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
       err = grub_video_set_mode (tmp, video_hook);
       grub_free (tmp);

=== modified file 'loader/multiboot_loader.c'
--- loader/multiboot_loader.c   2009-12-26 10:01:33 +0000
+++ loader/multiboot_loader.c   2010-01-02 01:48:37 +0000
@@ -139,7 +139,7 @@
   /* XXX Find a better way to identify this.
      This is for i386-pc */
 #if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \
-    defined(GRUB_MACHINE_QEMU)
+  defined(GRUB_MACHINE_QEMU) || defined(GRUB_MACHINE_EFI)
   if (header_multi_ver_found == 1)
     {
       grub_dprintf ("multiboot_loader",
@@ -148,6 +148,7 @@
       module_version_status = 1;
     }
 #endif
+#if !defined(GRUB_MACHINE_EFI)
   if (header_multi_ver_found == 0 || header_multi_ver_found == 2)
     {
       grub_dprintf ("multiboot_loader",
@@ -155,6 +156,7 @@
       grub_multiboot2 (argc, argv);
       module_version_status = 2;
     }
+#endif
 
   return grub_errno;
 
@@ -173,7 +175,7 @@
 {
 
 #if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \
-    defined(GRUB_MACHINE_QEMU)
+    defined(GRUB_MACHINE_QEMU) || defined(GRUB_MACHINE_EFI)
   if (module_version_status == 1)
     {
       grub_dprintf("multiboot_loader",
@@ -181,13 +183,14 @@
       grub_module (argc, argv);
     }
 #endif
+#if !defined(GRUB_MACHINE_EFI)
   if (module_version_status == 2)
     {
       grub_dprintf("multiboot_loader",
           "Launching multiboot 2 grub_module2() function\n");
       grub_module2 (argc, argv);
     }
-
+#endif
   return grub_errno;
 }
 

=== modified file 'video/video.c'
--- video/video.c       2009-12-24 22:53:05 +0000
+++ video/video.c       2010-01-02 01:48:37 +0000
@@ -399,6 +399,15 @@
   return grub_video_adapter_active->get_active_render_target (target);
 }
 
+const char *
+grub_video_get_active_adapter_name (void)
+{
+  if (grub_video_adapter_active)
+    return grub_video_adapter_active->name;
+  return NULL;
+}
+
+
 grub_err_t
 grub_video_set_mode (const char *modestring,
                     int NESTED_FUNC_ATTR (*hook) (grub_video_adapter_t p,

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

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