Index: ChangeLog =================================================================== RCS file: /cvsroot/grub/grub/ChangeLog,v retrieving revision 1.441 diff -u -r1.441 ChangeLog --- ChangeLog 2001/11/12 06:57:28 1.441 +++ ChangeLog 2001/11/21 16:21:59 @@ -1,3 +1,27 @@ +2001-11-18 Alexander Thiel + + * stage2/shared.h (VBE_FAR_PTR): New macro. + (mbh): Declared. + (vbe_info_block): Likewise. + (mode_info_block): Likewise. + (mode_list): Likewise. + * stage2/common.c: (vbe_info_block): Defined. + (mode_info_block): Likewise. + (mode_list): Likewise. + (init_bios_info): Probe for VBE compliant BIOS and + set mbi.flags accordingly. + * stage2/boot.c (mbh): Defined. + (load_image): Replaced pu.mb by mbh and flags by mbh->flags. + Added code to handle graphics request from multiboot kernels. + * stage2/builtins.c: + (boot_func): Switch video mode before booting + a multiboot kernel. + (testvbe_func): Renamed controller to vbe_info_block and mode to + mode_info_block. Check flag MB_INFO_VIDEO_INFO instead of probing + the BIOS. + (vbeprobe): Likewise. Replaced vbe_far_ptr_to_linear by VBE_FAR_PTR. + Use global mode_list. + 2001-11-12 Yoshinori K. Okuji * docs/grub.texi: The copyright of this file is only held by Index: stage2/boot.c =================================================================== RCS file: /cvsroot/grub/grub/stage2/boot.c,v retrieving revision 1.36 diff -u -r1.36 boot.c --- stage2/boot.c 2001/11/12 06:57:29 1.36 +++ stage2/boot.c 2001/11/21 16:21:59 @@ -29,6 +29,7 @@ entry_func entry_addr; static struct mod_list mll[99]; +struct multiboot_header *mbh; /* * The next two functions, 'load_image' and 'load_module', are the building @@ -43,12 +44,11 @@ int len, i, exec_type = 0, align_4k = 1; entry_func real_entry_addr = 0; kernel_t type = KERNEL_TYPE_NONE; - unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0; + unsigned long text_len = 0, data_len = 0, bss_len = 0; char *str = 0, *str2 = 0; struct linux_kernel_header *lh; union { - struct multiboot_header *mb; struct exec *aout; Elf32_Ehdr *elf; } @@ -57,10 +57,6 @@ executable header */ unsigned char buffer[MULTIBOOT_SEARCH]; - /* sets the header pointer to point to the beginning of the - buffer by default */ - pu.aout = (struct exec *) buffer; - if (!grub_open (kernel)) return KERNEL_TYPE_NONE; @@ -78,8 +74,8 @@ { if (MULTIBOOT_FOUND ((int) (buffer + i), len - i)) { - flags = ((struct multiboot_header *) (buffer + i))->flags; - if (flags & MULTIBOOT_UNSUPPORTED) + mbh = (struct multiboot_header *) (buffer + i); + if (mbh->flags & MULTIBOOT_UNSUPPORTED) { grub_close (); errnum = ERR_BOOT_FEATURES; @@ -91,6 +87,57 @@ } } + /* Handle graphics request for multiboot kernels */ + if (type == KERNEL_TYPE_MULTIBOOT && + mbh->flags & MULTIBOOT_VIDEO_MODE && + mbi.flags & MB_INFO_VIDEO_INFO) + { + mbi.vbe_mode = 0x03; /* default */ + + if (mbh->mode_type == 0) + { + unsigned short fallback = 0xFFFF; + + for (mode_list + = (unsigned short *) VBE_FAR_PTR (vbe_info_block.video_mode); + *mode_list != 0xFFFF; + mode_list++) + { + if (get_vbe_mode_info (*mode_list, &mode_info_block) != 0x004F + || (mode_info_block.mode_attributes & 0x0091) != 0x0091) + continue; + + /* use the first valid mode as fallback */ + if (fallback == 0xFFFF) fallback = *mode_list; + + if (mbh->width == mode_info_block.x_resolution && + mbh->height == mode_info_block.y_resolution && + mbh->depth == mode_info_block.bits_per_pixel ) + { + mbi.vbe_mode = *mode_list; + break; + } + } + + if (*mode_list == 0xFFFF && fallback != 0xFFFF) + mbi.vbe_mode = fallback; + + } + + if (debug) + { + grub_printf ("%s mode requested: %dx%dx%d\n", + (mbh->mode_type == 0 ? "VBE graphics" : "Text"), + mbh->width, mbh->height, mbh->depth); + grub_printf ("Mode selected: 0x%x\n", mbi.vbe_mode); + } + + } /* end graphics request */ + + /* sets the header pointer to point to the beginning of the + buffer by default */ + pu.aout = (struct exec *) buffer; + /* Use BUFFER as a linux kernel header, if the image is Linux zImage or bzImage. */ lh = (struct linux_kernel_header *) buffer; @@ -134,7 +181,7 @@ } } } - else if (flags & MULTIBOOT_AOUT_KLUDGE) + else if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) { pu.mb = (struct multiboot_header *) (buffer + i); entry_addr = (entry_func) pu.mb->entry_addr; @@ -397,7 +444,7 @@ if (exec_type) /* can be loaded like a.out */ { - if (flags & MULTIBOOT_AOUT_KLUDGE) + if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) str = "-and-data"; printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len); @@ -407,7 +454,7 @@ { cur_addr += text_len; - if (!(flags & MULTIBOOT_AOUT_KLUDGE)) + if (!(mbh->flags & MULTIBOOT_AOUT_KLUDGE)) { /* we have to align to a 4K boundary */ if (align_4k) Index: stage2/builtins.c =================================================================== RCS file: /cvsroot/grub/grub/stage2/builtins.c,v retrieving revision 1.116 diff -u -r1.116 builtins.c --- stage2/builtins.c 2001/11/12 06:57:29 1.116 +++ stage2/builtins.c 2001/11/21 16:22:02 @@ -326,6 +326,21 @@ case KERNEL_TYPE_MULTIBOOT: /* Multiboot */ + + /* MB specs require this */ + if (! (mbh->flags & MULTIBOOT_VIDEO_MODE)) + mbi.flags &= ~MB_INFO_VIDEO_INFO; + + /* Switch to video mode */ + if (mbi.vbe_mode != 0x03 && + (set_vbe_mode (mbi.vbe_mode) != 0x004F || + get_vbe_mode_info (mbi.vbe_mode, &mode_info_block) != 0x004F)) + { + /* fallback to text mode */ + mbi.vbe_mode = 0x03; + set_vbe_mode(mbi.vbe_mode); + } + multi_boot ((int) entry_addr, (int) &mbi); break; @@ -4099,8 +4114,6 @@ testvbe_func (char *arg, int flags) { int mode_number; - struct vbe_controller controller; - struct vbe_mode mode; if (! *arg) { @@ -4111,26 +4124,22 @@ if (! safe_parse_maxint (&arg, &mode_number)) return 1; - /* Preset `VBE2'. */ - grub_memmove (controller.signature, "VBE2", 4); - - /* Detect VBE BIOS. */ - if (get_vbe_controller_info (&controller) != 0x004F) + if (! (mbi.flags & MB_INFO_VIDEO_INFO)) { grub_printf (" VBE BIOS is not present.\n"); return 0; } - if (controller.version < 0x0200) + if (vbe_info_block.version < 0x0200) { grub_printf (" VBE version %d.%d is not supported.\n", - (int) (controller.version >> 8), - (int) (controller.version & 0xFF)); + (int) (vbe_info_block.version >> 8), + (int) (vbe_info_block.version & 0xFF)); return 0; } - if (get_vbe_mode_info (mode_number, &mode) != 0x004F - || (mode.mode_attributes & 0x0091) != 0x0091) + if (get_vbe_mode_info (mode_number, &mode_info_block) != 0x004F + || (mode_info_block.mode_attributes & 0x0091) != 0x0091) { grub_printf (" Mode 0x%x is not supported.\n", mode_number); return 0; @@ -4145,13 +4154,13 @@ /* Draw something on the screen... */ { - unsigned char *base_buf = (unsigned char *) mode.phys_base; - int scanline = controller.version >= 0x0300 - ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline; + unsigned char *base_buf = (unsigned char *) mode_info_block.phys_base; + int scanline = vbe_info_block.version >= 0x0300 + ? mode_info_block.linear_bytes_per_scanline : mode_info_block.bytes_per_scanline; /* FIXME: this assumes that any depth is a modulo of 8. */ - int bpp = mode.bits_per_pixel / 8; - int width = mode.x_resolution; - int height = mode.y_resolution; + int bpp = mode_info_block.bits_per_pixel / 8; + int width = mode_info_block.x_resolution; + int height = mode_info_block.y_resolution; int x, y; unsigned color = 0; @@ -4319,70 +4328,53 @@ static int vbeprobe_func (char *arg, int flags) { - struct vbe_controller controller; - unsigned short *mode_list; int mode_number = -1; int count = 1; - auto unsigned long vbe_far_ptr_to_linear (unsigned long); - - unsigned long vbe_far_ptr_to_linear (unsigned long ptr) - { - unsigned short seg = (ptr >> 16); - unsigned short off = (ptr & 0xFFFF); - - return (seg << 4) + off; - } - if (*arg) { if (! safe_parse_maxint (&arg, &mode_number)) return 1; } - /* Set the signature to `VBE2', to obtain VBE 3.0 information. */ - grub_memmove (controller.signature, "VBE2", 4); - - if (get_vbe_controller_info (&controller) != 0x004F) + if (! (mbi.flags & MB_INFO_VIDEO_INFO)) { grub_printf (" VBE BIOS is not present.\n"); return 0; } /* Check the version. */ - if (controller.version < 0x0200) + if (vbe_info_block.version < 0x0200) { grub_printf (" VBE version %d.%d is not supported.\n", - (int) (controller.version >> 8), - (int) (controller.version & 0xFF)); + (int) (vbe_info_block.version >> 8), + (int) (vbe_info_block.version & 0xFF)); return 0; } /* Print some information. */ grub_printf (" VBE version %d.%d\n", - (int) (controller.version >> 8), - (int) (controller.version & 0xFF)); + (int) (vbe_info_block.version >> 8), + (int) (vbe_info_block.version & 0xFF)); /* Iterate probing modes. */ for (mode_list - = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode); + = (unsigned short *) VBE_FAR_PTR (vbe_info_block.video_mode); *mode_list != 0xFFFF; mode_list++) { - struct vbe_mode mode; - - if (get_vbe_mode_info (*mode_list, &mode) != 0x004F) + if (get_vbe_mode_info (*mode_list, &mode_info_block) != 0x004F) continue; /* Skip this, if this is not supported or linear frame buffer mode is not support. */ - if ((mode.mode_attributes & 0x0081) != 0x0081) + if ((mode_info_block.mode_attributes & 0x0001) != 0x0001) continue; if (mode_number == -1 || mode_number == *mode_list) { char *model; - switch (mode.memory_model) + switch (mode_info_block.memory_model) { case 0x00: model = "Text"; break; case 0x01: model = "CGA graphics"; break; @@ -4398,9 +4390,9 @@ grub_printf (" 0x%x: %s, %ux%ux%u\n", (unsigned) *mode_list, model, - (unsigned) mode.x_resolution, - (unsigned) mode.y_resolution, - (unsigned) mode.bits_per_pixel); + (unsigned) mode_info_block.x_resolution, + (unsigned) mode_info_block.y_resolution, + (unsigned) mode_info_block.bits_per_pixel); if (mode_number != -1) break; @@ -4429,8 +4421,8 @@ vbeprobe_func, BUILTIN_CMDLINE, "vbeprobe [MODE]", - "Probe VBE information. If the mode number MODE is specified, show only" - "the information about only the mode." + "Probe VBE information. If the mode number MODE is specified, show " + "information about that mode only." }; Index: stage2/common.c =================================================================== RCS file: /cvsroot/grub/grub/stage2/common.c,v retrieving revision 1.19 diff -u -r1.19 common.c --- stage2/common.c 2001/11/12 06:57:29 1.19 +++ stage2/common.c 2001/11/21 16:22:02 @@ -29,6 +29,9 @@ */ struct multiboot_info mbi; +struct vbe_controller vbe_info_block; +struct vbe_mode mode_info_block; +unsigned short *mode_list; unsigned long saved_drive; unsigned long saved_partition; #ifndef STAGE1_5 @@ -316,19 +319,29 @@ /* Get the APM BIOS table. */ get_apm_info (); if (apm_bios_info.version) + { + mbi.flags |= MB_INFO_APM_TABLE; mbi.apm_table = (unsigned long) &apm_bios_info; + } + + /* Set the signature to `VBE2', to obtain VBE 3.0 information. */ + grub_memmove (vbe_info_block.signature, "VBE2", 4); + + if (get_vbe_controller_info (&vbe_info_block) == 0x004F) + { + mbi.flags |= MB_INFO_VIDEO_INFO; + mbi.vbe_control_info = (unsigned long) &vbe_info_block; + mbi.vbe_mode_info = (unsigned long) &mode_info_block; + } /* * Initialize other Multiboot Info flags. */ - mbi.flags = (MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV + mbi.flags |= (MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV | MB_INFO_DRIVE_INFO | MB_INFO_CONFIG_TABLE | MB_INFO_BOOT_LOADER_NAME); - if (apm_bios_info.version) - mbi.flags |= MB_INFO_APM_TABLE; - #endif /* STAGE1_5 */ #ifdef SUPPORT_DISKLESS Index: stage2/shared.h =================================================================== RCS file: /cvsroot/grub/grub/stage2/shared.h,v retrieving revision 1.79 diff -u -r1.79 shared.h --- stage2/shared.h 2001/11/12 06:57:29 1.79 +++ stage2/shared.h 2001/11/21 16:22:02 @@ -388,6 +388,7 @@ #include "mb_header.h" #include "mb_info.h" +extern struct multiboot_header *mbh; /* For the Linux/i386 boot protocol version 2.02. */ struct linux_kernel_header @@ -662,6 +663,9 @@ */ extern struct multiboot_info mbi; +struct vbe_controller vbe_info_block; +struct vbe_mode mode_info_block; +extern unsigned short *mode_list; extern unsigned long saved_drive; extern unsigned long saved_partition; #ifndef STAGE1_5 @@ -760,6 +764,9 @@ /* Set VBE mode. */ int set_vbe_mode (int mode_number); + +/* Convert 32-bit pointer to 16-bit segment:offset style pointer */ +#define VBE_FAR_PTR(p) (((p >> 16) << 4) + (p & 0xFFFF)) /* Return the data area immediately following our code. */ int get_code_end (void);