Skip to contentSkip to conversation

Rework vesafb/efifb handling in GRUB

PATCH In review Colin Watson 2 participants 3 messages Jul 5, 2010 – Jul 6, 2010

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Rework vesafb/efifb handling in GRUB

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 <[email protected]>

* 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'

grub/i386/linux.h +1 -1
@@ -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'

i386/efi/linux.c +2 -2
@@ -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'

i386/linux.c +2 -5
@@ -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'

grub.d/10_linux.in +14 -3
@@ -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
Signature · 1 line
Colin Watson                                       [[email protected]]
#1 lore raw
Quoted 7 lines · Colin Watson

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.

Quoted 10 lines

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!),

IMHO it's a plain overkill. efifb main use is to supply the transition until the real KMS driver is loaded or for recovery situations. Implementing anything more than framebuffer writing seems to be work for nothing for me.

Quoted 4 lines

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",

AFAIK EFI doesn't have any useful functions when bootloader is terminated.

Quoted 11 lines

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.

No it doesn't. Passing vesafb we claim that:
a) vesa is working
b) mode was set by vesa.
Both assumptions are plainly wrong when GRUB uses native driver, especially in vbe-free environment. This leads to kernel crash.

Quoted 3 lines

The following patch renames GRUB_VIDEO_LINUX_TYPE_SIMPLE back to something less misleading, and programs vesafb rather than efifb on BIOS systems.

I'm ok to use another ID if Linux standartises the ID when bootloader claims "at this fb address you have a simple framebuffer with following characteristics, don't even try to use firmware, unload in handover to real driver for the same card"

Signature · 2 lines
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
#2 lore raw
Quoted 12 lines · Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 10 lines · Colin Watson

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!),

Quoted 4 lines

IMHO it's a plain overkill. efifb main use is to supply the transition until the real KMS driver is loaded or for recovery situations. Implementing anything more than framebuffer writing seems to be work for nothing for me.

Firstly, as far as booting Linux is concerned I think we should be taking the word of the Linux developers when they tell us that setting a particular video ID is inappropriate. It's not our business to define their interfaces for them.

Secondly, KMS still doesn't work everywhere and so there'll still be cases where efifb ends up sticking around permanently for one reason or another.

Quoted 5 lines
Quoted 3 lines

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",

AFAIK EFI doesn't have any useful functions when bootloader is terminated.

I'd have to check on this, but I think this is by analogy with the way some BIOS-based drivers call into the video BIOS on resume in order to reinitialise the card.

Quoted 11 lines
Quoted 5 lines

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.

No it doesn't. Passing vesafb we claim that:
a) vesa is working
b) mode was set by vesa.
Both assumptions are plainly wrong when GRUB uses native driver, especially in vbe-free environment. This leads to kernel crash.

Interesting. How about we program vesafb when GRUB's vbe driver is active, then? That at least should be perfectly reasonable, and covers the majority of cases on BIOS systems.

Quoted 8 lines
Quoted 3 lines

The following patch renames GRUB_VIDEO_LINUX_TYPE_SIMPLE back to something less misleading, and programs vesafb rather than efifb on BIOS systems.

I'm ok to use another ID if Linux standartises the ID when bootloader claims "at this fb address you have a simple framebuffer with following characteristics, don't even try to use firmware, unload in handover to real driver for the same card"

I think that regardless of this we need to stop using VIDEO_TYPE_EFI, because, frankly, the Linux developers asked us to and it's only polite. I'd like to have something else in place, which is why I'm looking at when we can safely use VIDEO_TYPE_VLFB, but VIDEO_TYPE_EFI isn't documented as a simple linear framebuffer and it's really interface abuse for us to take it over for that purpose without the kernel saying it's OK.

Thanks,

Signature · 1 line
Colin Watson                                       [[email protected]]