[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Rework vesafb/efifb handling in GRUB

From: Colin Watson
Subject: [PATCH] Rework vesafb/efifb handling in GRUB
Date: Mon, 5 Jul 2010 18:00:23 +0100
User-agent: Mutt/1.5.18 (2008-05-17)

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

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

2010-07-05  Colin Watson  <address@hidden>

        * 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/ 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;
   /* 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;

=== modified file 'util/grub.d/'
--- util/grub.d/     2010-07-02 11:32:05 +0000
+++ util/grub.d/     2010-07-05 15:45:10 +0000
@@ -51,6 +51,14 @@ else
+if grep -qx vbe "${GRUB_PREFIX}/video.lst"; then
+elif grep -q '^efi_' "${GRUB_PREFIX}/video.lst"; then
 linux_entry ()
@@ -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
-      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                                       address@hidden

reply via email to

[Prev in Thread] Current Thread [Next in Thread]