=== modified file 'include/grub/i386/multiboot.h' --- include/grub/i386/multiboot.h 2009-12-17 23:59:02 +0000 +++ include/grub/i386/multiboot.h 2010-01-02 02:04:52 +0000 @@ -39,4 +39,7 @@ void grub_multiboot_set_bootdev (void); void grub_multiboot_set_accepts_video (int val); +void grub_multiboot_set_tagged (int val); +int grub_multiboot_get_tagged (void); + #endif /* ! GRUB_MULTIBOOT_CPU_HEADER */ === modified file 'include/multiboot.h' --- include/multiboot.h 2010-01-02 17:50:06 +0000 +++ include/multiboot.h 2010-01-02 21:06:42 +0000 @@ -31,8 +31,11 @@ /* This should be in %eax. */ #define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC_TAGGED 0x3BADB002 + /* The bits in the required part of flags field we don't support. */ -#define MULTIBOOT_UNSUPPORTED 0x0000fff8 +#define MULTIBOOT_UNSUPPORTED 0x0000fff0 /* Alignment of multiboot modules. */ #define MULTIBOOT_MOD_ALIGN 0x00001000 @@ -51,6 +54,9 @@ /* Must pass video information to OS. */ #define MULTIBOOT_VIDEO_MODE 0x00000004 +/* Must pass tagged mbi to OS. */ +#define MULTIBOOT_TAGGED_MBI 0x00000008 + /* This flag indicates the use of the address fields in the header. */ #define MULTIBOOT_AOUT_KLUDGE 0x00010000 @@ -254,6 +260,114 @@ }; typedef struct multiboot_mod_list multiboot_module_t; +struct multiboot_tag +{ + 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; + 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]; +}; + +#include + +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 grub_vbe_info_block vbe_control_info; + struct grub_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; + 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; + }; + }; +}; + +#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 + #endif /* ! ASM_FILE */ #endif /* ! MULTIBOOT_HEADER */ === modified file 'loader/i386/multiboot.c' --- loader/i386/multiboot.c 2010-01-02 17:50:06 +0000 +++ loader/i386/multiboot.c 2010-01-02 21:57:30 +0000 @@ -62,7 +62,6 @@ grub_err_t err; struct grub_relocator32_state state = { - .eax = MULTIBOOT_BOOTLOADER_MAGIC, .ecx = 0, .edx = 0, .eip = grub_multiboot_payload_eip, @@ -71,6 +70,11 @@ .esp = 0x7ff00 }; + if (grub_multiboot_get_tagged ()) + state.eax = MULTIBOOT_BOOTLOADER_MAGIC_TAGGED; + else + state.eax = MULTIBOOT_BOOTLOADER_MAGIC; + mbi_size = grub_multiboot_get_mbi_size (); if (alloc_mbi < mbi_size) { @@ -197,6 +201,9 @@ /* Skip filename. */ grub_multiboot_init_mbi (argc - 1, argv + 1); + if (header->flags & MULTIBOOT_TAGGED_MBI) + grub_multiboot_set_tagged (1); + if (header->flags & MULTIBOOT_AOUT_KLUDGE) { int offset = ((char *) header - buffer - === modified file 'loader/i386/multiboot_mbi.c' --- loader/i386/multiboot_mbi.c 2010-01-02 20:54:52 +0000 +++ loader/i386/multiboot_mbi.c 2010-01-02 21:01:58 +0000 @@ -55,9 +55,10 @@ static grub_size_t total_modcmd; static unsigned modcnt; static char *cmdline = NULL; -static grub_uint32_t bootdev; static int bootdev_set; static int accepts_video; +static int tagged; +static grub_uint32_t biosdev, slice, part; void grub_multiboot_set_accepts_video (int val) @@ -65,6 +66,18 @@ accepts_video = val; } +void +grub_multiboot_set_tagged (int val) +{ + tagged = val; +} + +int +grub_multiboot_get_tagged (void) +{ + return tagged; +} + /* Return the length of the Multiboot mmap that will be needed to allocate our platform's map. */ static grub_uint32_t @@ -89,12 +102,23 @@ grub_size_t 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 () - + sizeof (struct grub_vbe_info_block) - + sizeof (struct grub_vbe_mode_info_block) - + 256 * sizeof (struct multiboot_color); + if (tagged) + 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); + else + 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 () + + sizeof (struct grub_vbe_info_block) + + sizeof (struct grub_vbe_mode_info_block) + + 256 * sizeof (struct multiboot_color); } /* Fill previously allocated Multiboot mmap. */ @@ -158,40 +182,67 @@ #if HAS_VBE static grub_err_t -fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, - grub_uint32_t ptrdest) +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; - 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); - + + 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; + *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); + 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; +} + +static grub_err_t +fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, + grub_uint32_t ptrdest) +{ + struct grub_vbe_info_block *vbe_control_info; + struct grub_vbe_mode_info_block *vbe_mode_info; + grub_err_t err; + + vbe_control_info = (struct grub_vbe_info_block *) ptrorig; + mbi->vbe_control_info = ptrdest; + ptrorig += sizeof (struct grub_vbe_info_block); + ptrdest += sizeof (struct grub_vbe_info_block); + + vbe_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)); 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 = 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; @@ -276,16 +327,221 @@ mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; #if HAS_VBE + fill_vbe_info (mbi, ptrorig, ptrdest); +#endif + + return GRUB_ERR_NONE; +} + +static grub_err_t +set_video_info_tagged (struct multiboot_tag_framebuffer *tag, +#if HAS_VBE + int *vbe_active +#endif + ) +{ + struct grub_video_palette_data palette[256]; + grub_err_t err; + struct grub_video_mode_info mode_info; + void *framebuffer; + + tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->common.size = 0; + + err = set_video_mode (); + if (err) + return err; + + grub_video_get_palette (0, ARRAY_SIZE (palette), palette); + +#if HAS_VBE + { + const char *adapter_name; + adapter_name = grub_video_get_active_adapter_name (); + + *vbe_active = ((adapter_name + && grub_strcmp (adapter_name, + "VESA BIOS Extension Video Driver") == 0) + || (HAS_VGA_TEXT && !adapter_name)); + } +#endif + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + if (err) + return err; + + 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; + } + } + else + { + 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; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +make_mbi_tagged (void *orig, grub_uint32_t dest, grub_off_t buf_off) +{ + grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off; +#if HAS_VBE + int vbe_active = 0; +#endif + grub_err_t err; + + { + 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; + } + + { + struct multiboot_tag_framebuffer *tag + = (struct multiboot_tag_framebuffer *) ptrorig; + err = set_video_info_tagged (tag, +#if HAS_VBE + &vbe_active +#endif + ); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + else + ptrorig += tag->common.size; + } + +#if HAS_VBE if (vbe_active) - fill_vbe_info (mbi, ptrorig, ptrdest); + { + struct multiboot_tag_vbe *tag = (struct multiboot_tag_vbe *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_VBE; + tag->size = sizeof (struct multiboot_tag_vbe); + err = fill_vbe_info_real (&(tag->vbe_control_info), + &(tag->vbe_mode_info), + &(tag->vbe_mode), + &(tag->vbe_interface_seg), + &(tag->vbe_interface_off), + &(tag->vbe_interface_len)); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + else + ptrorig += tag->size; + } #endif + + { + 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; } -grub_err_t -grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, - grub_size_t bufsize) +static grub_err_t +make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off) { grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off; grub_uint32_t ptrdest = dest + buf_off; @@ -296,9 +552,6 @@ 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"); - mbi = (struct multiboot_info *) ptrorig; ptrorig += sizeof (*mbi); ptrdest += sizeof (*mbi); @@ -356,7 +609,8 @@ if (bootdev_set) { - mbi->boot_device = bootdev; + mbi->boot_device = (((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) + | ((part & 0xff) << 8) | 0xff); mbi->flags |= MULTIBOOT_INFO_BOOTDEV; } @@ -374,6 +628,19 @@ 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) +{ + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + if (tagged) + return make_mbi_tagged (orig, dest, buf_off); + else + return make_mbi (orig, dest, buf_off); +} + void grub_multiboot_free_mbi (void) { @@ -403,6 +670,7 @@ char *p; int i; + tagged = 0; grub_multiboot_free_mbi (); for (i = 0; i < argc; i++) @@ -486,9 +754,11 @@ grub_multiboot_set_bootdev (void) { char *p; - grub_uint32_t biosdev, slice = ~0, part = ~0; grub_device_t dev; + slice = ~0; + part = ~0; + #ifdef GRUB_MACHINE_PCBIOS biosdev = grub_get_root_biosnumber (); #else @@ -517,7 +787,5 @@ if (dev) grub_device_close (dev); - bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) - | ((part & 0xff) << 8) | 0xff; bootdev_set = 1; }