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
20146398c4
(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 <mmontecelo@sipwise.com> for the initial patch and Volodymyr Fedorov <vfedorov@sipwise.com> for underlying research

Change-Id: I5374322cb0a39cfed6563df6c4c30f1eafe560c1
mr9.5.1
Michael Prokop 4 years ago
parent 93209fb893
commit 535e6df392

@ -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

Loading…
Cancel
Save