[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Multiboot video support
From: |
Vladimir 'φ-coder/phcoder' Serbinenko |
Subject: |
[PATCH] Multiboot video support |
Date: |
Thu, 14 Jan 2010 15:55:25 +0100 |
User-agent: |
Mozilla-Thunderbird 2.0.0.22 (X11/20091109) |
--
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-14 14:22:27 +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;
+ 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;
+};
+
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
+
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-14 14:22:27 +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;
+ 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;
+};
+
+#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 2010-01-12 18:47:02 +0000
+++ loader/i386/multiboot.c 2010-01-14 14:22:27 +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>
@@ -232,6 +229,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-14 14:29:26 +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,160 @@
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
+ {
+ grub_video_driver_id_t driv_id;
+ driv_id = grub_video_get_driver_id ();
+
+ vbe_active = ((driv_id == GRUB_VIDEO_DRIVER_VBE)
+ || ((driv_id == GRUB_VIDEO_DRIVER_NONE) && HAS_VGA_TEXT));
+ }
+#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 (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)
@@ -117,6 +295,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 +361,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,
signature.asc
Description: OpenPGP digital signature
- [PATCH] Multiboot video support,
Vladimir 'φ-coder/phcoder' Serbinenko <=