]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
2010-01-15 Vladimir Serbinenko <phcoder@gmail.com>
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 15 Jan 2010 15:30:57 +0000 (16:30 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 15 Jan 2010 15:30:57 +0000 (16:30 +0100)
Video multiboot support.

* include/grub/multiboot.h (grub_multiboot_set_accepts_video):
New prototype.
* include/multiboot.h: Resynced with multiboot specification.
* include/multiboot2.h: Likewise.
* loader/i386/multiboot.c (UNSUPPORTED_FLAGS): Support video flags.
(grub_multiboot): Parse MULTIBOOT_VIDEO_MODE fields.
* loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): New constant.
(HAS_VGA_TEXT): Likewise.
(accepts_video): New variable.
(grub_multiboot_set_accepts_video): New function.
(grub_multiboot_get_mbi_size): Account for video structures.
(set_video_mode): New function.
(retrieve_video_parameters): Likewise.
(grub_multiboot_make_mbi): Fill video fields.

ChangeLog
include/grub/multiboot.h
include/multiboot.h
include/multiboot2.h
loader/i386/multiboot.c
loader/i386/multiboot_mbi.c

index dc123888ba99b78c8df3bab51179b23cb6976b0d..8d3245ea3ecafef4e0f1ec68f5105f9a6dbeb164 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2010-01-15  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Video multiboot support.
+
+       * include/grub/multiboot.h (grub_multiboot_set_accepts_video):
+       New prototype.
+       * include/multiboot.h: Resynced with multiboot specification.
+       * include/multiboot2.h: Likewise.
+       * loader/i386/multiboot.c (UNSUPPORTED_FLAGS): Support video flags.
+       (grub_multiboot): Parse MULTIBOOT_VIDEO_MODE fields.
+       * loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): New constant.
+       (HAS_VGA_TEXT): Likewise.
+       (accepts_video): New variable.
+       (grub_multiboot_set_accepts_video): New function.
+       (grub_multiboot_get_mbi_size): Account for video structures.
+       (set_video_mode): New function.
+       (retrieve_video_parameters): Likewise.
+       (grub_multiboot_make_mbi): Fill video fields.
+
 2010-01-15  Vladimir Serbinenko  <phcoder@gmail.com>
 
        Video driver ids.
index f9edb0c598b84619b7d5c178ad3da583b6352feb..665292e330425267bfcb1ee1ca2579f67a18b62a 100644 (file)
@@ -35,6 +35,8 @@
 void grub_multiboot (int argc, char *argv[]);
 void grub_module (int argc, char *argv[]);
 
+void grub_multiboot_set_accepts_video (int val);
+
 grub_size_t grub_multiboot_get_mbi_size (void);
 grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest,
                                    grub_off_t buf_off, grub_size_t bufsize);
index da7afd9b3b6d93b731795025919cb544eac84342..57c154c98f86507b19b62f714a5842c1f4eab061 100644 (file)
 #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;
@@ -187,9 +189,43 @@ struct multiboot_info
   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;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB     1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT    2
+  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;
+    };
+  };
 };
 typedef struct multiboot_info multiboot_info_t;
 
+struct multiboot_color
+{
+  multiboot_uint8_t red;
+  multiboot_uint8_t green;
+  multiboot_uint8_t blue;
+};
+
 struct multiboot_mmap_entry
 {
   multiboot_uint32_t size;
index 0488849d7f730a3110f4244351f98df22ab51018..a241a70ad2311ad41beaf641fd073a7d1d3e6ad1 100644 (file)
 #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;
@@ -187,9 +189,43 @@ struct multiboot_info
   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;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB     1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT    2
+  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;
+    };
+  };
 };
 typedef struct multiboot_info multiboot_info_t;
 
+struct multiboot_color
+{
+  multiboot_uint8_t red;
+  multiboot_uint8_t green;
+  multiboot_uint8_t blue;
+};
+
 struct multiboot_mmap_entry
 {
   multiboot_uint32_t size;
index 4360e8a2cb58b67be3ce0d8d9991645de90ac248..637bc5d492df0b3d30810b4b49fabfa8840c0f7a 100644 (file)
  */
 
 /* The bits in the required part of flags field we don't support.  */
-#define UNSUPPORTED_FLAGS                      0x0000fffc
+#define UNSUPPORTED_FLAGS                      0x0000fff8
 
 #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>
@@ -90,8 +88,6 @@ grub_multiboot_boot (void)
   if (err)
     return err;
 
-  grub_video_set_mode ("text", NULL);
-
   grub_relocator32_boot (grub_multiboot_payload_orig,
                         grub_multiboot_payload_dest,
                         state);
@@ -235,6 +231,34 @@ grub_multiboot (int argc, char *argv[])
   else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
     goto fail;
 
+  if (header->flags & MULTIBOOT_VIDEO_MODE)
+    {
+      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;
+         }
+       }
+    }
+
+  grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE));
+
   grub_multiboot_set_bootdev ();
 
   grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
index 58802d44c95c941cfdf51bc0725cf28b0fdf4e44..5f33a7314d66e6feb3fbc3d14230a3aeb8355f75 100644 (file)
 #include <grub/mm.h>
 #include <grub/misc.h>
 #include <grub/env.h>
+#include <grub/video.h>
+
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
+#include <grub/i386/pc/vbe.h>
+#define DEFAULT_VIDEO_MODE "text"
+#define HAS_VGA_TEXT 1
+#else
+#define DEFAULT_VIDEO_MODE "auto"
+#define HAS_VGA_TEXT 0
+#endif
 
 struct module
 {
@@ -46,6 +56,13 @@ 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.  */
@@ -73,7 +90,8 @@ 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 ();
+    + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_len ()
+    + 256 * sizeof (struct multiboot_color);
 }
 
 /* Fill previously allocated Multiboot mmap.  */
@@ -106,6 +124,107 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
   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;
+}
+
+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;
+  grub_video_driver_id_t driv_id;
+  struct grub_video_palette_data palette[256];
+
+  err = set_video_mode ();
+  if (err)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+    }
+
+  grub_video_get_palette (0, ARRAY_SIZE (palette), palette);
+
+  driv_id = grub_video_get_driver_id ();
+  if (driv_id == GRUB_VIDEO_DRIVER_NONE)
+    return GRUB_ERR_NONE;
+
+  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;
+      mbi->framebuffer_palette_num_colors = mode_info.number_of_colors;
+      if (mbi->framebuffer_palette_num_colors > ARRAY_SIZE (palette))
+       mbi->framebuffer_palette_num_colors = ARRAY_SIZE (palette);
+      mb_palette = (struct multiboot_color *) ptrorig;
+      for (i = 0; i < mbi->framebuffer_palette_num_colors; i++)
+       {
+         mb_palette[i].red = palette[i].r;
+         mb_palette[i].green = palette[i].g;
+         mb_palette[i].blue = palette[i].b;
+       }
+      ptrorig += mbi->framebuffer_palette_num_colors
+       * sizeof (struct multiboot_color);
+      ptrdest += mbi->framebuffer_palette_num_colors
+       * 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;
+
+  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)
@@ -117,6 +236,7 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
   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");
@@ -182,6 +302,13 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
       mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
     }
 
+  err = retrieve_video_parameters (mbi, ptrorig, ptrdest);
+  if (err)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+    }
+
   return GRUB_ERR_NONE;
 }