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.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-01-15 16:30:57 +01:00
parent 0d90e8a6fb
commit 884ade5654
6 changed files with 252 additions and 8 deletions

View file

@ -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> 2010-01-15 Vladimir Serbinenko <phcoder@gmail.com>
Video driver ids. Video driver ids.

View file

@ -35,6 +35,8 @@
void grub_multiboot (int argc, char *argv[]); void grub_multiboot (int argc, char *argv[]);
void grub_module (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_size_t grub_multiboot_get_mbi_size (void);
grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest,
grub_off_t buf_off, grub_size_t bufsize); grub_off_t buf_off, grub_size_t bufsize);

View file

@ -85,10 +85,12 @@
#define MULTIBOOT_INFO_APM_TABLE 0x00000400 #define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */ /* 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 #ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t; typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t; typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_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_seg;
multiboot_uint16_t vbe_interface_off; multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len; 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; 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 struct multiboot_mmap_entry
{ {
multiboot_uint32_t size; multiboot_uint32_t size;

View file

@ -85,10 +85,12 @@
#define MULTIBOOT_INFO_APM_TABLE 0x00000400 #define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */ /* 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 #ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t; typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t; typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_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_seg;
multiboot_uint16_t vbe_interface_off; multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len; 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; 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 struct multiboot_mmap_entry
{ {
multiboot_uint32_t size; multiboot_uint32_t size;

View file

@ -28,13 +28,11 @@
*/ */
/* The bits in the required part of flags field we don't support. */ /* 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/loader.h>
#include <grub/machine/loader.h> #include <grub/machine/loader.h>
#include <grub/multiboot.h> #include <grub/multiboot.h>
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/cpu/multiboot.h> #include <grub/cpu/multiboot.h>
#include <grub/elf.h> #include <grub/elf.h>
#include <grub/aout.h> #include <grub/aout.h>
@ -90,8 +88,6 @@ grub_multiboot_boot (void)
if (err) if (err)
return err; return err;
grub_video_set_mode ("text", NULL);
grub_relocator32_boot (grub_multiboot_payload_orig, grub_relocator32_boot (grub_multiboot_payload_orig,
grub_multiboot_payload_dest, grub_multiboot_payload_dest,
state); state);
@ -235,6 +231,34 @@ grub_multiboot (int argc, char *argv[])
else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
goto fail; 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_multiboot_set_bootdev ();
grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);

View file

@ -29,6 +29,16 @@
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/env.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 struct module
{ {
@ -46,6 +56,13 @@ static unsigned modcnt;
static char *cmdline = NULL; static char *cmdline = NULL;
static grub_uint32_t bootdev; static grub_uint32_t bootdev;
static int bootdev_set; 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 /* Return the length of the Multiboot mmap that will be needed to allocate
our platform's map. */ our platform's map. */
@ -73,7 +90,8 @@ grub_multiboot_get_mbi_size (void)
{ {
return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4)
+ modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + 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. */ /* Fill previously allocated Multiboot mmap. */
@ -106,6 +124,107 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry)
grub_mmap_iterate (hook); 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_err_t
grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off,
grub_size_t bufsize) 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; unsigned i;
struct module *cur; struct module *cur;
grub_size_t mmap_size; grub_size_t mmap_size;
grub_err_t err;
if (bufsize < grub_multiboot_get_mbi_size ()) if (bufsize < grub_multiboot_get_mbi_size ())
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); 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; 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; return GRUB_ERR_NONE;
} }