From 535e6df392a1ce5022966fbe87cf1eb5b37fb57e Mon Sep 17 00:00:00 2001 From: Michael Prokop Date: Thu, 27 May 2021 17:39:28 +0200 Subject: [PATCH] TT#118659 Use "efivarfs" instead of "efivars" + mount /sys/firmware/efi/efivars for efibootmgr Current trunk installations based on bullseye using recent Grml environments are broken, as EFI environments running with recent kernel versions (>=5.10) aren't properly detected anymore. This is caused by the missing efivars kernel module. CONFIG_EFI_VARS is no longer available since https://salsa.debian.org/kernel-team/linux/-/commit/20146398c4599147244ed3ffc54f38d07fb8dea3 (tagged initially as debian/5.10.1-1_exp1 + shipped with kernel package 5.10.1-1~exp1 and newer, incl. 5.10.38-1 as present in current Debian/unstable). Therefore the kernel module efivars is no longer available on more recent Debian kernel systems. Quoting from https://wiki.debian.org/UEFI: | The older interface was efivars, showing files under | /sys/firmware/efi/vars, and this is what was used by default in both | Wheezy and Jessie. | | The new interface is efivarfs, which will expose things in a slightly | different format under /sys/firmware/efi/efivars. This is the new | preferred way of using UEFI configuration variables, and Debian switched | to it by default from Stretch onwards. CONFIG_EFI_VARS is no longer required, instead efivarfs seems to be available starting with kernel v3.10 and newer (see linux.git): | commit a9499fa7cd3fd4824a7202d00c766b269fa3bda6 | Author: Tom Gundersen teg@jklm.no | Date: Fri Feb 8 15:37:06 2013 +0000 | | efi: split efisubsystem from efivars | | This registers /sys/firmware/efi/{,systab,efivars/} whenever EFI is enabled | and the system is booted with EFI. | | This allows | *) userspace to check for the existence of /sys/firmware/efi as a way | to determine whether or it is running on an EFI system. | *) 'mount -t efivarfs none /sys/firmware/efi/efivars' without manually | loading any modules. | | [ Also, move the efivar API into vars.c and unconditionally compile it. | This allows us to move efivars.c, which now only contains the sysfs | variable code, into the firmware/efi directory. Note that the efivars.c | filename is kept to maintain backwards compatability with the old | efivars.ko module. With this patch it is now possible for efivarfs | to be built without CONFIG_EFI_VARS - Matt ] and: | commit d68772b7c83f4b518be15ae96f4827c8ed02f684 | Author: Matt Fleming matt.fleming@intel.com | Date: Fri Feb 8 16:27:24 2013 +0000 | | efivarfs: Move to fs/efivarfs | | Now that efivarfs uses the efivar API, move it out of efivars.c and | into fs/efivarfs where it belongs. This move will eventually allow us | to enable the efivarfs code without having to also enable | CONFIG_EFI_VARS built, and vice versa. | | Furthermore, things like, | | mount -t efivarfs none /sys/firmware/efi/efivars | | will now work if efivarfs is built as a module without requiring the | use of MODULE_ALIAS(), which would have been necessary when the | efivarfs code was part of efivars.c. But we also need to ensure /sys/firmware/efi/efivars is mounted, otherwise efibootmgr fails to execute: | # efibootmgr | EFI variables are not supported on this system. | # lsmod| grep efi | efi_pstore 16384 0 | efivarfs 16384 1 | # mount -t efivarfs none /sys/firmware/efi/efivars | # efibootmgr | BootCurrent: 0002 | Timeout: 3 seconds | BootOrder: 0001,0002,0003,0000,0004 | Boot0000* UiApp | Boot0001* UEFI QEMU QEMU HARDDISK | Boot0002* UEFI PXEv4 (MAC:02B31C8CA0AA) | Boot0003* UEFI PXEv4 (MAC:92097BD02A48) | Boot0004* EFI Internal Shell FTR: we can't test only for existence of directory /sys/firmware/efi/efivars, as it exists but is empty by default, so we need to look inside the directory instead. See https://github.com/grml/grml-debootstrap/pull/174 for the related grml-debootstrap upstream change, which is supposed to be released as of grml-debootstrap v0.97. But as a) grml-debootstrap v0.97 isn't released yet, b) it's unclear whether grml-debootstrap v0.97 will make it into bullseye (soonish, or if at all) and c) we don't have the Grml repositories available via our approx Debian mirror (as used in our PRO/Carrier environments) and don't want to update our Grml squashfs system for this change neither, we need to apply a workaround for this efivars vs efivarfs situation. Otherwise Debian installation fails in EFI environments using Debian kernel >=5.10. Thankfully we can work around this using according pre/post scripts in grml-debootstrap, that's what efivars_workaround() is all about. Thanks: Manuel Montecelo for the initial patch and Volodymyr Fedorov for underlying research Change-Id: I5374322cb0a39cfed6563df6c4c30f1eafe560c1 --- templates/scripts/includes/deployment.sh | 85 +++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/templates/scripts/includes/deployment.sh b/templates/scripts/includes/deployment.sh index 66901e9..b6a5865 100755 --- a/templates/scripts/includes/deployment.sh +++ b/templates/scripts/includes/deployment.sh @@ -341,12 +341,12 @@ wait_exit() { # check for EFI support, if not present try to enable it efi_support() { - if lsmod | grep -q efivars ; then + if lsmod | grep -q efivarfs ; then echo "EFI support detected." return 0 fi - if modprobe efivars &>/dev/null ; then + if modprobe efivarfs &>/dev/null ; then echo "EFI support enabled now." return 0 fi @@ -354,6 +354,74 @@ efi_support() { return 1 } +# Debian kernels >=5.10 don't provide efivars support, ensure to either: +# 1) have grml-debootstrap v0.97 or newer available (which provides according +# efivarfs workaround), or otherwise: +# 2) apply local workaround using pre and post scripts within grml-debootstrap +# (to avoid having to update the grml-debootstrap package, because that's not +# available within environments relying on our approx Debian mirror, which +# doesn't the Grml repository) +efivars_workaround() { + if lsmod | grep -q 'efivars' ; then + echo "We do have efivars support, no need to apply workarounds" + return 0 + fi + + echo "Running with kernel without efivars support" + if check_package_version grml-debootstrap 0.97~ ; then + echo "grml-debootstrap >=0.97 available, no need to apply pre/post script workaround" + return 0 + fi + + echo "Present grml-debootstrap version is not recent enough, falling back to workarounds using local scripts" + + # pre script + mkdir -p /etc/debootstrap/pre-scripts/ + cat > /etc/debootstrap/pre-scripts/efivarfs << "EOL" +#!/bin/bash +set -eu -p pipefail + +echo "Executing $0" + +if ! ls "${MNTPOINT}"/sys/firmware/efi/efivars/* &>/dev/null ; then + # we need to have /sys available to be able to mount /sys/firmware/efi/efivars + if ! chroot "${MNTPOINT}" test -d /sys/kernel ; then + echo "Mointing /sys" + chroot "${MNTPOINT}" mount -t sysfs none /sys + fi + + echo "Mounting efivarfs on /sys/firmware/efi/efivars" + chroot "${MNTPOINT}" mount -t efivarfs efivarfs /sys/firmware/efi/efivars +fi +echo "Finished execution of $0" +EOL + + chmod 775 /etc/debootstrap/pre-scripts/efivarfs + PRE_SCRIPTS_OPTION="--pre-scripts /etc/debootstrap/pre-scripts/" + + # post script + mkdir -p /etc/debootstrap/post-scripts/ + cat > /etc/debootstrap/post-scripts/efivarfs << "EOL" +#!/bin/bash +set -eu -p pipefail + +echo "Executing $0" + +if mountpoint "${MNTPOINT}"/sys/firmware/efi/efivars &>/dev/null ; then + umount "${MNTPOINT}"/sys/firmware/efi/efivars +fi + +if mountpoint "${MNTPOINT}"/sys &>/dev/null ; then + umount "${MNTPOINT}"/sys +fi + +echo "Finished execution of $0" +EOL + + chmod 775 /etc/debootstrap/post-scripts/efivarfs + POST_SCRIPTS_OPTION="--post-scripts /etc/debootstrap/post-scripts/" +} + cdr2mask() { # From https://stackoverflow.com/questions/20762575/explanation-of-convertor-of-cidr-to-netmask-in-linux-shell-netmask2cdir-and-cdir # Number of args to shift, 255..255, first non-255 byte, zeroes @@ -1934,6 +2002,9 @@ if [[ -n "${EFI_PARTITION}" ]] ; then if efi_support ; then echo "EFI support present, enabling EFI support within grml-debootstrap" EFI_OPTION="--efi ${EFI_PARTITION}" + + # this can be dropped once we have grml-debootstrap >=v0.97 available in our squashfs + efivars_workaround else echo "EFI support NOT present, not enabling EFI support within grml-debootstrap" fi @@ -1956,6 +2027,8 @@ echo y | grml-debootstrap \ -r "$DEBIAN_RELEASE" \ -t "$ROOT_FS" \ $EFI_OPTION \ + $PRE_SCRIPTS_OPTION \ + $POST_SCRIPTS_OPTION \ --password 'sipwise' 2>&1 | tee -a /tmp/grml-debootstrap.log if [ "${PIPESTATUS[1]}" != "0" ]; then @@ -2228,6 +2301,13 @@ if [[ "${SWRAID}" = "true" ]] ; then if efi_support ; then grml-chroot "${TARGET}" mount /boot/efi + # if efivarfs kernel module is loaded, but efivars isn't, + # then we need to mount efivarfs for efibootmgr usage + if ! ls /sys/firmware/efi/efivars/* &>/dev/null ; then + echo "Mounting efivarfs on /sys/firmware/efi/efivars" + grml-chroot "${TARGET}" mount -t efivarfs efivarfs /sys/firmware/efi/efivars + fi + if efibootmgr | grep -q 'NGCP Fallback' ; then echo "Deleting existing NGCP Fallback entry from EFI boot manager" efi_entry=$(efibootmgr | awk '/ NGCP Fallback$/ {print $1; exit}' | sed 's/^Boot//; s/\*$//') @@ -2253,6 +2333,7 @@ fi # don't leave any mountpoints sync +umount ${TARGET}/sys/firmware/efi/efivars || true umount ${TARGET}/boot/efi || true umount ${TARGET}/proc || true umount ${TARGET}/sys || true