I've been looking once again at supporting relatively smooth visual transitions from GRUB to the kernel, which entails deploying 'set gfxpayload=keep' in Ubuntu (I've had it turned off for a while due to various reported problems of the black-screen type). I talked with Matthew Garrett (CCed), a Linux kernel developer friend of mine who knows about the video subsystem, about what would be involved here.
Initially I was strongly advocating using efifb for this, since, hey, GRUB already uses it by default and labels it as GRUB_VIDEO_LINUX_TYPE_SIMPLE, so it must be the simplest option, right? Matthew pointed out that GRUB's current behaviour is actually quite wrong as far as Linux is concerned. It happens to work with the kernel as it is now, because once efifb has been programmed with the framebuffer base address etc. it just acts as a simple linear framebuffer. However, in the future, the Linux developers might well change efifb to support the EFI virtual machine and use EFI for modesetting (and they'd be entitled to do so given its name!), and at this point using efifb on non-EFI systems will break. Matthew said "It's really a bug that efifb doesn't check efi_enabled before binding", so it seems clear to me that GRUB's current code only works by luck. All we actually need is a simple linear framebuffer that we can program using the boot screen_info structure and that can support displaying text quite early in kernel startup (at least to the extent of being able to show output if the initramfs fails to mount the root filesystem). vesafb gives us this just as well as efifb does. The following patch renames GRUB_VIDEO_LINUX_TYPE_SIMPLE back to something less misleading, and programs vesafb rather than efifb on BIOS systems. I also adjusted the (hacky, but not obviously avoidable in context given that lots of people have modular framebuffers) code to check whether the framebuffer is built-in to check the correct framebuffer for the platform, so that we don't shoot the user in the foot. I've tested this with the current Ubuntu Maverick kernel, which has vesafb and fbcon built in, and it works as expected. (fbcon blats the framebuffer contents as soon as it starts up, so you don't yet get a smooth transition, but there's an existing patch which sort of fixes that and I've asked our kernel team to clean it up and get it resubmitted.) 2010-07-05 Colin Watson <cjwat...@ubuntu.com> * include/grub/i386/linux.h (GRUB_VIDEO_LINUX_TYPE_SIMPLE): Rename to ... (GRUB_VIDEO_LINUX_TYPE_EFI): ... this. Update all users. * loader/i386/linux.c (grub_linux_boot): Programming GRUB_VIDEO_LINUX_TYPE_EFI (a.k.a. VIDEO_TYPE_EFI in Linux) is incorrect on BIOS systems; just program GRUB_VIDEO_LINUX_TYPE_VESA (VIDEO_TYPE_VLFB) instead and vesafb will use that mode if possible. * util/grub.d/10_linux.in: Set LINUX_CONFIG_FB appropriately for the platform (based on available video modules). (linux_entry): Check for $LINUX_CONFIG_FB being built-in rather than hardcoding CONFIG_FB_EFI. === modified file 'include/grub/i386/linux.h' --- include/grub/i386/linux.h 2010-01-18 07:49:50 +0000 +++ include/grub/i386/linux.h 2010-07-02 13:04:08 +0000 @@ -81,7 +81,7 @@ struct grub_e820_mmap #define GRUB_VIDEO_LINUX_TYPE_TEXT 0x01 #define GRUB_VIDEO_LINUX_TYPE_VESA 0x23 /* VESA VGA in graphic mode. */ -#define GRUB_VIDEO_LINUX_TYPE_SIMPLE 0x70 /* Linear framebuffer without any additional functions. */ +#define GRUB_VIDEO_LINUX_TYPE_EFI 0x70 /* EFI graphic mode. */ /* For the Linux/i386 boot protocol version 2.03. */ struct linux_kernel_header === modified file 'loader/i386/efi/linux.c' --- loader/i386/efi/linux.c 2010-06-23 08:16:39 +0000 +++ loader/i386/efi/linux.c 2010-07-05 11:09:44 +0000 @@ -317,7 +317,7 @@ grub_linux_setup_video (struct linux_ker params->reserved_mask_size = mode_info.reserved_mask_size; params->reserved_field_pos = mode_info.reserved_field_pos; - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFI; #ifdef GRUB_MACHINE_PCBIOS /* VESA packed modes may come with zeroed mask sizes, which need @@ -775,7 +775,7 @@ grub_cmd_linux (grub_command_t cmd __att else if (grub_memcmp (argv[i], "video=efifb", 11) == 0) { if (params->have_vga) - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFI; } /* Specify the boot file. */ === modified file 'loader/i386/linux.c' --- loader/i386/linux.c 2010-02-10 19:27:12 +0000 +++ loader/i386/linux.c 2010-07-02 13:04:08 +0000 @@ -540,11 +540,8 @@ grub_linux_boot (void) if (! grub_linux_setup_video (params)) { - /* Use generic framebuffer unless VESA is known to be supported. */ - if (params->have_vga != GRUB_VIDEO_LINUX_TYPE_VESA) - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; - else - params->lfb_size >>= 16; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; + params->lfb_size >>= 16; } else { === modified file 'util/grub.d/10_linux.in' --- util/grub.d/10_linux.in 2010-07-02 11:32:05 +0000 +++ util/grub.d/10_linux.in 2010-07-05 15:45:10 +0000 @@ -51,6 +51,14 @@ else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi +if grep -qx vbe "${GRUB_PREFIX}/video.lst"; then + LINUX_CONFIG_FB=CONFIG_FB_VESA +elif grep -q '^efi_' "${GRUB_PREFIX}/video.lst"; then + LINUX_CONFIG_FB=CONFIG_FB_EFI +else + LINUX_CONFIG_FB= +fi + linux_entry () { os="$1" @@ -65,13 +73,16 @@ linux_entry () printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" save_default_entry | sed -e "s/^/\t/" - # Use ELILO's generic "efifb" when it's known to be available. - # FIXME: We need an interface to select vesafb in case efifb can't be used. + # Use a simple linear framebuffer appropriate to the platform if support + # for it is known to be built into the kernel. We need it to be built-in + # rather than modular, as otherwise early output from the kernel won't + # work. if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then cat << EOF load_video EOF - if grep -qx "CONFIG_FB_EFI=y" /boot/config-${version} 2> /dev/null \ + if [ "x$LINUX_CONFIG_FB" != x ] \ + && grep -qx "$LINUX_CONFIG_FB=y" /boot/config-${version} 2> /dev/null \ && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" /boot/config-${version} 2> /dev/null; then cat << EOF set gfxpayload=keep -- Colin Watson [cjwat...@ubuntu.com] _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel