grub-devel
[Top][All Lists]
Advanced

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

Re: [PATCH] Multiboot video support


From: Vladimir 'phi-coder/phcoder' Serbinenko
Subject: Re: [PATCH] Multiboot video support
Date: Fri, 15 Jan 2010 15:50:35 +0100
User-agent: Mozilla-Thunderbird 2.0.0.22 (X11/20091109)

Added EGA text support


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

=== added file 'ChangeLog.mbivid'
--- ChangeLog.mbivid    1970-01-01 00:00:00 +0000
+++ ChangeLog.mbivid    2010-01-14 14:44:14 +0000
@@ -0,0 +1,24 @@
+2010-01-14  Vladimir Serbinenko  <address@hidden>
+
+       Video multiboot support.
+
+       * include/grub/multiboot.h (grub_multiboot_set_accepts_video):
+       New prototype.
+       * include/grub/video.h (grub_video_driver_id): New type.
+       (grub_video_adapter): New member 'id'. All users updated.
+       (grub_video_get_driver_id): New proto.
+       * 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.
+       (HAS_VBE): 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.
+       (fill_vbe_info) [HAS_VBE]: Likewise.
+       (retrieve_video_parameters): Likewise.
+       (grub_multiboot_make_mbi): Fill video fields.
+       * video/video.c (grub_video_get_driver_id): New function.

=== modified file 'include/grub/multiboot.h'
--- include/grub/multiboot.h    2010-01-10 17:58:18 +0000
+++ include/grub/multiboot.h    2010-01-14 14:26:47 +0000
@@ -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);

=== modified file 'include/grub/video.h'
--- include/grub/video.h        2009-08-14 12:41:58 +0000
+++ include/grub/video.h        2010-01-14 14:22:33 +0000
@@ -159,10 +159,19 @@
   grub_uint8_t a; /* Reserved bits value (0-255).  */
 };
 
+typedef enum grub_video_driver_id
+  {
+    GRUB_VIDEO_DRIVER_NONE,
+    GRUB_VIDEO_DRIVER_VBE,
+    GRUB_VIDEO_DRIVER_EFI_UGA,
+    GRUB_VIDEO_DRIVER_EFI_GOP
+  } grub_video_driver_id_t;
+
 struct grub_video_adapter
 {
   /* The video adapter name.  */
   const char *name;
+  grub_video_driver_id_t id;
 
   /* Initialize the video adapter.  */
   grub_err_t (*init) (void);
@@ -310,4 +319,7 @@
                                int NESTED_FUNC_ATTR (*hook) 
(grub_video_adapter_t p,
                                                              struct 
grub_video_mode_info *mode_info));
 
+grub_video_driver_id_t
+grub_video_get_driver_id (void);
+
 #endif /* ! GRUB_VIDEO_HEADER */

=== modified file 'include/multiboot.h'
--- include/multiboot.h 2010-01-07 19:55:16 +0000
+++ include/multiboot.h 2010-01-15 12:54:32 +0000
@@ -85,10 +85,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;
@@ -187,9 +189,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;
+#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;

=== modified file 'include/multiboot2.h'
--- include/multiboot2.h        2010-01-07 21:05:25 +0000
+++ include/multiboot2.h        2010-01-15 12:54:48 +0000
@@ -85,10 +85,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;
@@ -187,9 +189,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;
+#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;

=== modified file 'loader/i386/multiboot.c'
--- loader/i386/multiboot.c     2010-01-14 21:08:31 +0000
+++ loader/i386/multiboot.c     2010-01-15 14:49:11 +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
@@ -28,13 +27,11 @@
  */
 
 /* 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 +87,6 @@
   if (err)
     return err;
 
-  grub_video_set_mode ("text", NULL);
-
   grub_relocator32_boot (grub_multiboot_payload_orig,
                         grub_multiboot_payload_dest,
                         state);
@@ -235,6 +230,34 @@
   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);

=== modified file 'loader/i386/multiboot_mbi.c'
--- loader/i386/multiboot_mbi.c 2010-01-10 17:58:18 +0000
+++ loader/i386/multiboot_mbi.c 2010-01-15 14:45:03 +0000
@@ -29,6 +29,18 @@
 #include <grub/mm.h>
 #include <grub/misc.h>
 #include <grub/env.h>
+#include <grub/video.h>
+
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || 
defined (GRUB_MACHINE_QEMU)
+#include <grub/i386/pc/vbe.h>
+#define DEFAULT_VIDEO_MODE "text"
+#define HAS_VGA_TEXT 1
+#define HAS_VBE 1
+#else
+#define DEFAULT_VIDEO_MODE "auto"
+#define HAS_VGA_TEXT 0
+#define HAS_VBE 0
+#endif
 
 struct module
 {
@@ -46,6 +58,13 @@
 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 +92,12 @@
 {
   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 ()
+#if HAS_VBE
+    + sizeof (struct grub_vbe_info_block)
+    + sizeof (struct grub_vbe_mode_info_block)
+#endif
+    + 256 * sizeof (struct multiboot_color);
 }
 
 /* Fill previously allocated Multiboot mmap.  */
@@ -106,6 +130,189 @@
   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, int fill_generic)
+{
+  grub_vbe_status_t status;
+  grub_uint32_t vbe_mode;
+  void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+  struct grub_vbe_mode_info_block *mode_info;
+    
+  status = grub_vbe_bios_get_controller_info (scratch);
+  if (status != GRUB_VBE_STATUS_OK)
+    return grub_error (GRUB_ERR_IO, "Can't get controller info.");
+  
+  mbi->vbe_control_info = ptrdest;
+  grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_info_block));
+  ptrorig += sizeof (struct grub_vbe_info_block);
+  ptrdest += sizeof (struct grub_vbe_info_block);
+  
+  status = grub_vbe_bios_get_mode (scratch);
+  vbe_mode = *(grub_uint32_t *) scratch;
+  if (status != GRUB_VBE_STATUS_OK)
+    return grub_error (GRUB_ERR_IO, "can't get VBE mode");
+  mbi->vbe_mode = vbe_mode;
+
+  mode_info = (struct grub_vbe_mode_info_block *) ptrorig;
+  mbi->vbe_mode_info = ptrdest;
+  /* get_mode_info isn't available for mode 3.  */
+  if (vbe_mode == 3)
+    {
+      grub_memset (mode_info, 0, sizeof (struct grub_vbe_mode_info_block));
+      mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT;
+      mode_info->x_resolution = 80;
+      mode_info->y_resolution = 25;
+    }
+  else
+    {
+      status = grub_vbe_bios_get_mode_info (vbe_mode, scratch);
+      if (status != GRUB_VBE_STATUS_OK)
+       return grub_error (GRUB_ERR_IO, "can't get mode info");
+      grub_memcpy (mode_info, scratch,
+                  sizeof (struct grub_vbe_mode_info_block));
+    }
+  ptrorig += sizeof (struct grub_vbe_mode_info_block);
+  ptrdest += sizeof (struct grub_vbe_mode_info_block);
+      
+  /* FIXME: retrieve those.  */
+  mbi->vbe_interface_seg = 0;
+  mbi->vbe_interface_off = 0;
+  mbi->vbe_interface_len = 0;
+  
+  mbi->flags |= MULTIBOOT_INFO_VBE_INFO;
+
+  if (fill_generic && mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT)
+    {
+      mbi->framebuffer_addr = 0xb8000;
+
+      mbi->framebuffer_pitch = 2 * mode_info->x_resolution;    
+      mbi->framebuffer_width = mode_info->x_resolution;
+      mbi->framebuffer_height = mode_info->y_resolution;
+
+      mbi->framebuffer_bpp = 16;
+
+      mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
+
+      mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO;
+    }
+
+  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;
+  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 HAS_VGA_TEXT
+  if (driv_id == GRUB_VIDEO_DRIVER_NONE)
+    return fill_vbe_info (mbi, ptrorig, ptrdest, 1);
+#else
+  if (driv_id == GRUB_VIDEO_DRIVER_NONE)
+    return GRUB_ERR_NONE;
+#endif
+
+  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
+  if (err)
+    return err;
+
+  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;
+
+#if HAS_VBE
+  if (driv_id == GRUB_VIDEO_DRIVER_VBE)
+    return fill_vbe_info (mbi, ptrorig, ptrdest, 0);
+#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)
@@ -117,6 +324,7 @@
   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 +390,19 @@
       mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
     }
 
+  err = retrieve_video_parameters (mbi, ptrorig, ptrdest);
+  if (err)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+    }
+#if HAS_VBE
+  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);
+#endif
+
   return GRUB_ERR_NONE;
 }
 

=== modified file 'video/efi_gop.c'
--- video/efi_gop.c     2009-12-24 22:53:05 +0000
+++ video/efi_gop.c     2010-01-14 14:22:33 +0000
@@ -353,6 +353,7 @@
 static struct grub_video_adapter grub_video_gop_adapter =
   {
     .name = "EFI GOP driver",
+    .id = GRUB_VIDEO_DRIVER_EFI_GOP,
 
     .init = grub_video_gop_init,
     .fini = grub_video_gop_fini,

=== modified file 'video/efi_uga.c'
--- video/efi_uga.c     2009-12-24 22:53:05 +0000
+++ video/efi_uga.c     2010-01-14 14:22:33 +0000
@@ -300,6 +300,7 @@
 static struct grub_video_adapter grub_video_uga_adapter =
   {
     .name = "EFI UGA driver",
+    .id = GRUB_VIDEO_DRIVER_EFI_UGA,
 
     .init = grub_video_uga_init,
     .fini = grub_video_uga_fini,

=== modified file 'video/i386/pc/vbe.c'
--- video/i386/pc/vbe.c 2009-12-24 22:53:05 +0000
+++ video/i386/pc/vbe.c 2010-01-14 14:22:33 +0000
@@ -557,6 +557,7 @@
 static struct grub_video_adapter grub_video_vbe_adapter =
   {
     .name = "VESA BIOS Extension Video Driver",
+    .id = GRUB_VIDEO_DRIVER_VBE,
 
     .init = grub_video_vbe_init,
     .fini = grub_video_vbe_fini,

=== modified file 'video/video.c'
--- video/video.c       2009-12-24 22:53:05 +0000
+++ video/video.c       2010-01-14 14:22:33 +0000
@@ -93,6 +93,14 @@
   return grub_video_adapter_active->get_info (mode_info);
 }
 
+grub_video_driver_id_t
+grub_video_get_driver_id (void)
+{
+  if (! grub_video_adapter_active)
+    return GRUB_VIDEO_DRIVER_NONE;
+  return grub_video_adapter_active->id;
+}
+
 /* Get information about active video mode.  */
 grub_err_t
 grub_video_get_info_and_fini (struct grub_video_mode_info *mode_info,

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

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