From 57e41c71bc8af58384bccbfa9090704e02e33157 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 14 Jan 2010 15:54:14 +0100 Subject: [PATCH 01/12] multiboot video support --- ChangeLog.mbivid | 24 +++++ include/grub/multiboot.h | 2 + include/grub/video.h | 12 +++ include/multiboot.h | 38 ++++++- include/multiboot2.h | 38 ++++++- loader/i386/multiboot.c | 33 +++++- loader/i386/multiboot_mbi.c | 194 +++++++++++++++++++++++++++++++++++- video/efi_gop.c | 1 + video/efi_uga.c | 1 + video/i386/pc/vbe.c | 1 + video/video.c | 8 ++ 11 files changed, 345 insertions(+), 7 deletions(-) create mode 100644 ChangeLog.mbivid diff --git a/ChangeLog.mbivid b/ChangeLog.mbivid new file mode 100644 index 000000000..da4fa3c88 --- /dev/null +++ b/ChangeLog.mbivid @@ -0,0 +1,24 @@ +2010-01-14 Vladimir Serbinenko + + 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. diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index f9edb0c59..665292e33 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -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); diff --git a/include/grub/video.h b/include/grub/video.h index 4145db465..437c98eb9 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -159,10 +159,19 @@ struct grub_video_palette_data 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 @@ grub_err_t grub_video_set_mode (const char *modestring, 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 */ diff --git a/include/multiboot.h b/include/multiboot.h index da7afd9b3..460347d22 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -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 @@ 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; + 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; diff --git a/include/multiboot2.h b/include/multiboot2.h index 0488849d7..8bcf5a7e4 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -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 @@ 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; + 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; diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index 5dc304117..15f9977c9 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -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 #include #include -#include -#include #include #include #include @@ -232,6 +229,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); diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index 58802d44c..f362b800d 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -29,6 +29,18 @@ #include #include #include +#include + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#include +#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 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 +92,12 @@ 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 () +#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_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; +} + +#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 @@ 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 +361,19 @@ 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; + } +#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; } diff --git a/video/efi_gop.c b/video/efi_gop.c index 30863c1ed..13ef0ddae 100644 --- a/video/efi_gop.c +++ b/video/efi_gop.c @@ -353,6 +353,7 @@ grub_video_gop_get_info_and_fini (struct grub_video_mode_info *mode_info, 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, diff --git a/video/efi_uga.c b/video/efi_uga.c index 12ca35cde..7ef7594cc 100644 --- a/video/efi_uga.c +++ b/video/efi_uga.c @@ -300,6 +300,7 @@ grub_video_uga_get_info_and_fini (struct grub_video_mode_info *mode_info, 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, diff --git a/video/i386/pc/vbe.c b/video/i386/pc/vbe.c index 17d9b3282..918bab0b0 100644 --- a/video/i386/pc/vbe.c +++ b/video/i386/pc/vbe.c @@ -557,6 +557,7 @@ grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info, 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, diff --git a/video/video.c b/video/video.c index 682bebcbf..e678c2982 100644 --- a/video/video.c +++ b/video/video.c @@ -93,6 +93,14 @@ grub_video_get_info (struct grub_video_mode_info *mode_info) 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, From 017402922228e69ff88f11a3d396ee2ed03f0420 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 15 Jan 2010 15:46:59 +0100 Subject: [PATCH 02/12] Add EGA text support --- include/multiboot.h | 6 ++-- include/multiboot2.h | 6 ++-- loader/i386/multiboot_mbi.c | 69 ++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/include/multiboot.h b/include/multiboot.h index 460347d22..57c154c98 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -195,6 +195,9 @@ struct multiboot_info 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 { @@ -223,9 +226,6 @@ struct multiboot_color multiboot_uint8_t blue; }; -#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 -#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 - struct multiboot_mmap_entry { multiboot_uint32_t size; diff --git a/include/multiboot2.h b/include/multiboot2.h index 8bcf5a7e4..a241a70ad 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -195,6 +195,9 @@ struct multiboot_info 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 { @@ -223,9 +226,6 @@ struct multiboot_color multiboot_uint8_t blue; }; -#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 -#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 - struct multiboot_mmap_entry { multiboot_uint32_t size; diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index f362b800d..ddbbf3cfd 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -162,11 +162,12 @@ set_video_mode (void) #if HAS_VBE static grub_err_t fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, - grub_uint32_t ptrdest) + 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) @@ -180,14 +181,27 @@ fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, 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."); + 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."); + mode_info = (struct grub_vbe_mode_info_block *) ptrorig; mbi->vbe_mode_info = ptrdest; - grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_mode_info_block)); + /* 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); @@ -198,6 +212,21 @@ fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, 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 @@ -209,25 +238,25 @@ retrieve_video_parameters (struct multiboot_info *mbi, grub_err_t err; struct grub_video_mode_info mode_info; void *framebuffer; -#if HAS_VBE - int vbe_active; -#endif + grub_video_driver_id_t driv_id; struct grub_video_palette_data palette[256]; err = set_video_mode (); if (err) - return err; + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } 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)); - } + 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); @@ -277,8 +306,8 @@ retrieve_video_parameters (struct multiboot_info *mbi, mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; #if HAS_VBE - if (vbe_active) - fill_vbe_info (mbi, ptrorig, ptrdest); + if (driv_id == GRUB_VIDEO_DRIVER_VBE) + return fill_vbe_info (mbi, ptrorig, ptrdest, 0); #endif return GRUB_ERR_NONE; From 5408044f4c6805bfbec81a6a166218b37899d9fd Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 16 Jan 2010 16:25:43 +0100 Subject: [PATCH 03/12] Multiboot 2 tags support --- ChangeLog.tag | 40 +++ conf/i386.rmk | 2 +- include/grub/i386/multiboot.h | 8 - include/grub/multiboot.h | 21 +- include/multiboot2.h | 257 ++++++++----------- loader/i386/multiboot.c | 138 +++++++++- loader/i386/multiboot_mbi.c | 210 ++++----------- loader/i386/multiboot_mbi2.c | 468 ++++++++++++++++++++++++++++++++++ 8 files changed, 827 insertions(+), 317 deletions(-) create mode 100644 ChangeLog.tag create mode 100644 loader/i386/multiboot_mbi2.c diff --git a/ChangeLog.tag b/ChangeLog.tag new file mode 100644 index 000000000..dbeea1017 --- /dev/null +++ b/ChangeLog.tag @@ -0,0 +1,40 @@ +2010-01-16 Vladimir Serbinenko + + Multiboot2 tag support + + * conf/i386.rmk (multiboot2_mod_SOURCES): Replace + loader/i386/multiboot_mbi.c with loader/i386/multiboot_mbi2.c. + * include/grub/i386/multiboot.h (grub_multiboot_real_boot): Removed. + (grub_multiboot2_real_boot): Likewise. + * include/grub/multiboot.h (grub_multiboot_set_accepts_video): Removed. + (grub_get_multiboot_mmap_len): New proto. + (grub_fill_multiboot_mmap): Likewise. + (grub_multiboot_set_video_mode): Likewise. + (grub_multiboot_fill_vbe_info_real): Likewise. + * include/multiboot2.h: Resynced with specification. + * loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): Moved from here... + * loader/i386/multiboot.c (DEFAULT_VIDEO_MODE): ... here. + * loader/i386/multiboot_mbi.c (HAS_VGA_TEXT): Moved from here .. + * include/grub/multiboot.h (GRUB_MACHINE_HAS_VGA_TEXT): ... here. All + users updated. + * loader/i386/multiboot_mbi.c (HAS_VBE): Moved from here .. + * include/grub/multiboot.h (GRUB_MACHINE_HAS_VBE): ... here. All + users updated. + * loader/i386/multiboot_mbi.c (accepts_video): Moved from here... + * loader/i386/multiboot.c (accepts_video): ... here. All users updated. + * loader/i386/multiboot_mbi.c (grub_multiboot_set_accepts_video): + Removed. + * loader/i386/multiboot_mbi.c (grub_get_multiboot_mmap_len): + Moved from here... + * loader/i386/multiboot.c (grub_get_multiboot_mmap_len): ... here. + * loader/i386/multiboot_mbi.c (grub_fill_multiboot_mmap): + Moved from here... + * loader/i386/multiboot.c (grub_fill_multiboot_mmap): ... here. + * loader/i386/multiboot_mbi.c (set_video_mode): Moved from here... + * loader/i386/multiboot.c (grub_multiboot_set_video_mode): ... here. + All users updated. + * loader/i386/multiboot_mbi.c (fill_vbe_info): Moved generic parts + from here... + * loader/i386/multiboot.c (grub_multiboot_fill_vbe_info_real): ... here. + All users updated. + * loader/i386/multiboot_mbi2.c: New file. diff --git a/conf/i386.rmk b/conf/i386.rmk index 7ef337c61..064ee3ab4 100644 --- a/conf/i386.rmk +++ b/conf/i386.rmk @@ -36,7 +36,7 @@ multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) pkglib_MODULES += multiboot2.mod multiboot2_mod_SOURCES = loader/i386/multiboot.c \ - loader/i386/multiboot_mbi.c \ + loader/i386/multiboot_mbi2.c \ loader/multiboot_loader.c multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2 multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h index 584955449..8131e9477 100644 --- a/include/grub/i386/multiboot.h +++ b/include/grub/i386/multiboot.h @@ -19,14 +19,6 @@ #ifndef GRUB_MULTIBOOT_CPU_HEADER #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)); - extern grub_uint32_t grub_multiboot_payload_eip; extern char *grub_multiboot_payload_orig; extern grub_addr_t grub_multiboot_payload_dest; diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 665292e33..8a7289820 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -35,8 +35,6 @@ 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); @@ -46,5 +44,24 @@ grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size, int argc, char *argv[]); void grub_multiboot_set_bootdev (void); +grub_uint32_t grub_get_multiboot_mmap_len (void); +void grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry); +grub_err_t grub_multiboot_set_video_mode (void); + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#include +grub_err_t +grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info, + struct grub_vbe_mode_info_block *vbe_mode_info, + multiboot_uint16_t *vbe_mode, + multiboot_uint16_t *vbe_interface_seg, + multiboot_uint16_t *vbe_interface_off, + multiboot_uint16_t *vbe_interface_len); +#define GRUB_MACHINE_HAS_VBE 1 +#define GRUB_MACHINE_HAS_VGA_TEXT 1 +#else +#define GRUB_MACHINE_HAS_VBE 0 +#define GRUB_MACHINE_HAS_VGA_TEXT 0 +#endif #endif /* ! GRUB_MULTIBOOT_HEADER */ diff --git a/include/multiboot2.h b/include/multiboot2.h index a241a70ad..a76364fa7 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -51,42 +51,15 @@ /* This flag indicates the use of the address fields in the header. */ #define MULTIBOOT_AOUT_KLUDGE 0x00010000 -/* Flags to be set in the 'flags' member of the multiboot info structure. */ - -/* is there basic lower/upper memory information? */ -#define MULTIBOOT_INFO_MEMORY 0x00000001 -/* is there a boot device set? */ -#define MULTIBOOT_INFO_BOOTDEV 0x00000002 -/* is the command-line defined? */ -#define MULTIBOOT_INFO_CMDLINE 0x00000004 -/* are there modules to do something with? */ -#define MULTIBOOT_INFO_MODS 0x00000008 - -/* These next two are mutually exclusive */ - -/* is there a symbol table loaded? */ -#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 -/* is there an ELF section header table? */ -#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 - -/* is there a full memory map? */ -#define MULTIBOOT_INFO_MEM_MAP 0x00000040 - -/* Is there drive info? */ -#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 - -/* Is there a config table? */ -#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 - -/* Is there a boot loader name? */ -#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 - -/* Is there a APM table? */ -#define MULTIBOOT_INFO_APM_TABLE 0x00000400 - -/* Is there video information? */ -#define MULTIBOOT_INFO_VBE_INFO 0x00000800 -#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 #ifndef ASM_FILE @@ -120,105 +93,6 @@ struct multiboot_header multiboot_uint32_t depth; }; -/* The symbol table for a.out. */ -struct multiboot_aout_symbol_table -{ - multiboot_uint32_t tabsize; - multiboot_uint32_t strsize; - multiboot_uint32_t addr; - multiboot_uint32_t reserved; -}; -typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; - -/* The section header table for ELF. */ -struct multiboot_elf_section_header_table -{ - multiboot_uint32_t num; - multiboot_uint32_t size; - multiboot_uint32_t addr; - multiboot_uint32_t shndx; -}; -typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; - -struct multiboot_info -{ - /* Multiboot info version number */ - multiboot_uint32_t flags; - - /* Available memory from BIOS */ - multiboot_uint32_t mem_lower; - multiboot_uint32_t mem_upper; - - /* "root" partition */ - multiboot_uint32_t boot_device; - - /* Kernel command line */ - multiboot_uint32_t cmdline; - - /* Boot-Module list */ - multiboot_uint32_t mods_count; - multiboot_uint32_t mods_addr; - - union - { - multiboot_aout_symbol_table_t aout_sym; - multiboot_elf_section_header_table_t elf_sec; - } u; - - /* Memory Mapping buffer */ - multiboot_uint32_t mmap_length; - multiboot_uint32_t mmap_addr; - - /* Drive Info buffer */ - multiboot_uint32_t drives_length; - multiboot_uint32_t drives_addr; - - /* ROM configuration table */ - multiboot_uint32_t config_table; - - /* Boot Loader Name */ - multiboot_uint32_t boot_loader_name; - - /* APM table */ - multiboot_uint32_t apm_table; - - /* Video */ - multiboot_uint32_t vbe_control_info; - multiboot_uint32_t vbe_mode_info; - multiboot_uint16_t vbe_mode; - 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; @@ -237,19 +111,114 @@ struct multiboot_mmap_entry } __attribute__((packed)); typedef struct multiboot_mmap_entry multiboot_memory_map_t; -struct multiboot_mod_list +struct multiboot_tag { - /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + multiboot_uint32_t type; + multiboot_uint32_t size; +}; + +struct multiboot_tag_string +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + char string[0]; +}; + +struct multiboot_tag_module +{ + multiboot_uint32_t type; + multiboot_uint32_t size; multiboot_uint32_t mod_start; multiboot_uint32_t mod_end; - - /* Module command line */ - multiboot_uint32_t cmdline; - - /* padding to take it to 16 bytes (must be zero) */ - multiboot_uint32_t pad; + char cmdline[0]; +}; + +struct multiboot_tag_basic_meminfo +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; +}; + +struct multiboot_tag_bootdev +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t biosdev; + multiboot_uint32_t slice; + multiboot_uint32_t part; +}; + +struct multiboot_tag_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + struct multiboot_mmap_entry entries[0]; +}; + +struct multiboot_vbe_info_block +{ + multiboot_uint8_t external_specification[512]; +}; + +struct multiboot_vbe_mode_info_block +{ + multiboot_uint8_t external_specification[256]; +}; + +struct multiboot_tag_vbe +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + struct multiboot_vbe_info_block vbe_control_info; + struct multiboot_vbe_mode_info_block vbe_mode_info; +}; + +struct multiboot_tag_framebuffer_common +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + 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; +}; + +struct multiboot_tag_framebuffer +{ + struct multiboot_tag_framebuffer_common common; + + union + { + struct + { + multiboot_uint16_t framebuffer_palette_num_colors; + struct multiboot_color framebuffer_palette[0]; + }; + 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_mod_list multiboot_module_t; #endif /* ! ASM_FILE */ diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index 0ac3ca339..86bb91ec8 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -44,11 +44,18 @@ #include #include #include +#include #ifdef GRUB_MACHINE_EFI #include #endif +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#define DEFAULT_VIDEO_MODE "text" +#else +#define DEFAULT_VIDEO_MODE "auto" +#endif + extern grub_dl_t my_mod; static grub_size_t code_size, alloc_mbi; @@ -56,6 +63,135 @@ char *grub_multiboot_payload_orig; grub_addr_t grub_multiboot_payload_dest; grub_size_t grub_multiboot_pure_size; grub_uint32_t grub_multiboot_payload_eip; +static int accepts_video; + +/* Return the length of the Multiboot mmap that will be needed to allocate + our platform's map. */ +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. */ +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); +} + +grub_err_t +grub_multiboot_set_video_mode (void) +{ + grub_err_t err; + const char *modevar; + + if (accepts_video || !GRUB_MACHINE_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 GRUB_MACHINE_HAS_VBE +grub_err_t +grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info, + struct grub_vbe_mode_info_block *vbe_mode_info, + multiboot_uint16_t *vbe_mode, + multiboot_uint16_t *vbe_interface_seg, + multiboot_uint16_t *vbe_interface_off, + multiboot_uint16_t *vbe_interface_len) +{ + grub_vbe_status_t status; + 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."); + grub_memcpy (vbe_control_info, scratch, 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"); + + /* get_mode_info isn't available for mode 3. */ + if (*vbe_mode == 3) + { + grub_memset (vbe_mode_info, 0, sizeof (struct grub_vbe_mode_info_block)); + vbe_mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT; + vbe_mode_info->x_resolution = 80; + vbe_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 (vbe_mode_info, scratch, + sizeof (struct grub_vbe_mode_info_block)); + } + + /* FIXME: retrieve those. */ + *vbe_interface_seg = 0; + *vbe_interface_off = 0; + *vbe_interface_len = 0; + + return GRUB_ERR_NONE; +} +#endif static grub_err_t grub_multiboot_boot (void) @@ -265,7 +401,7 @@ grub_multiboot (int argc, char *argv[]) } } - grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE)); + accepts_video = !!(header->flags & MULTIBOOT_VIDEO_MODE); grub_multiboot_set_bootdev (); diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index ddbbf3cfd..9c45b3352 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -31,17 +31,6 @@ #include #include -#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) -#include -#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; @@ -58,34 +47,6 @@ 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) @@ -93,142 +54,45 @@ 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 () -#if HAS_VBE +#if GRUB_MACHINE_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. */ -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); -} - +#if GRUB_MACHINE_HAS_VBE static grub_err_t -set_video_mode (void) +fill_vbe_info (struct multiboot_info *mbi, + struct grub_vbe_mode_info_block **vbe_mode_info_out, + grub_uint8_t *ptrorig, grub_addr_t ptrdest) { + struct grub_vbe_info_block *vbe_control_info; + struct grub_vbe_mode_info_block *vbe_mode_info; 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."); - + vbe_control_info = (struct grub_vbe_info_block *) ptrorig; 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; + vbe_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; + err = grub_multiboot_fill_vbe_info_real (vbe_control_info, vbe_mode_info, + &mbi->vbe_mode, + &mbi->vbe_interface_seg, + &mbi->vbe_interface_off, + &mbi->vbe_interface_len); + if (err) + return err; 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; - } - + if (vbe_mode_info_out) + *vbe_mode_info_out = vbe_mode_info; return GRUB_ERR_NONE; } + #endif static grub_err_t @@ -241,7 +105,7 @@ retrieve_video_parameters (struct multiboot_info *mbi, grub_video_driver_id_t driv_id; struct grub_video_palette_data palette[256]; - err = set_video_mode (); + err = grub_multiboot_set_video_mode (); if (err) { grub_print_error (); @@ -251,9 +115,29 @@ retrieve_video_parameters (struct multiboot_info *mbi, grub_video_get_palette (0, ARRAY_SIZE (palette), palette); driv_id = grub_video_get_driver_id (); -#if HAS_VGA_TEXT +#if GRUB_MACHINE_HAS_VGA_TEXT if (driv_id == GRUB_VIDEO_DRIVER_NONE) - return fill_vbe_info (mbi, ptrorig, ptrdest, 1); + { + struct grub_vbe_mode_info_block *vbe_mode_info; + err = fill_vbe_info (mbi, &vbe_mode_info, ptrorig, ptrdest); + if (err) + return err; + if (vbe_mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) + { + mbi->framebuffer_addr = 0xb8000; + + mbi->framebuffer_pitch = 2 * vbe_mode_info->x_resolution; + mbi->framebuffer_width = vbe_mode_info->x_resolution; + mbi->framebuffer_height = vbe_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; + } #else if (driv_id == GRUB_VIDEO_DRIVER_NONE) return GRUB_ERR_NONE; @@ -305,9 +189,13 @@ retrieve_video_parameters (struct multiboot_info *mbi, mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; -#if HAS_VBE +#if GRUB_MACHINE_HAS_VBE if (driv_id == GRUB_VIDEO_DRIVER_VBE) - return fill_vbe_info (mbi, ptrorig, ptrdest, 0); + { + err = fill_vbe_info (mbi, NULL, ptrorig, ptrdest); + if (err) + return err; + } #endif return GRUB_ERR_NONE; @@ -396,7 +284,7 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, grub_print_error (); grub_errno = GRUB_ERR_NONE; } -#if HAS_VBE +#if GRUB_MACHINE_HAS_VBE ptrorig += sizeof (struct grub_vbe_info_block); ptrdest += sizeof (struct grub_vbe_info_block); ptrorig += sizeof (struct grub_vbe_mode_info_block); diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c new file mode 100644 index 000000000..031d4c0eb --- /dev/null +++ b/loader/i386/multiboot_mbi2.c @@ -0,0 +1,468 @@ +/* + * 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 . + */ + +#include +#include +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#include +#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_addr_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 int bootdev_set; +static grub_uint32_t biosdev, slice, part; + +grub_size_t +grub_multiboot_get_mbi_size (void) +{ + return sizeof (struct multiboot_tag) + + (sizeof (struct multiboot_tag_string) + ALIGN_UP (cmdline_size, 4)) + + (sizeof (struct multiboot_tag_string) + + ALIGN_UP (sizeof (PACKAGE_STRING), 4)) + + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd) + + sizeof (struct multiboot_tag_basic_meminfo) + + sizeof (struct multiboot_tag_bootdev) + + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_len ()) + + sizeof (struct multiboot_tag_vbe); +} + +#ifdef GRUB_MACHINE_HAS_VBE + +static grub_err_t +fill_vbe_info (struct grub_vbe_mode_info_block **vbe_mode_info_out, + grub_uint8_t **ptrorig) +{ + struct multiboot_tag_vbe *tag = (struct multiboot_tag_vbe *) *ptrorig; + grub_err_t err; + + tag->type = MULTIBOOT_TAG_TYPE_VBE; + tag->size = 0; + err = grub_multiboot_fill_vbe_info_real ((struct grub_vbe_info_block *) + &(tag->vbe_control_info), + (struct grub_vbe_mode_info_block *) + &(tag->vbe_mode_info), + &(tag->vbe_mode), + &(tag->vbe_interface_seg), + &(tag->vbe_interface_off), + &(tag->vbe_interface_len)); + if (err) + return err; + if (vbe_mode_info_out) + *vbe_mode_info_out = (struct grub_vbe_mode_info_block *) + &(tag->vbe_mode_info); + tag->size = sizeof (struct multiboot_tag_vbe); + *ptrorig += tag->size; + return GRUB_ERR_NONE; +} + +#endif + +static grub_err_t +retrieve_video_parameters (grub_uint8_t **ptrorig) +{ + 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]; + struct multiboot_tag_framebuffer *tag + = (struct multiboot_tag_framebuffer *) *ptrorig; + + err = grub_multiboot_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) + { + struct grub_vbe_mode_info_block *vbe_mode_info; + err = fill_vbe_info (&vbe_mode_info, ptrorig); + if (err) + return err; + if (vbe_mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) + { + tag = (struct multiboot_tag_framebuffer *) *ptrorig; + tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->common.size = 0; + + tag->common.framebuffer_addr = 0xb8000; + + tag->common.framebuffer_pitch = 2 * vbe_mode_info->x_resolution; + tag->common.framebuffer_width = vbe_mode_info->x_resolution; + tag->common.framebuffer_height = vbe_mode_info->y_resolution; + + tag->common.framebuffer_bpp = 16; + + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; + tag->common.size = sizeof (tag->common); + *ptrorig += tag->common.size; + } + return GRUB_ERR_NONE; + } +#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; + + tag = (struct multiboot_tag_framebuffer *) *ptrorig; + tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->common.size = 0; + + tag->common.framebuffer_addr = (grub_addr_t) framebuffer; + tag->common.framebuffer_pitch = mode_info.pitch; + + tag->common.framebuffer_width = mode_info.width; + tag->common.framebuffer_height = mode_info.height; + + tag->common.framebuffer_bpp = mode_info.bpp; + + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) + { + unsigned i; + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; + tag->framebuffer_palette_num_colors = mode_info.number_of_colors; + if (tag->framebuffer_palette_num_colors > ARRAY_SIZE (palette)) + tag->framebuffer_palette_num_colors = ARRAY_SIZE (palette); + tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + + sizeof (multiboot_uint16_t) + tag->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + for (i = 0; i < tag->framebuffer_palette_num_colors; i++) + { + tag->framebuffer_palette[i].red = palette[i].r; + tag->framebuffer_palette[i].green = palette[i].g; + tag->framebuffer_palette[i].blue = palette[i].b; + } + *ptrorig += tag->common.size; + } + else + { + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + tag->framebuffer_red_field_position = mode_info.green_field_pos; + tag->framebuffer_red_mask_size = mode_info.green_mask_size; + tag->framebuffer_green_field_position = mode_info.green_field_pos; + tag->framebuffer_green_mask_size = mode_info.green_mask_size; + tag->framebuffer_blue_field_position = mode_info.blue_field_pos; + tag->framebuffer_blue_mask_size = mode_info.blue_mask_size; + + tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + 6; + } + +#if HAS_VBE + if (driv_id == GRUB_VIDEO_DRIVER_VBE) + { + err = fill_vbe_info (NULL, ptrorig); + if (err) + return err; + } +#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_err_t err; + + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + { + struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; + tag->size = sizeof (struct multiboot_tag_string) + + ALIGN_UP (cmdline_size, 4); + grub_memcpy (tag->string, cmdline, cmdline_size); + ptrorig += tag->size; + } + + { + struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; + tag->size = sizeof (struct multiboot_tag_string) + + ALIGN_UP (sizeof (PACKAGE_STRING), 4); + grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING)); + ptrorig += tag->size; + } + + { + unsigned i; + struct module *cur; + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + struct multiboot_tag_module *tag + = (struct multiboot_tag_module *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_MODULE; + tag->size = sizeof (struct multiboot_tag_module) + + ALIGN_UP (sizeof (cur->cmdline_size), 4); + + tag->mod_start = dest + cur->start; + tag->mod_end = tag->mod_start + cur->size; + grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size); + ptrorig += tag->size; + } + } + + { + struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_MMAP; + tag->size = sizeof (struct multiboot_tag_mmap) + + grub_get_multiboot_mmap_len (); + grub_fill_multiboot_mmap (tag->entries); + ptrorig += tag->size; + } + + { + struct multiboot_tag_basic_meminfo *tag + = (struct multiboot_tag_basic_meminfo *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; + tag->size = sizeof (struct multiboot_tag_basic_meminfo); + + /* Convert from bytes to kilobytes. */ + tag->mem_lower = grub_mmap_get_lower () / 1024; + tag->mem_upper = grub_mmap_get_upper () / 1024; + ptrorig += tag->size; + } + + if (bootdev_set) + { + struct multiboot_tag_bootdev *tag + = (struct multiboot_tag_bootdev *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BOOTDEV; + tag->size = sizeof (struct multiboot_tag_bootdev); + + tag->biosdev = biosdev; + tag->slice = slice; + tag->part = part; + ptrorig += tag->size; + } + + { + err = retrieve_video_parameters (&ptrorig); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + } + + { + struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_END; + tag->size = sizeof (struct multiboot_tag); + ptrorig += tag->size; + } + + 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_addr_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; + + modcnt++; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_set_bootdev (void) +{ + char *p; + grub_device_t dev; + + slice = ~0; + part = ~0; + +#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_set = 1; +} From 234328552802a698c7dc66c0d5f204975cd62a64 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 16 Jan 2010 16:36:42 +0100 Subject: [PATCH 04/12] Don't pass biosdev if not booted from BIOS disk --- loader/i386/multiboot_mbi.c | 3 +++ loader/i386/multiboot_mbi2.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index 9c45b3352..3e63b3456 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -417,6 +417,9 @@ grub_multiboot_set_bootdev (void) biosdev = 0xffffffff; #endif + if (biosdev == 0xffffffff) + return; + dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c index 031d4c0eb..de234727b 100644 --- a/loader/i386/multiboot_mbi2.c +++ b/loader/i386/multiboot_mbi2.c @@ -442,6 +442,9 @@ grub_multiboot_set_bootdev (void) biosdev = 0xffffffff; #endif + if (biosdev == 0xffffffff) + return; + dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { From 1c4ad986aa89b41f8478ae94689557f362c9fe82 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 16 Jan 2010 17:18:02 +0100 Subject: [PATCH 05/12] size field in tagged mbi --- loader/i386/multiboot_mbi2.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c index de234727b..636b63923 100644 --- a/loader/i386/multiboot_mbi2.c +++ b/loader/i386/multiboot_mbi2.c @@ -62,7 +62,7 @@ static grub_uint32_t biosdev, slice, part; grub_size_t grub_multiboot_get_mbi_size (void) { - return sizeof (struct multiboot_tag) + return sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) + (sizeof (struct multiboot_tag_string) + ALIGN_UP (cmdline_size, 4)) + (sizeof (struct multiboot_tag_string) + ALIGN_UP (sizeof (PACKAGE_STRING), 4)) @@ -221,12 +221,15 @@ 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_uint8_t *ptrorig; + grub_uint8_t *mbistart = (grub_uint8_t *) orig + buf_off; grub_err_t err; if (bufsize < grub_multiboot_get_mbi_size ()) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + ptrorig = (grub_uint8_t *) orig + buf_off + sizeof (grub_uint32_t); + { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; @@ -314,6 +317,8 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, ptrorig += tag->size; } + *(grub_uint32_t *) mbistart = ptrorig - mbistart; + return GRUB_ERR_NONE; } From 8eb567e6629c892428c1a563afb6aa40d1a74f64 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 7 Mar 2010 14:59:15 +0100 Subject: [PATCH 06/12] Update with newest mbtag spec --- include/grub/multiboot.h | 2 +- include/multiboot2.h | 33 ++++++++++++++- loader/i386/multiboot.c | 4 +- loader/i386/multiboot_mbi.c | 6 ++- loader/i386/multiboot_mbi2.c | 78 +++++++++++++++++++----------------- 5 files changed, 81 insertions(+), 42 deletions(-) diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 27d4d816d..c108e5eef 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -44,7 +44,7 @@ grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size, int argc, char *argv[]); void grub_multiboot_set_bootdev (void); -grub_uint32_t grub_get_multiboot_mmap_len (void); +grub_uint32_t grub_get_multiboot_mmap_count (void); grub_err_t grub_multiboot_set_video_mode (void); #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) diff --git a/include/multiboot2.h b/include/multiboot2.h index 20c5c5696..36710ddf6 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -51,6 +51,7 @@ /* This flag indicates the use of the address fields in the header. */ #define MULTIBOOT_AOUT_KLUDGE 0x00010000 +#define MULTIBOOT_TAG_ALIGN 8 #define MULTIBOOT_TAG_TYPE_END 0 #define MULTIBOOT_TAG_TYPE_CMDLINE 1 #define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 @@ -102,7 +103,6 @@ struct multiboot_color struct multiboot_mmap_entry { - multiboot_uint32_t size; multiboot_uint64_t addr; multiboot_uint64_t len; #define MULTIBOOT_MEMORY_AVAILABLE 1 @@ -110,6 +110,7 @@ struct multiboot_mmap_entry #define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 #define MULTIBOOT_MEMORY_NVS 4 multiboot_uint32_t type; + multiboot_uint32_t zero; } __attribute__((packed)); typedef struct multiboot_mmap_entry multiboot_memory_map_t; @@ -123,6 +124,8 @@ struct multiboot_tag_string { multiboot_uint32_t type; multiboot_uint32_t size; + multiboot_uint32_t entry_size; + multiboot_uint32_t entry_version; char string[0]; }; @@ -156,6 +159,8 @@ struct multiboot_tag_mmap { multiboot_uint32_t type; multiboot_uint32_t size; + multiboot_uint32_t entry_size; + multiboot_uint32_t entry_version; struct multiboot_mmap_entry entries[0]; }; @@ -197,6 +202,7 @@ struct multiboot_tag_framebuffer_common #define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 #define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 multiboot_uint8_t framebuffer_type; + multiboot_uint16_t reserved; }; struct multiboot_tag_framebuffer @@ -222,6 +228,31 @@ struct multiboot_tag_framebuffer }; }; +struct multiboot_tag_elf_sections +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t num; + multiboot_uint32_t entsize; + multiboot_uint32_t shndx; + char sections[0]; +}; + +struct multiboot_tag_apm +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + #endif /* ! ASM_FILE */ #endif /* ! MULTIBOOT_HEADER */ diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index 5f9751f33..dab81dc8c 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -68,7 +68,7 @@ static int accepts_video; /* Return the length of the Multiboot mmap that will be needed to allocate our platform's map. */ grub_uint32_t -grub_get_multiboot_mmap_len (void) +grub_get_multiboot_mmap_count (void) { grub_size_t count = 0; @@ -83,7 +83,7 @@ grub_get_multiboot_mmap_len (void) grub_mmap_iterate (hook); - return count * sizeof (struct multiboot_mmap_entry); + return count; } grub_err_t diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index a8133a705..0d5db3c13 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -53,7 +53,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_count () * sizeof (struct multiboot_mmap_entry) #if GRUB_MACHINE_HAS_VBE + sizeof (struct grub_vbe_info_block) + sizeof (struct grub_vbe_mode_info_block) @@ -233,7 +234,8 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, mbi->mods_count = 0; } - mmap_size = grub_get_multiboot_mmap_len (); + mmap_size = grub_get_multiboot_mmap_count () + * sizeof (struct multiboot_mmap_entry); grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); mbi->mmap_length = mmap_size; mbi->mmap_addr = ptrdest; diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c index a53bbe50a..ab803734f 100644 --- a/loader/i386/multiboot_mbi2.c +++ b/loader/i386/multiboot_mbi2.c @@ -62,15 +62,17 @@ static grub_uint32_t biosdev, slice, part; grub_size_t grub_multiboot_get_mbi_size (void) { - return sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) - + (sizeof (struct multiboot_tag_string) + ALIGN_UP (cmdline_size, 4)) + return 2 * sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) + (sizeof (struct multiboot_tag_string) - + ALIGN_UP (sizeof (PACKAGE_STRING), 4)) + + ALIGN_UP (cmdline_size, MULTIBOOT_TAG_ALIGN)) + + (sizeof (struct multiboot_tag_string) + + ALIGN_UP (sizeof (PACKAGE_STRING), MULTIBOOT_TAG_ALIGN)) + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd) + sizeof (struct multiboot_tag_basic_meminfo) - + sizeof (struct multiboot_tag_bootdev) - + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_len ()) - + sizeof (struct multiboot_tag_vbe); + + ALIGN_UP (sizeof (struct multiboot_tag_bootdev), MULTIBOOT_TAG_ALIGN) + + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_count () + * sizeof (struct multiboot_mmap_entry)) + + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1; } #ifdef GRUB_MACHINE_HAS_VBE @@ -98,7 +100,7 @@ fill_vbe_info (struct grub_vbe_mode_info_block **vbe_mode_info_out, *vbe_mode_info_out = (struct grub_vbe_mode_info_block *) &(tag->vbe_mode_info); tag->size = sizeof (struct multiboot_tag_vbe); - *ptrorig += tag->size; + *ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); return GRUB_ERR_NONE; } @@ -106,9 +108,9 @@ fill_vbe_info (struct grub_vbe_mode_info_block **vbe_mode_info_out, /* Fill previously allocated Multiboot mmap. */ static void -grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) +grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag) { - struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; + struct multiboot_mmap_entry *mmap_entry = tag->entries; 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) @@ -137,12 +139,17 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; break; } - mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); mmap_entry++; return 0; } + tag->type = MULTIBOOT_TAG_TYPE_MMAP; + tag->size = sizeof (struct multiboot_tag_mmap) + + sizeof (struct multiboot_mmap_entry) * grub_get_multiboot_mmap_count (); + tag->entry_size = sizeof (struct multiboot_mmap_entry); + tag->entry_version = 0; + grub_mmap_iterate (hook); } @@ -190,7 +197,8 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; tag->common.size = sizeof (tag->common); - *ptrorig += tag->common.size; + tag->common.reserved = 0; + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); } return GRUB_ERR_NONE; } @@ -214,6 +222,8 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) tag->common.framebuffer_height = mode_info.height; tag->common.framebuffer_bpp = mode_info.bpp; + + tag->common.reserved = 0; if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) { @@ -231,7 +241,6 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) tag->framebuffer_palette[i].green = palette[i].g; tag->framebuffer_palette[i].blue = palette[i].b; } - *ptrorig += tag->common.size; } else { @@ -246,6 +255,7 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + 6; } + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); #if HAS_VBE if (driv_id == GRUB_VIDEO_DRIVER_VBE) @@ -264,30 +274,29 @@ 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 *mbistart = (grub_uint8_t *) orig + buf_off; + grub_uint8_t *mbistart = (grub_uint8_t *) orig + buf_off + + (ALIGN_UP (dest + buf_off, MULTIBOOT_TAG_ALIGN) - (dest + buf_off)); grub_err_t err; if (bufsize < grub_multiboot_get_mbi_size ()) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); - ptrorig = (grub_uint8_t *) orig + buf_off + sizeof (grub_uint32_t); + ptrorig = mbistart + 2 * sizeof (grub_uint32_t); { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; - tag->size = sizeof (struct multiboot_tag_string) - + ALIGN_UP (cmdline_size, 4); + tag->size = sizeof (struct multiboot_tag_string) + cmdline_size; grub_memcpy (tag->string, cmdline, cmdline_size); - ptrorig += tag->size; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; - tag->size = sizeof (struct multiboot_tag_string) - + ALIGN_UP (sizeof (PACKAGE_STRING), 4); + tag->size = sizeof (struct multiboot_tag_string) + sizeof (PACKAGE_STRING); grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING)); - ptrorig += tag->size; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } { @@ -299,23 +308,18 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, struct multiboot_tag_module *tag = (struct multiboot_tag_module *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_MODULE; - tag->size = sizeof (struct multiboot_tag_module) - + ALIGN_UP (sizeof (cur->cmdline_size), 4); - + tag->size = sizeof (struct multiboot_tag_module) + cur->cmdline_size; tag->mod_start = dest + cur->start; tag->mod_end = tag->mod_start + cur->size; grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size); - ptrorig += tag->size; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } } { struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig; - tag->type = MULTIBOOT_TAG_TYPE_MMAP; - tag->size = sizeof (struct multiboot_tag_mmap) - + grub_get_multiboot_mmap_len (); - grub_fill_multiboot_mmap (tag->entries); - ptrorig += tag->size; + grub_fill_multiboot_mmap (tag); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } { @@ -327,7 +331,7 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, /* Convert from bytes to kilobytes. */ tag->mem_lower = grub_mmap_get_lower () / 1024; tag->mem_upper = grub_mmap_get_upper () / 1024; - ptrorig += tag->size; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } if (bootdev_set) @@ -340,7 +344,7 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, tag->biosdev = biosdev; tag->slice = slice; tag->part = part; - ptrorig += tag->size; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } { @@ -356,10 +360,11 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_END; tag->size = sizeof (struct multiboot_tag); - ptrorig += tag->size; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } - *(grub_uint32_t *) mbistart = ptrorig - mbistart; + ((grub_uint32_t *) mbistart)[0] = ptrorig - mbistart; + ((grub_uint32_t *) mbistart)[1] = 0; return GRUB_ERR_NONE; } @@ -447,7 +452,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size, return grub_errno; } newmod->cmdline_size = len; - total_modcmd += ALIGN_UP (len, 4); + total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN); for (i = 0; i < argc; i++) { @@ -495,8 +500,8 @@ grub_multiboot_set_bootdev (void) dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { - - p = dev->disk->partition->partmap->get_name (dev->disk->partition); + char *p0; + p = p0 = dev->disk->partition->partmap->get_name (dev->disk->partition); if (p) { if ((p[0] >= '0') && (p[0] <= '9')) @@ -510,6 +515,7 @@ grub_multiboot_set_bootdev (void) if ((p[0] >= 'a') && (p[0] <= 'z')) part = p[0] - 'a'; } + grub_free (p0); } if (dev) grub_device_close (dev); From b1f6f35ae91d6ee413b8d319e73b7be172a56491 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 8 Mar 2010 15:40:57 +0100 Subject: [PATCH 07/12] Preparation for mbh tag --- conf/i386.rmk | 6 +- include/grub/multiboot.h | 16 +++ include/multiboot.h | 1 + include/multiboot2.h | 78 ++++++++++- loader/i386/multiboot.c | 236 ++++++++++++++-------------------- loader/i386/multiboot_elfxx.c | 5 +- loader/i386/multiboot_mbi.c | 131 +++++++++++++++++++ loader/multiboot_loader.c | 150 --------------------- 8 files changed, 318 insertions(+), 305 deletions(-) delete mode 100644 loader/multiboot_loader.c diff --git a/conf/i386.rmk b/conf/i386.rmk index e5bd27265..076da3bb2 100644 --- a/conf/i386.rmk +++ b/conf/i386.rmk @@ -34,16 +34,14 @@ setpci_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += multiboot.mod multiboot_mod_SOURCES = loader/i386/multiboot.c \ - loader/i386/multiboot_mbi.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) pkglib_MODULES += multiboot2.mod multiboot2_mod_SOURCES = loader/i386/multiboot.c \ - loader/i386/multiboot_mbi2.c \ - loader/multiboot_loader.c + loader/i386/multiboot_mbi2.c multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2 multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) multiboot2_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index c108e5eef..89efbc6dd 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -20,6 +20,8 @@ #ifndef GRUB_MULTIBOOT_HEADER #define GRUB_MULTIBOOT_HEADER 1 +#include + #ifdef GRUB_USE_MULTIBOOT2 #include /* Same thing as far as our loader is concerned. */ @@ -63,4 +65,18 @@ grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info, #define GRUB_MACHINE_HAS_VGA_TEXT 0 #endif +#define GRUB_MULTIBOOT_CONSOLE_EGA_TEXT 1 +#define GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER 2 + +grub_err_t +grub_multiboot_set_console (int console_type, int accepted_consoles, + int width, int height, int depth); +grub_err_t +grub_multiboot_load (grub_file_t file); +/* Load ELF32 or ELF64. */ +grub_err_t +grub_multiboot_load_elf (grub_file_t file, void *buffer); +extern grub_size_t grub_multiboot_pure_size; +extern grub_size_t grub_multiboot_alloc_mbi; + #endif /* ! GRUB_MULTIBOOT_HEADER */ diff --git a/include/multiboot.h b/include/multiboot.h index c529c5c5f..fda863e85 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -24,6 +24,7 @@ /* How many bytes from the start of the file we search for the header. */ #define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 /* The magic field should contain this. */ #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 diff --git a/include/multiboot2.h b/include/multiboot2.h index 36710ddf6..dae05a7a3 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -23,7 +23,8 @@ #define MULTIBOOT_HEADER 1 /* How many bytes from the start of the file we search for the header. */ -#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 /* The magic field should contain this. */ #define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 @@ -62,6 +63,17 @@ #define MULTIBOOT_TAG_TYPE_VBE 7 #define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 + +#define GRUB_MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 + #ifndef ASM_FILE typedef unsigned char multiboot_uint8_t; @@ -74,21 +86,73 @@ struct multiboot_header /* Must be MULTIBOOT_MAGIC - see above. */ multiboot_uint32_t magic; - /* Feature flags. */ - multiboot_uint32_t flags; + /* ISA */ + multiboot_uint32_t architecture; + + /* Total header length. */ + multiboot_uint32_t header_length; /* The above fields plus this one must equal 0 mod 2^32. */ multiboot_uint32_t checksum; +}; - /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ +struct multiboot_header_tag +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t flags; +}; + +struct multiboot_header_tag_information_request +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t flags; + multiboot_uint32_t requests[0]; +}; + +struct multiboot_header_tag_address +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t flags; multiboot_uint32_t header_addr; multiboot_uint32_t load_addr; multiboot_uint32_t load_end_addr; multiboot_uint32_t bss_end_addr; - multiboot_uint32_t entry_addr; +}; - /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ - multiboot_uint32_t mode_type; +struct multiboot_header_tag_entry_address +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t flags; + multiboot_uint32_t entry_addr; +}; + +struct multiboot_header_tag_console_flags +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t flags; + multiboot_uint32_t console_flags; +}; + +struct multiboot_header_tag_framebuffer +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t flags; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +struct multiboot_header_tag_module_align +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t flags; multiboot_uint32_t width; multiboot_uint32_t height; multiboot_uint32_t depth; diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index dab81dc8c..17fefc85a 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -26,10 +26,8 @@ * - APM table */ -/* The bits in the required part of flags field we don't support. */ -#define UNSUPPORTED_FLAGS 0x0000fff8 - #include +#include #include #include #include @@ -45,6 +43,7 @@ #include #include #include +#include #ifdef GRUB_MACHINE_EFI #include @@ -56,14 +55,15 @@ #define DEFAULT_VIDEO_MODE "auto" #endif -extern grub_dl_t my_mod; -static grub_size_t code_size, alloc_mbi; +grub_size_t grub_multiboot_alloc_mbi; char *grub_multiboot_payload_orig; grub_addr_t grub_multiboot_payload_dest; grub_size_t grub_multiboot_pure_size; grub_uint32_t grub_multiboot_payload_eip; static int accepts_video; +static grub_dl_t my_mod; + /* Return the length of the Multiboot mmap that will be needed to allocate our platform's map. */ @@ -178,14 +178,14 @@ grub_multiboot_boot (void) }; mbi_size = grub_multiboot_get_mbi_size (); - if (alloc_mbi < mbi_size) + if (grub_multiboot_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; + grub_multiboot_alloc_mbi = mbi_size; } state.ebx = grub_multiboot_payload_dest + grub_multiboot_pure_size; @@ -215,7 +215,7 @@ grub_multiboot_unload (void) grub_relocator32_free (grub_multiboot_payload_orig); - alloc_mbi = 0; + grub_multiboot_alloc_mbi = 0; grub_multiboot_payload_orig = NULL; grub_dl_unref (my_mod); @@ -232,7 +232,7 @@ grub_multiboot_unload (void) #undef MULTIBOOT_LOAD_ELF32 /* Load ELF32 or ELF64. */ -static grub_err_t +grub_err_t grub_multiboot_load_elf (grub_file_t file, void *buffer) { if (grub_multiboot_is_elf32 (buffer)) @@ -243,137 +243,61 @@ grub_multiboot_load_elf (grub_file_t file, void *buffer) return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); } -void -grub_multiboot (int argc, char *argv[]) +grub_err_t +grub_multiboot_set_console (int console_type, int accepted_consoles, + int width, int height, int depth) +{ + if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER) + { + char *buf; + if (depth && width && height) + buf = grub_xasprintf ("%dx%dx%d,%dx%d,auto", width, + height, depth, width, height); + else if (width && height) + buf = grub_xasprintf ("%dx%d,auto", width, height); + else + buf = grub_strdup ("auto"); + + if (!buf) + return grub_errno; + grub_env_set ("gfxpayload", buf); + grub_free (buf); + } + else + grub_env_set ("gfxpayload", "text"); + + accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) { grub_file_t file = 0; - char buffer[MULTIBOOT_SEARCH]; - struct multiboot_header *header; - grub_ssize_t len; + grub_err_t err; grub_loader_unset (); if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); file = grub_gzfile_open (argv[0], 1); if (! file) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); - len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); - if (len < 32) - { - grub_error (GRUB_ERR_BAD_OS, "file too small"); - goto fail; - } - - /* Look for the multiboot header in the buffer. The header should - be at least 12 bytes and aligned on a 4-byte boundary. */ - for (header = (struct multiboot_header *) buffer; - ((char *) header <= buffer + len - 12) || (header = 0); - header = (struct multiboot_header *) ((char *) header + 4)) - { - if (header->magic == MULTIBOOT_HEADER_MAGIC - && !(header->magic + header->flags + header->checksum)) - break; - } - - if (header == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); - goto fail; - } - - if (header->flags & UNSUPPORTED_FLAGS) - { - grub_error (GRUB_ERR_UNKNOWN_OS, - "unsupported flag: 0x%x", header->flags); - goto fail; - } - - grub_relocator32_free (grub_multiboot_payload_orig); - grub_multiboot_payload_orig = NULL; + grub_dl_ref (my_mod); /* Skip filename. */ grub_multiboot_init_mbi (argc - 1, argv + 1); - if (header->flags & MULTIBOOT_AOUT_KLUDGE) - { - int offset = ((char *) header - buffer - - (header->header_addr - header->load_addr)); - int load_size = ((header->load_end_addr == 0) ? file->size - offset : - header->load_end_addr - header->load_addr); + grub_relocator32_free (grub_multiboot_payload_orig); + grub_multiboot_payload_orig = NULL; - if (header->bss_end_addr) - code_size = (header->bss_end_addr - header->load_addr); - else - code_size = load_size; - grub_multiboot_payload_dest = header->load_addr; - - grub_multiboot_pure_size += code_size; - - /* Allocate a bit more to avoid relocations in most cases. */ - alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi); - - if (! grub_multiboot_payload_orig) - goto fail; - - if ((grub_file_seek (file, offset)) == (grub_off_t) -1) - goto fail; - - grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); - if (grub_errno) - goto fail; - - if (header->bss_end_addr) - grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, - header->bss_end_addr - header->load_addr - load_size); - - grub_multiboot_payload_eip = header->entry_addr; - - } - else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) + err = grub_multiboot_load (file); + if (err) goto fail; - if (header->flags & MULTIBOOT_VIDEO_MODE) - { - switch (header->mode_type) - { - case 1: - grub_env_set ("gfxpayload", "text"); - break; - - case 0: - { - char *buf; - if (header->depth && header->width && header->height) - buf = grub_xasprintf ("%dx%dx%d,%dx%d,auto", header->width, - header->height, header->depth, header->width, - header->height); - else if (header->width && header->height) - buf = grub_xasprintf ("%dx%d,auto", header->width, header->height); - else - buf = grub_strdup ("auto"); - - if (!buf) - goto fail; - grub_env_set ("gfxpayload", buf); - grub_free (buf); - break; - } - } - } - - accepts_video = !!(header->flags & MULTIBOOT_VIDEO_MODE); - grub_multiboot_set_bootdev (); grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); @@ -385,12 +309,16 @@ grub_multiboot (int argc, char *argv[]) if (grub_errno != GRUB_ERR_NONE) { grub_relocator32_free (grub_multiboot_payload_orig); + grub_multiboot_free_mbi (); grub_dl_unref (my_mod); } + + return grub_errno; } -void -grub_module (int argc, char *argv[]) +static grub_err_t +grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) { grub_file_t file = 0; grub_ssize_t size; @@ -398,40 +326,64 @@ grub_module (int argc, char *argv[]) grub_err_t err; if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); if (!grub_multiboot_payload_orig) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, - "you need to load the multiboot kernel first"); - goto fail; - } + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "you need to load the multiboot kernel first"); file = grub_gzfile_open (argv[0], 1); if (! file) - goto fail; + return grub_errno; size = grub_file_size (file); module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); if (! module) - goto fail; + { + grub_file_close (file); + return grub_errno; + } err = grub_multiboot_add_module ((grub_addr_t) module, size, argc - 1, argv + 1); if (err) - goto fail; + { + grub_file_close (file); + return err; + } if (grub_file_read (file, module, size) != size) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; + grub_file_close (file); + return grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); } - fail: - if (file) - grub_file_close (file); + grub_file_close (file); + return GRUB_ERR_NONE;; } +static grub_command_t cmd_multiboot, cmd_module; + +GRUB_MOD_INIT(multiboot) +{ + cmd_multiboot = +#ifdef GRUB_USE_MULTIBOOT2 + grub_register_command ("multiboot2", grub_cmd_multiboot, + 0, N_("Load a multiboot 2 kernel.")); +#else + grub_register_command ("multiboot", grub_cmd_multiboot, + 0, N_("Load a multiboot kernel.")); +#endif + + cmd_module = + grub_register_command ("module", grub_cmd_module, + 0, N_("Load a multiboot module.")); + + my_mod = mod; +} + +GRUB_MOD_FINI(multiboot) +{ + grub_unregister_command (cmd_multiboot); + grub_unregister_command (cmd_module); +} diff --git a/loader/i386/multiboot_elfxx.c b/loader/i386/multiboot_elfxx.c index 2e35183a4..05fb2c1c1 100644 --- a/loader/i386/multiboot_elfxx.c +++ b/loader/i386/multiboot_elfxx.c @@ -53,6 +53,7 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) char *phdr_base; int lowest_segment = -1, highest_segment = -1; int i; + grub_size_t code_size; if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX) return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); @@ -102,9 +103,9 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) grub_multiboot_pure_size += code_size; - alloc_mbi = grub_multiboot_get_mbi_size (); + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + alloc_mbi + 65536); + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); if (!grub_multiboot_payload_orig) return grub_errno; diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index 0d5db3c13..e273e29ca 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -23,6 +23,7 @@ #endif #include #include +#include #include #include #include @@ -30,6 +31,10 @@ #include #include #include +#include + +/* The bits in the required part of flags field we don't support. */ +#define UNSUPPORTED_FLAGS 0x0000fff8 struct module { @@ -48,6 +53,132 @@ static char *cmdline = NULL; static grub_uint32_t bootdev; static int bootdev_set; +grub_err_t +grub_multiboot_load (grub_file_t file) +{ + char *buffer; + grub_ssize_t len; + struct multiboot_header *header; + grub_err_t err; + + buffer = grub_malloc (MULTIBOOT_SEARCH); + if (!buffer) + return grub_errno; + + len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); + if (len < 32) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_OS, "file too small"); + } + + /* Look for the multiboot header in the buffer. The header should + be at least 12 bytes and aligned on a 4-byte boundary. */ + for (header = (struct multiboot_header *) buffer; + ((char *) header <= buffer + len - 12) || (header = 0); + header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) + { + if (header->magic == MULTIBOOT_HEADER_MAGIC + && !(header->magic + header->flags + header->checksum)) + break; + } + + if (header == 0) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); + } + + if (header->flags & UNSUPPORTED_FLAGS) + { + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "unsupported flag: 0x%x", header->flags); + } + + if (header->flags & MULTIBOOT_AOUT_KLUDGE) + { + int offset = ((char *) header - buffer - + (header->header_addr - header->load_addr)); + int load_size = ((header->load_end_addr == 0) ? file->size - offset : + header->load_end_addr - header->load_addr); + grub_size_t code_size; + + if (header->bss_end_addr) + code_size = (header->bss_end_addr - header->load_addr); + else + code_size = load_size; + grub_multiboot_payload_dest = header->load_addr; + + grub_multiboot_pure_size += code_size; + + /* Allocate a bit more to avoid relocations in most cases. */ + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; + grub_multiboot_payload_orig + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); + + if (! grub_multiboot_payload_orig) + { + grub_free (buffer); + return grub_errno; + } + + if ((grub_file_seek (file, offset)) == (grub_off_t) -1) + { + grub_free (buffer); + return grub_errno; + } + + grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + if (grub_errno) + { + grub_free (buffer); + return grub_errno; + } + + if (header->bss_end_addr) + grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + header->bss_end_addr - header->load_addr - load_size); + + grub_multiboot_payload_eip = header->entry_addr; + + } + else + { + err = grub_multiboot_load_elf (file, buffer); + if (err) + { + grub_free (buffer); + return err; + } + } + + if (header->flags & MULTIBOOT_VIDEO_MODE) + { + switch (header->mode_type) + { + case 1: + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + GRUB_MULTIBOOT_CONSOLE_EGA_TEXT + | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + 0, 0, 0); + break; + case 0: + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + GRUB_MULTIBOOT_CONSOLE_EGA_TEXT + | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + header->width, header->height, + header->depth); + break; + } + } + else + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + 0, 0, 0); + return err; +} + grub_size_t grub_multiboot_get_mbi_size (void) { diff --git a/loader/multiboot_loader.c b/loader/multiboot_loader.c deleted file mode 100644 index 6d042fa81..000000000 --- a/loader/multiboot_loader.c +++ /dev/null @@ -1,150 +0,0 @@ -/* multiboot_loader.c - boot multiboot kernel image */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008,2009,2010 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -grub_dl_t my_mod; - -static int -find_multi_boot1_header (grub_file_t file) -{ - struct multiboot_header *header; - char buffer[MULTIBOOT_SEARCH]; - int found_status = 0; - grub_ssize_t len; - - len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); - if (len < 32) - return found_status; - - /* Look for the multiboot header in the buffer. The header should - be at least 12 bytes and aligned on a 4-byte boundary. */ - for (header = (struct multiboot_header *) buffer; - ((char *) header <= buffer + len - 12) || (header = 0); - header = (struct multiboot_header *) ((char *) header + 4)) - { - if (header->magic == MULTIBOOT_HEADER_MAGIC - && !(header->magic + header->flags + header->checksum)) - { - found_status = 1; - break; - } - } - - return found_status; -} - -static grub_err_t -grub_cmd_multiboot_loader (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - int header_multi_ver_found = 0; - - grub_dl_ref (my_mod); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - goto fail; - } - - file = grub_gzfile_open (argv[0], 1); - if (! file) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); - goto fail; - } - - /* find which header is in the file */ - if (find_multi_boot1_header (file)) - header_multi_ver_found = 1; - else - { - grub_error (GRUB_ERR_BAD_OS, "multiboot header not found"); - goto fail; - } - - /* close file before calling functions */ - if (file) - grub_file_close (file); - - /* Launch multi boot with header */ - - grub_dprintf ("multiboot_loader", - "Launching multiboot 1 grub_multiboot() function\n"); - grub_multiboot (argc, argv); - - return grub_errno; - -fail: - if (file) - grub_file_close (file); - - grub_dl_unref (my_mod); - - return grub_errno; -} - -static grub_err_t -grub_cmd_module_loader (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - - grub_dprintf("multiboot_loader", - "Launching multiboot 1 grub_module() function\n"); - grub_module (argc, argv); - - return grub_errno; -} - -static grub_command_t cmd_multiboot, cmd_module; - -GRUB_MOD_INIT(multiboot) -{ - cmd_multiboot = -#ifdef GRUB_USE_MULTIBOOT2 - grub_register_command ("multiboot2", grub_cmd_multiboot_loader, - 0, N_("Load a multiboot 2 kernel.")); -#else - grub_register_command ("multiboot", grub_cmd_multiboot_loader, - 0, N_("Load a multiboot kernel.")); -#endif - - cmd_module = - grub_register_command ("module", grub_cmd_module_loader, - 0, N_("Load a multiboot module.")); - - my_mod = mod; -} - -GRUB_MOD_FINI(multiboot) -{ - grub_unregister_command (cmd_multiboot); - grub_unregister_command (cmd_module); -} From c3a8dfc8b750e3bebd731aefdcf9788fe2a22f77 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 10 Mar 2010 11:40:20 +0100 Subject: [PATCH 08/12] Tagged header support --- include/grub/multiboot.h | 3 +- include/multiboot2.h | 5 + loader/i386/multiboot.c | 20 +++- loader/i386/multiboot_mbi.c | 6 +- loader/i386/multiboot_mbi2.c | 196 +++++++++++++++++++++++++++++++++++ 5 files changed, 225 insertions(+), 5 deletions(-) diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 89efbc6dd..70241ec3c 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -70,7 +70,8 @@ grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info, grub_err_t grub_multiboot_set_console (int console_type, int accepted_consoles, - int width, int height, int depth); + int width, int height, int depth, + int console_required); grub_err_t grub_multiboot_load (grub_file_t file); /* Load ELF32 or ELF64. */ diff --git a/include/multiboot2.h b/include/multiboot2.h index dae05a7a3..820479425 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -62,6 +62,8 @@ #define MULTIBOOT_TAG_TYPE_MMAP 6 #define MULTIBOOT_TAG_TYPE_VBE 7 #define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 #define MULTIBOOT_HEADER_TAG_END 0 #define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 @@ -74,6 +76,9 @@ #define GRUB_MULTIBOOT_ARCHITECTURE_I386 0 #define MULTIBOOT_HEADER_TAG_OPTIONAL 1 +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 + #ifndef ASM_FILE typedef unsigned char multiboot_uint8_t; diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index 17fefc85a..a89233431 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -62,6 +62,8 @@ grub_addr_t grub_multiboot_payload_dest; grub_size_t grub_multiboot_pure_size; grub_uint32_t grub_multiboot_payload_eip; static int accepts_video; +static int accepts_ega_text; +static int console_required; static grub_dl_t my_mod; @@ -245,8 +247,23 @@ grub_multiboot_load_elf (grub_file_t file, void *buffer) grub_err_t grub_multiboot_set_console (int console_type, int accepted_consoles, - int width, int height, int depth) + int width, int height, int depth, + int console_req) { + console_required = console_req; + if (!(accepted_consoles + & (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER + | (GRUB_MACHINE_HAS_VGA_TEXT ? GRUB_MULTIBOOT_CONSOLE_EGA_TEXT : 0)))) + { + if (console_required) + return grub_error (GRUB_ERR_BAD_OS, + "OS requires a console but none is available"); + grub_printf ("WARNING: no console will be available to OS"); + accepts_video = 0; + accepts_ega_text = 0; + return GRUB_ERR_NONE; + } + if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER) { char *buf; @@ -267,6 +284,7 @@ grub_multiboot_set_console (int console_type, int accepted_consoles, grub_env_set ("gfxpayload", "text"); accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER); + accepts_ega_text = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_EGA_TEXT); return GRUB_ERR_NONE; } diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index e273e29ca..6d104ed1c 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -161,21 +161,21 @@ grub_multiboot_load (grub_file_t file) err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, - 0, 0, 0); + 0, 0, 0, 0); break; case 0: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, header->width, header->height, - header->depth); + header->depth, 0); break; } } else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, - 0, 0, 0); + 0, 0, 0, 0); return err; } diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c index ab803734f..d07ce92f3 100644 --- a/loader/i386/multiboot_mbi2.c +++ b/loader/i386/multiboot_mbi2.c @@ -23,6 +23,7 @@ #endif #include #include +#include #include #include #include @@ -59,6 +60,201 @@ static char *cmdline = NULL; static int bootdev_set; static grub_uint32_t biosdev, slice, part; +grub_err_t +grub_multiboot_load (grub_file_t file) +{ + char *buffer; + grub_ssize_t len; + struct multiboot_header *header; + grub_err_t err; + struct multiboot_header_tag *tag; + struct multiboot_header_tag_address *addr_tag = NULL; + int entry_specified = 0; + grub_addr_t entry = 0; + grub_uint32_t console_required = 0; + struct multiboot_header_tag_framebuffer *fbtag = NULL; + int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; + + buffer = grub_malloc (MULTIBOOT_SEARCH); + if (!buffer) + return grub_errno; + + len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); + if (len < 32) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_OS, "file too small"); + } + + /* Look for the multiboot header in the buffer. The header should + be at least 12 bytes and aligned on a 4-byte boundary. */ + for (header = (struct multiboot_header *) buffer; + ((char *) header <= buffer + len - 12) || (header = 0); + header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) + { + if (header->magic == MULTIBOOT_HEADER_MAGIC + && !(header->magic + header->architecture + + header->header_length + header->checksum)) + break; + } + + if (header == 0) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); + } + + for (tag = (struct multiboot_header_tag *) (header + 1); + tag->type != MULTIBOOT_TAG_TYPE_END; + tag = (struct multiboot_header_tag *) ((char *) tag + tag->size)) + switch (tag->type) + { + case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: + { + unsigned i; + struct multiboot_header_tag_information_request *request_tag + = (struct multiboot_header_tag_information_request *) tag; + if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL) + break; + for (i = 0; i < (request_tag->size - sizeof (request_tag)) + / sizeof (request_tag->requests[0]); i++) + switch (request_tag->requests[i]) + { + case MULTIBOOT_TAG_TYPE_END: + case MULTIBOOT_TAG_TYPE_CMDLINE: + case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: + case MULTIBOOT_TAG_TYPE_MODULE: + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + case MULTIBOOT_TAG_TYPE_BOOTDEV: + case MULTIBOOT_TAG_TYPE_MMAP: + case MULTIBOOT_TAG_TYPE_VBE: + case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: + break; + + case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: + case MULTIBOOT_TAG_TYPE_APM: + default: + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "unsupported information tag: 0x%x", + request_tag->requests[i]); + } + break; + } + + case MULTIBOOT_HEADER_TAG_ADDRESS: + addr_tag = (struct multiboot_header_tag_address *) tag; + break; + + case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: + entry_specified = 1; + entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr; + break; + + case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: + if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags + & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED)) + accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; + if (((struct multiboot_header_tag_console_flags *) tag)->console_flags + & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED) + console_required = 1; + break; + + case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: + fbtag = (struct multiboot_header_tag_framebuffer *) tag; + accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER; + break; + + /* GRUB always page-aligns modules. */ + case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: + break; + + default: + if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) + { + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "unsupported tag: 0x%x", tag->type); + } + break; + } + + if (addr_tag && !entry_specified) + { + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "load address tag without entry address tag"); + } + + if (addr_tag) + { + int offset = ((char *) header - buffer - + (addr_tag->header_addr - addr_tag->load_addr)); + int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : + addr_tag->load_end_addr - addr_tag->load_addr); + grub_size_t code_size; + + if (addr_tag->bss_end_addr) + code_size = (addr_tag->bss_end_addr - addr_tag->load_addr); + else + code_size = load_size; + grub_multiboot_payload_dest = addr_tag->load_addr; + + grub_multiboot_pure_size += code_size; + + /* Allocate a bit more to avoid relocations in most cases. */ + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; + grub_multiboot_payload_orig + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); + + if (! grub_multiboot_payload_orig) + { + grub_free (buffer); + return grub_errno; + } + + if ((grub_file_seek (file, offset)) == (grub_off_t) -1) + { + grub_free (buffer); + return grub_errno; + } + + grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + if (grub_errno) + { + grub_free (buffer); + return grub_errno; + } + + if (addr_tag->bss_end_addr) + grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + addr_tag->bss_end_addr - addr_tag->load_addr - load_size); + } + else + { + err = grub_multiboot_load_elf (file, buffer); + if (err) + { + grub_free (buffer); + return err; + } + } + + if (entry_specified) + grub_multiboot_payload_eip = entry; + + if (fbtag) + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + accepted_consoles, + fbtag->width, fbtag->height, + fbtag->depth, console_required); + else + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + accepted_consoles, + 0, 0, 0, console_required); + return err; +} + grub_size_t grub_multiboot_get_mbi_size (void) { From 46960ff9ec75f23666c47b745b041c221655acb5 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 27 Mar 2010 21:50:57 +0100 Subject: [PATCH 09/12] Resynced with multiboot2 spec --- include/multiboot2.h | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/include/multiboot2.h b/include/multiboot2.h index 820479425..59d7c951f 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -103,24 +103,24 @@ struct multiboot_header struct multiboot_header_tag { - multiboot_uint32_t type; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t flags; }; struct multiboot_header_tag_information_request { - multiboot_uint32_t type; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t flags; multiboot_uint32_t requests[0]; }; struct multiboot_header_tag_address { - multiboot_uint32_t type; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t flags; multiboot_uint32_t header_addr; multiboot_uint32_t load_addr; multiboot_uint32_t load_end_addr; @@ -129,25 +129,25 @@ struct multiboot_header_tag_address struct multiboot_header_tag_entry_address { - multiboot_uint32_t type; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t flags; multiboot_uint32_t entry_addr; }; struct multiboot_header_tag_console_flags { - multiboot_uint32_t type; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t flags; multiboot_uint32_t console_flags; }; struct multiboot_header_tag_framebuffer { - multiboot_uint32_t type; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t flags; multiboot_uint32_t width; multiboot_uint32_t height; multiboot_uint32_t depth; @@ -155,9 +155,9 @@ struct multiboot_header_tag_framebuffer struct multiboot_header_tag_module_align { - multiboot_uint32_t type; + multiboot_uint16_t type; + multiboot_uint16_t flags; multiboot_uint32_t size; - multiboot_uint32_t flags; multiboot_uint32_t width; multiboot_uint32_t height; multiboot_uint32_t depth; @@ -193,8 +193,6 @@ struct multiboot_tag_string { multiboot_uint32_t type; multiboot_uint32_t size; - multiboot_uint32_t entry_size; - multiboot_uint32_t entry_version; char string[0]; }; From 3a7c36977a37c21d07484ecde445a8cce801a68f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 27 Mar 2010 22:40:49 +0100 Subject: [PATCH 10/12] Fix compilation problem --- loader/i386/multiboot_mbi2.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c index d07ce92f3..09d09d5a9 100644 --- a/loader/i386/multiboot_mbi2.c +++ b/loader/i386/multiboot_mbi2.c @@ -678,7 +678,6 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size, void grub_multiboot_set_bootdev (void) { - char *p; grub_device_t dev; slice = ~0; @@ -696,22 +695,13 @@ grub_multiboot_set_bootdev (void) dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { - char *p0; - p = p0 = 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->disk->partition->parent) + { + part = dev->disk->partition->number; + slice = dev->disk->partition->parent->number; } - grub_free (p0); + else + slice = dev->disk->partition->number; } if (dev) grub_device_close (dev); From fe9381dd00d957b49e6c92fbb17b6ad4e18f1a21 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 27 Mar 2010 22:42:02 +0100 Subject: [PATCH 11/12] Resync changelog --- ChangeLog.tag | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog.tag b/ChangeLog.tag index dbeea1017..73983b463 100644 --- a/ChangeLog.tag +++ b/ChangeLog.tag @@ -4,13 +4,20 @@ * conf/i386.rmk (multiboot2_mod_SOURCES): Replace loader/i386/multiboot_mbi.c with loader/i386/multiboot_mbi2.c. + Remove loader/multiboot_loader.c. * include/grub/i386/multiboot.h (grub_multiboot_real_boot): Removed. (grub_multiboot2_real_boot): Likewise. * include/grub/multiboot.h (grub_multiboot_set_accepts_video): Removed. - (grub_get_multiboot_mmap_len): New proto. + (grub_get_multiboot_mmap_count): New proto. (grub_fill_multiboot_mmap): Likewise. (grub_multiboot_set_video_mode): Likewise. (grub_multiboot_fill_vbe_info_real): Likewise. + (grub_multiboot_set_console): Likewise. + (grub_multiboot_load): Likewise. + (grub_multiboot_load_elf): Likewise. + (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT): New definition. + (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER): Likewise. + * include/multiboot.h: Resynced with specification. * include/multiboot2.h: Resynced with specification. * loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): Moved from here... * loader/i386/multiboot.c (DEFAULT_VIDEO_MODE): ... here. From f5d5c327e3884dd99171fc7b5c17669f356f9b28 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 28 Mar 2010 13:46:42 +0200 Subject: [PATCH 12/12] Remove VBE multiboot support --- ChangeLog.mbivid | 9 ---- ChangeLog.tag | 8 ---- include/grub/multiboot.h | 9 ---- loader/i386/multiboot.c | 49 +-------------------- loader/i386/multiboot_mbi.c | 10 ----- loader/i386/multiboot_mbi2.c | 82 +++++++++++++++--------------------- 6 files changed, 34 insertions(+), 133 deletions(-) delete mode 100644 ChangeLog.mbivid diff --git a/ChangeLog.mbivid b/ChangeLog.mbivid deleted file mode 100644 index 25db22c19..000000000 --- a/ChangeLog.mbivid +++ /dev/null @@ -1,9 +0,0 @@ -2010-01-14 Vladimir Serbinenko - - VBE multiboot support. - - * loader/i386/multiboot_mbi.c (HAS_VBE): New constant. - (grub_multiboot_get_mbi_size) [HAS_VBE]: Account for VBE structures. - (grub_multiboot_make_mbi) [HAS_VBE]: Likewise. - (fill_vbe_info) [HAS_VBE]: New function. - (retrieve_video_parameters) [HAS_VBE]: Call fill_vbe_info. diff --git a/ChangeLog.tag b/ChangeLog.tag index 73983b463..90faf3dd6 100644 --- a/ChangeLog.tag +++ b/ChangeLog.tag @@ -11,7 +11,6 @@ (grub_get_multiboot_mmap_count): New proto. (grub_fill_multiboot_mmap): Likewise. (grub_multiboot_set_video_mode): Likewise. - (grub_multiboot_fill_vbe_info_real): Likewise. (grub_multiboot_set_console): Likewise. (grub_multiboot_load): Likewise. (grub_multiboot_load_elf): Likewise. @@ -24,9 +23,6 @@ * loader/i386/multiboot_mbi.c (HAS_VGA_TEXT): Moved from here .. * include/grub/multiboot.h (GRUB_MACHINE_HAS_VGA_TEXT): ... here. All users updated. - * loader/i386/multiboot_mbi.c (HAS_VBE): Moved from here .. - * include/grub/multiboot.h (GRUB_MACHINE_HAS_VBE): ... here. All - users updated. * loader/i386/multiboot_mbi.c (accepts_video): Moved from here... * loader/i386/multiboot.c (accepts_video): ... here. All users updated. * loader/i386/multiboot_mbi.c (grub_multiboot_set_accepts_video): @@ -40,8 +36,4 @@ * loader/i386/multiboot_mbi.c (set_video_mode): Moved from here... * loader/i386/multiboot.c (grub_multiboot_set_video_mode): ... here. All users updated. - * loader/i386/multiboot_mbi.c (fill_vbe_info): Moved generic parts - from here... - * loader/i386/multiboot.c (grub_multiboot_fill_vbe_info_real): ... here. - All users updated. * loader/i386/multiboot_mbi2.c: New file. diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 70241ec3c..49d71fa09 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -51,17 +51,8 @@ grub_err_t grub_multiboot_set_video_mode (void); #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) #include -grub_err_t -grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info, - struct grub_vbe_mode_info_block *vbe_mode_info, - multiboot_uint16_t *vbe_mode, - multiboot_uint16_t *vbe_interface_seg, - multiboot_uint16_t *vbe_interface_off, - multiboot_uint16_t *vbe_interface_len); -#define GRUB_MACHINE_HAS_VBE 1 #define GRUB_MACHINE_HAS_VGA_TEXT 1 #else -#define GRUB_MACHINE_HAS_VBE 0 #define GRUB_MACHINE_HAS_VGA_TEXT 0 #endif diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index a89233431..99d1cf906 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -20,6 +20,7 @@ /* * FIXME: The following features from the Multiboot specification still * need to be implemented: + * - VBE support * - symbol table * - drives table * - ROM configuration table @@ -115,54 +116,6 @@ grub_multiboot_set_video_mode (void) return err; } -#if GRUB_MACHINE_HAS_VBE -grub_err_t -grub_multiboot_fill_vbe_info_real (struct grub_vbe_info_block *vbe_control_info, - struct grub_vbe_mode_info_block *vbe_mode_info, - multiboot_uint16_t *vbe_mode, - multiboot_uint16_t *vbe_interface_seg, - multiboot_uint16_t *vbe_interface_off, - multiboot_uint16_t *vbe_interface_len) -{ - grub_vbe_status_t status; - 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."); - grub_memcpy (vbe_control_info, scratch, 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"); - - /* get_mode_info isn't available for mode 3. */ - if (*vbe_mode == 3) - { - grub_memset (vbe_mode_info, 0, sizeof (struct grub_vbe_mode_info_block)); - vbe_mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT; - vbe_mode_info->x_resolution = 80; - vbe_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 (vbe_mode_info, scratch, - sizeof (struct grub_vbe_mode_info_block)); - } - - /* FIXME: retrieve those. */ - *vbe_interface_seg = 0; - *vbe_interface_off = 0; - *vbe_interface_len = 0; - - return GRUB_ERR_NONE; -} -#endif - static grub_err_t grub_multiboot_boot (void) { diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c index 0deca8930..2a7c70f96 100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@ -186,10 +186,6 @@ grub_multiboot_get_mbi_size (void) + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) -#if GRUB_MACHINE_HAS_VBE - + sizeof (struct grub_vbe_info_block) - + sizeof (struct grub_vbe_mode_info_block) -#endif + 256 * sizeof (struct multiboot_color); } @@ -391,12 +387,6 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, grub_print_error (); grub_errno = GRUB_ERR_NONE; } -#if GRUB_MACHINE_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; } diff --git a/loader/i386/multiboot_mbi2.c b/loader/i386/multiboot_mbi2.c index 09d09d5a9..436cd0901 100644 --- a/loader/i386/multiboot_mbi2.c +++ b/loader/i386/multiboot_mbi2.c @@ -127,10 +127,10 @@ grub_multiboot_load (grub_file_t file) case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: case MULTIBOOT_TAG_TYPE_BOOTDEV: case MULTIBOOT_TAG_TYPE_MMAP: - case MULTIBOOT_TAG_TYPE_VBE: case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: break; + case MULTIBOOT_TAG_TYPE_VBE: case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: case MULTIBOOT_TAG_TYPE_APM: default: @@ -271,37 +271,6 @@ grub_multiboot_get_mbi_size (void) + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1; } -#ifdef GRUB_MACHINE_HAS_VBE - -static grub_err_t -fill_vbe_info (struct grub_vbe_mode_info_block **vbe_mode_info_out, - grub_uint8_t **ptrorig) -{ - struct multiboot_tag_vbe *tag = (struct multiboot_tag_vbe *) *ptrorig; - grub_err_t err; - - tag->type = MULTIBOOT_TAG_TYPE_VBE; - tag->size = 0; - err = grub_multiboot_fill_vbe_info_real ((struct grub_vbe_info_block *) - &(tag->vbe_control_info), - (struct grub_vbe_mode_info_block *) - &(tag->vbe_mode_info), - &(tag->vbe_mode), - &(tag->vbe_interface_seg), - &(tag->vbe_interface_off), - &(tag->vbe_interface_len)); - if (err) - return err; - if (vbe_mode_info_out) - *vbe_mode_info_out = (struct grub_vbe_mode_info_block *) - &(tag->vbe_mode_info); - tag->size = sizeof (struct multiboot_tag_vbe); - *ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); - return GRUB_ERR_NONE; -} - -#endif - /* Fill previously allocated Multiboot mmap. */ static void grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag) @@ -373,11 +342,35 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) #if HAS_VGA_TEXT if (driv_id == GRUB_VIDEO_DRIVER_NONE) { - struct grub_vbe_mode_info_block *vbe_mode_info; - err = fill_vbe_info (&vbe_mode_info, ptrorig); - if (err) - return err; - if (vbe_mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) + struct grub_vbe_mode_info_block vbe_mode_info; + grub_vbe_status_t status; + grub_uint32_t vbe_mode; + void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + status = grub_vbe_bios_get_mode (scratch); + vbe_mode = *(grub_uint32_t *) scratch; + if (status != GRUB_VBE_STATUS_OK) + return GRUB_ERR_NONE; + + /* get_mode_info isn't available for mode 3. */ + if (vbe_mode == 3) + { + grub_memset (&vbe_mode_info, 0, + sizeof (struct grub_vbe_mode_info_block)); + vbe_mode_info.memory_model = GRUB_VBE_MEMORY_MODEL_TEXT; + vbe_mode_info.x_resolution = 80; + vbe_mode_info.y_resolution = 25; + } + else + { + status = grub_vbe_bios_get_mode_info (vbe_mode, scratch); + if (status != GRUB_VBE_STATUS_OK) + return GRUB_ERR_NONE; + grub_memcpy (&vbe_mode_info, scratch, + sizeof (struct grub_vbe_mode_info_block)); + } + + if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) { tag = (struct multiboot_tag_framebuffer *) *ptrorig; tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; @@ -385,9 +378,9 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) tag->common.framebuffer_addr = 0xb8000; - tag->common.framebuffer_pitch = 2 * vbe_mode_info->x_resolution; - tag->common.framebuffer_width = vbe_mode_info->x_resolution; - tag->common.framebuffer_height = vbe_mode_info->y_resolution; + tag->common.framebuffer_pitch = 2 * vbe_mode_info.x_resolution; + tag->common.framebuffer_width = vbe_mode_info.x_resolution; + tag->common.framebuffer_height = vbe_mode_info.y_resolution; tag->common.framebuffer_bpp = 16; @@ -453,15 +446,6 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) } *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); -#if HAS_VBE - if (driv_id == GRUB_VIDEO_DRIVER_VBE) - { - err = fill_vbe_info (NULL, ptrorig); - if (err) - return err; - } -#endif - return GRUB_ERR_NONE; }