Most of my workstations & laptops require a passphrase typed in to open the encrypted root filesystem. So my steps to booting are as follows:
- Power on machine
- Wait for FDE passphrase prompt
- Type in FDE passphrase
- Wait for boot to complete and automatic XFCE session to start
Since I need to know when the computer is ready to accept the
passphrase, it is important the framebuffer is usable during the early
part of the boot. In the case of of HP Elitebook 820 G4, the EFI
framebuffer does not appear to work, and I rather not boot in BIOS
mode to get a functional VESA framebuffer. Making things more awkward,
a firmware is needed when the i915 driver is loaded, or the
framebuffer will not work either. (It’s not always clear if a firmware
is needed, so one should run dmesg | grep -F firmware
and check if
firmware is being loaded.)
With this information, the problem is summarized to: “How do I ensure i915 is available at boot with the appropriate firmware?”. This question can be easily generalized to any framebuffer driver, as the steps are more-or-less the same.
§Zeroth step: Do you need only a driver, or a driver with firmware?
IT is a good idea to verify if your kernel is missing a driver at boot, or is missing firmware or both. Boot up a Live USB with good hardware compatibility, such as GRML1 or Ubuntu’s, and let’s see what framebuffer driver our host is trying to use2:
$ dmesg | grep -i 'frame.*buffer'
[ 4.790570] efifb: framebuffer at 0xe0000000, using 8128k, total 8128k
[ 4.790611] fb0: EFI VGA frame buffer device
[ 4.820637] Console: switching to colour frame buffer device 240x67
[ 6.643895] i915 0000:00:02.0: fb1: i915drmfb frame buffer device
Se we can see the efifb is initially used for a couple seconds, then
i915 is used for the rest of the computer’s uptime. Now let’s look
at if firmware is necessary, first checking if modinfo(8)
knows of
any firmware:
$ modinfo i915 -F firmware
i915/bxt_dmc_ver1_07.bin
i915/skl_dmc_ver1_27.bin
i915/kbl_dmc_ver1_04.bin
... SNIP ...
i915/kbl_guc_33.0.0.bin
i915/icl_huc_ver8_4_3238.bin
i915/icl_guc_33.0.0.bin
This indicates this driver will load firmware when available, and if necessary for the particular mode of operation or hardware.
Now let’s look at dmesg to see if any firmware is loaded:
[ 0.222906] Spectre V2 : Enabling Restricted Speculation for firmware calls
[ 5.511731] [drm] Finished loading DMC firmware i915/kbl_dmc_ver1_04.bin (v1.4)
[ 25.579703] iwlwifi 0000:02:00.0: loaded firmware version 36.77d01142.0 op_mode iwlmvm
[ 25.612759] Bluetooth: hci0: Minimum firmware build 1 week 10 2014
[ 25.620251] Bluetooth: hci0: Found device firmware: intel/ibt-12-16.sfi
[ 25.712793] iwlwifi 0000:02:00.0: Allocated 0x00400000 bytes for firmware monitor.
[ 27.042080] Bluetooth: hci0: Waiting for firmware download to complete
Aha! So it appears we need i915/kbl_dmc_ver1_04.bin
for i915. In
the case case one doesn’t need firmware, it won’t show anything
related to drm
or a line with your driver name in it.
By the way, it is a good idea to check dmesg for hints about missing firmware, or alternative drivers, for example my trackpad is supported by both i2c and synaptics based trackpad drivers, and the kernel was kind enough to tell me.
§First step: Obtain the firmware
On Gentoo install
sys-kernel/linux-firmware
. You will have to agree to some non-free
licenses; nothing too inane, but worth mentioning. Now just
run emerge -av sys-kernel/linux-firmware
. (On other distros it
might be this easy, or more difficult; for example—in my experience
Debian does not ship every single firmware like Gentoo does, so
YMMV.)
§Second step, Option A: Compile firmware into your kernel
Since most of my systems run Gentoo, it is business as usual to deploy a kernel with most excess drivers disabled except for common hot-swappable components such as USB network interfaces, audio devices, and so on. For example, this laptop’s config was originally derived from genkernel’ stock amd64 config with most extra drivers disabled, then augmented with support for an Acer ES1-111M-C7DE, and finally with support for this Elitebook.
I had compiled the kernel with i915 support built into the image, as
opposed to an additional kernel module. Unfortunately this meant the
kernel is unable to load firmware from filesystem, because it
appears only kernel modules can load firmware from filesystem. To
work around this without resorting to making i915 a kernel module,
we can include the drivers within the kernel image (vmlinuz
).
Including firmware and drivers both in the vmlinuz has a couple
benefits. First it will always be available. There is no need to
figure out how to load the driver and firmware from initrd, let
alone getting the initrd generator one is using, to cooperate. A
downside is it makes the kernel very specific to the machine,
because perhaps a different Intel machine needs a different firmware
file compiled in.
To achieve including the firmware in kernel, I set the following
values in my kernel config (.config
in your kernel source tree).
CONFIG_EXTRA_FIRMWARE="i915/kbl_dmc_ver1_04.bin"
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
Note, if you’re using menuconfig, you can type /EXTRA_FIRMWARE
(slash for search, then the text) followed by keyboard return to
find where these settings exist in the menu system.
Then I verified i915 is indeed not a kernel module, but built into
the kernel image (it would be m
if it’s a module):
CONFIG_DRM_I915=y
After compiling & installing the kernel (and generating a dracut initrd for cryptsetup/lvm), I was able to reboot and get an early pre-mounted-root framebuffer on this device.
§Second step, Option B: A portable kernel approach (using sys-kernel/vanilla-kernel
)
I discovered the Gentoo devs have begun shipping an ebuild that builds and installs a kernel with a portable, livecd friendly config. In addition this package will optionally generates an initrd with dracut as a pkg_postinst step, making it very suitable as a replacement for users who just want a working kernel, and don’t mind a excessive compatibility (at a cost to size and build time).
This presents a different challenge, because while this package does
allow the user to drop in their own .config, it is not very
multiple-machine-deployment friendly to hard-code each individual
firmware into the kernel. Instead we tell dracut to include our
framebuffer driver. As mentioned above I found this computer uses
the i915
kernel driver for framebuffer. Let’s tell dracut to
include the driver:
cat > /etc/dracut.conf.d/i915.conf <<EOF
add_drivers+=" i915 "
EOF
Dracut is smart enough to pick up the firmware the kernel module
needs, provided they are installed. To get an idea what firmware
dracut will include, run modinfo i915 -F firmware
which will print
out a bunch of firmware relative paths.
After applying this fix, just regenerate your initrd using dracut; in
my case I let portage do the work:
emerge -1av sys-kernel/vanilla-kernel
. Finally reboot.
§Conclusion
Check dmesg. Always check dmesg. We found two ways to deploy firmware, in-kernel and in-initrd. The in-kernel technique is best for a device-specific kernel, the in-initrd is best for a portable kernel. I am a big fan of the second technique because it scales well to many machines.
I did not touch on the political side of using binary blobs. It would be nice to not use any non-free software, but I rather have a working system with a couple small non-free components, than a non-working system. Which is more valuable, your freedom, or reduced capacity of your tools?
-
GRML is my favorite live media. It is simple, to the point, has lots of little scripts to streamline tasks such as setting up a wireless AP, a iPXE netboot environment, a router, installing debian, and so on. And Remastering is relatively straight forward. It also has a sane gui sutable for any machine (fluxbox). ↩︎