diff --git a/ChangeLog b/ChangeLog index 301f32d48..6d503edf1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2010-09-20 Vladimir Serbinenko + + Support multiboot VBE info. + + * grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_get_mbi_size): + Take VBE info into account. + (fill_vbe_info) [GRUB_MACHINE_HAS_VBE]: New function. + (retrieve_video_parameters) [GRUB_MACHINE_HAS_VBE]: + Call fill_vbe_info when appropriate. + (grub_multiboot_make_mbi): Account for the size occupied by VBE info. + * grub-core/loader/multiboot_mbi2.c (grub_multiboot_load): Declare tags + as supported. + (grub_multiboot_get_mbi_size): Take new tags into account. + (fill_vbe_tag) [GRUB_MACHINE_HAS_VBE]: New function. + (retrieve_video_parameters) [GRUB_MACHINE_HAS_VBE]: + Call fill_vbe_tag when appropriate. + (grub_multiboot_make_mbi): Properly align tags. + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_pm_interface): New + function. + * include/grub/i386/pc/vbe.h (grub_vbe_bios_get_pm_interface): New + proto. + * include/grub/multiboot.h (GRUB_MACHINE_HAS_VBE): New definition. + 2010-09-20 Vladimir Serbinenko Suport manual terminal geometry specification. diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index 1c9a77b8b..eb86958cb 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -20,6 +20,7 @@ #ifdef GRUB_MACHINE_PCBIOS #include #include +#include #endif #include #include @@ -195,6 +196,10 @@ grub_multiboot_get_mbi_size (void) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) + elf_sec_entsize * elf_sec_num + 256 * sizeof (struct multiboot_color) +#if GRUB_MACHINE_HAS_VBE + + sizeof (struct grub_vbe_info_block) + + sizeof (struct grub_vbe_mode_info_block) +#endif + ALIGN_UP (sizeof (struct multiboot_apm_info), 4); } @@ -238,6 +243,77 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) grub_mmap_iterate (hook); } +#if GRUB_MACHINE_HAS_VBE +static grub_err_t +fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig, + grub_uint32_t ptrdest, int fill_generic) +{ + grub_vbe_status_t status; + grub_uint32_t vbe_mode; + void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + struct grub_vbe_mode_info_block *mode_info; + + status = grub_vbe_bios_get_controller_info (scratch); + if (status != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "Can't get controller info."); + + mbi->vbe_control_info = ptrdest; + grub_memcpy (ptrorig, scratch, sizeof (struct grub_vbe_info_block)); + ptrorig += sizeof (struct grub_vbe_info_block); + ptrdest += sizeof (struct grub_vbe_info_block); + + status = grub_vbe_bios_get_mode (scratch); + vbe_mode = *(grub_uint32_t *) scratch; + if (status != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "can't get VBE mode"); + mbi->vbe_mode = vbe_mode; + + mode_info = (struct grub_vbe_mode_info_block *) ptrorig; + mbi->vbe_mode_info = ptrdest; + /* get_mode_info isn't available for mode 3. */ + if (vbe_mode == 3) + { + grub_memset (mode_info, 0, sizeof (struct grub_vbe_mode_info_block)); + mode_info->memory_model = GRUB_VBE_MEMORY_MODEL_TEXT; + mode_info->x_resolution = 80; + mode_info->y_resolution = 25; + } + else + { + status = grub_vbe_bios_get_mode_info (vbe_mode, scratch); + if (status != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "can't get mode info"); + grub_memcpy (mode_info, scratch, + sizeof (struct grub_vbe_mode_info_block)); + } + ptrorig += sizeof (struct grub_vbe_mode_info_block); + ptrdest += sizeof (struct grub_vbe_mode_info_block); + + grub_vbe_bios_get_pm_interface (&mbi->vbe_interface_seg, + &mbi->vbe_interface_off, + &mbi->vbe_interface_len); + + mbi->flags |= MULTIBOOT_INFO_VBE_INFO; + + if (fill_generic && mode_info->memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) + { + mbi->framebuffer_addr = 0xb8000; + + mbi->framebuffer_pitch = 2 * mode_info->x_resolution; + mbi->framebuffer_width = mode_info->x_resolution; + mbi->framebuffer_height = mode_info->y_resolution; + + mbi->framebuffer_bpp = 16; + + mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; + + mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; + } + + return GRUB_ERR_NONE; +} +#endif + static grub_err_t retrieve_video_parameters (struct multiboot_info *mbi, grub_uint8_t *ptrorig, grub_uint32_t ptrdest) @@ -258,8 +334,13 @@ retrieve_video_parameters (struct multiboot_info *mbi, grub_video_get_palette (0, ARRAY_SIZE (palette), palette); driv_id = grub_video_get_driver_id (); +#if GRUB_MACHINE_HAS_VGA_TEXT + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return fill_vbe_info (mbi, ptrorig, ptrdest, 1); +#else if (driv_id == GRUB_VIDEO_DRIVER_NONE) return GRUB_ERR_NONE; +#endif err = grub_video_get_info_and_fini (&mode_info, &framebuffer); if (err) @@ -307,6 +388,11 @@ retrieve_video_parameters (struct multiboot_info *mbi, mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; +#if GRUB_MACHINE_HAS_VBE + if (driv_id == GRUB_VIDEO_DRIVER_VBE) + return fill_vbe_info (mbi, ptrorig, ptrdest, 0); +#endif + return GRUB_ERR_NONE; } @@ -440,6 +526,12 @@ grub_multiboot_make_mbi (grub_uint32_t *target) 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/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index c6182109b..9062ba01c 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -20,7 +20,6 @@ /* * FIXME: The following features from the Multiboot specification still * need to be implemented: - * - VBE support * - drives table * - ROM configuration table */ diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 08b882ed7..b4cd8ac0e 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -139,11 +139,11 @@ grub_multiboot_load (grub_file_t file) case MULTIBOOT_TAG_TYPE_BOOTDEV: case MULTIBOOT_TAG_TYPE_MMAP: case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: - break; - case MULTIBOOT_TAG_TYPE_VBE: case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: case MULTIBOOT_TAG_TYPE_APM: + break; + default: grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, @@ -274,12 +274,15 @@ grub_multiboot_get_mbi_size (void) + (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) + + ALIGN_UP (sizeof (struct multiboot_tag_basic_meminfo), + MULTIBOOT_TAG_ALIGN) + ALIGN_UP (sizeof (struct multiboot_tag_bootdev), MULTIBOOT_TAG_ALIGN) - + sizeof (struct multiboot_tag_elf_sections) - + elf_sec_entsize * elf_sec_num - + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_count () - * sizeof (struct multiboot_mmap_entry)) + + ALIGN_UP (sizeof (struct multiboot_tag_elf_sections), MULTIBOOT_TAG_ALIGN) + + ALIGN_UP (elf_sec_entsize * elf_sec_num, MULTIBOOT_TAG_ALIGN) + + ALIGN_UP ((sizeof (struct multiboot_tag_mmap) + + grub_get_multiboot_mmap_count () + * sizeof (struct multiboot_mmap_entry)), MULTIBOOT_TAG_ALIGN) + + ALIGN_UP (sizeof (struct multiboot_tag_framebuffer), MULTIBOOT_TAG_ALIGN) + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1 + sizeof (struct multiboot_tag_apm) + MULTIBOOT_TAG_ALIGN - 1; } @@ -329,6 +332,54 @@ grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag) grub_mmap_iterate (hook); } +#if defined (GRUB_MACHINE_PCBIOS) +static void +fill_vbe_tag (struct multiboot_tag_vbe *tag) +{ + grub_vbe_status_t status; + void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + tag->type = MULTIBOOT_TAG_TYPE_VBE; + tag->size = 0; + + status = grub_vbe_bios_get_controller_info (scratch); + if (status != GRUB_VBE_STATUS_OK) + return; + + grub_memcpy (&tag->vbe_control_info, scratch, + sizeof (struct grub_vbe_info_block)); + + status = grub_vbe_bios_get_mode (scratch); + tag->vbe_mode = *(grub_uint32_t *) scratch; + if (status != GRUB_VBE_STATUS_OK) + return; + + /* get_mode_info isn't available for mode 3. */ + if (tag->vbe_mode == 3) + { + struct grub_vbe_mode_info_block *mode_info = (void *) &tag->vbe_mode_info; + 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 (tag->vbe_mode, scratch); + if (status != GRUB_VBE_STATUS_OK) + return; + grub_memcpy (&tag->vbe_mode_info, scratch, + sizeof (struct grub_vbe_mode_info_block)); + } + grub_vbe_bios_get_pm_interface (&tag->vbe_interface_seg, + &tag->vbe_interface_off, + &tag->vbe_interface_len); + + tag->size = sizeof (*tag); +} +#endif + static grub_err_t retrieve_video_parameters (grub_uint8_t **ptrorig) { @@ -417,6 +468,16 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) return GRUB_ERR_NONE; #endif +#if GRUB_MACHINE_HAS_VBE + { + struct multiboot_tag_vbe *tag_vbe = (struct multiboot_tag_vbe *) *ptrorig; + + fill_vbe_tag (tag_vbe); + + *ptrorig += ALIGN_UP (tag_vbe->size, MULTIBOOT_TAG_ALIGN); + } +#endif + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); if (err) return err; @@ -482,7 +543,7 @@ grub_multiboot_make_mbi (grub_uint32_t *target) err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0, 0xffffffff - bufsize, - bufsize, 4, + bufsize, MULTIBOOT_TAG_ALIGN, GRUB_RELOCATOR_PREFERENCE_NONE); if (err) return err; diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c index 4bb46e4cd..2ddb4ca80 100644 --- a/grub-core/video/i386/pc/vbe.c +++ b/grub-core/video/i386/pc/vbe.c @@ -248,6 +248,32 @@ grub_vbe_bios_get_display_start (grub_uint32_t *x, return regs.eax & 0xffff; } +/* Call VESA BIOS 0x4f0a. */ +grub_vbe_status_t +grub_vbe_bios_get_pm_interface (grub_uint16_t *segment, grub_uint16_t *offset, + grub_uint16_t *length) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f0a; + regs.ebx = 0x0000; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + if ((regs.eax & 0xffff) != GRUB_VBE_STATUS_OK) + { + *segment = 0; + *offset = 0; + *length = 0; + } + + *segment = regs.es & 0xffff; + *offset = regs.edi & 0xffff; + *length = regs.ecx & 0xffff; + return regs.eax & 0xffff; +} + + grub_err_t grub_vbe_probe (struct grub_vbe_info_block *info_block) { diff --git a/include/grub/i386/pc/vbe.h b/include/grub/i386/pc/vbe.h index 9b05c2299..fba3ee642 100644 --- a/include/grub/i386/pc/vbe.h +++ b/include/grub/i386/pc/vbe.h @@ -209,6 +209,9 @@ grub_err_t grub_vbe_set_video_mode (grub_uint32_t mode, grub_err_t grub_vbe_get_video_mode (grub_uint32_t *mode); grub_err_t grub_vbe_get_video_mode_info (grub_uint32_t mode, struct grub_vbe_mode_info_block *mode_info); +grub_vbe_status_t +grub_vbe_bios_get_pm_interface (grub_uint16_t *seg, grub_uint16_t *offset, + grub_uint16_t *length); #endif /* ! GRUB_VBE_MACHINE_HEADER */ diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index cbc58b2ee..92837d7d2 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -56,8 +56,10 @@ grub_err_t grub_multiboot_set_video_mode (void); #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU) #include #define GRUB_MACHINE_HAS_VGA_TEXT 1 +#define GRUB_MACHINE_HAS_VBE 1 #else #define GRUB_MACHINE_HAS_VGA_TEXT 0 +#define GRUB_MACHINE_HAS_VBE 0 #endif #define GRUB_MULTIBOOT_CONSOLE_EGA_TEXT 1