All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GNU GRUB <grub-devel@gnu.org>
Subject: Re: [RFC] Multiboot ammendment: non-VBE video
Date: Sat, 02 Jan 2010 19:26:08 +0100	[thread overview]
Message-ID: <4B3F8FC0.3040004@gmail.com> (raw)
In-Reply-To: <20100101113010.GA3692@thorin>


[-- Attachment #1.1: Type: text/plain, Size: 3104 bytes --]

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


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: mbvid_spec.diff --]
[-- Type: text/x-diff; name="mbvid_spec.diff", Size: 9293 bytes --]

=== 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
-@samp{Multiboot 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 non-@sc{vbe} 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:
+@example
+@group
+        +----------------------------------+
+110     | framebuffer_palette_addr         |
+114     | framebuffer_palette_num_colors   |
+        +----------------------------------+
+@end group
+@end example
+@samp{framebuffer_palette_addr} contains address of array of @samp{framebuffer_palette_num_colors} following structures:
+@example
+@group
+        +-------------+
+0       | red_value   |
+1       | green_value |
+2       | blue_value  |
+        +-------------+
+@end group
+@end example
+If @samp{framebuffer_type} is set to 1 it direct RGB color. Then color_type is defined as following:
+
+@example
+@group
+        +----------------------------------+
+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       |
+        +----------------------------------+
+@end group
+@end example
+All further values of @samp{framebuffer_type} are reserved for future expansion
 
 @node Examples
 @chapter Examples


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: mbvid_efi.diff --]
[-- Type: text/x-diff; name="mbvid_efi.diff", Size: 39638 bytes --]

=== 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  <phcoder@gmail.com>
+
+	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 #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]

  reply	other threads:[~2010-01-02 18:26 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-01 15:37 [RFC] Multiboot ammendment: non-VBE video Vladimir 'phcoder' Serbinenko
2009-12-24 22:29 ` Robert Millan
2009-12-28 12:07   ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-01-01 11:30     ` Robert Millan
2010-01-02 18:26       ` Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2010-01-03 16:13         ` Robert Millan
2010-01-03 16:35           ` Isaac Dupree
2010-01-04 21:19             ` richardvoigt
2010-01-04 19:35           ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-01-07 18:45             ` Robert Millan
2010-01-07 20:18               ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-01-12 16:52                 ` Robert Millan
2010-01-12 16:54         ` Multiboot video in GRUB (Re: [RFC] Multiboot ammendment: non-VBE video) Robert Millan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B3F8FC0.3040004@gmail.com \
    --to=phcoder@gmail.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.