[pve-devel] [RFC pve-kernel-meta 3/5] proxmox-boot: keep EFI and legacy bootloaders in sync

Stoiko Ivanov s.ivanov at proxmox.com
Tue Feb 1 23:03:29 CET 2022


The current boot-scheme with grub for legacy boot and systemd-boot for
UEFI makes it quite cumbersome to switch from one boot mode to the
other (by booting a live-cd, chrooting into the system with the
new boot-mode and running p-b-t init for the configured ESPs).
Additionally it causes old, unused kernel+initrd versions to take up
space on the ESPs (if a switch was performed - the old boot-mode files
are never cleaned up)

Sadly FAT does not support symlinks so it is not possible to copy the
kernel+image once and symlink it for both boot-loaders.
However systemd-boot does not need to have the files in a
vendor/version specific subdirectory (although this is against the
recommendations of the boot-loader-specification [0]) - so we can
simply point the entries to boot the kernel+initrd image from the ESPs
root (where grub needs them).

The UEFI spec on the directory structure [1], also should be fine with
it.

With the following patch p-b-t simply installs both boot-loaders in
parallel - if booted in legacy mode bootctl cannot update the efivars
accordingly - but bootctl installs systemd-boot as default boot-loader
($esp_root/EFI/BOOT/BOOTX64.EFI) in any case - so it should at least
be reachable from most UEFI menus.

Quickly tested on two VMs (one with UEFI one with legacy) - and
switching their BIOS setting did not change their ability to boot.

[0] https://systemd.io/BOOT_LOADER_SPECIFICATION/
[1] section 13.3.1.3 of
https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf

Signed-off-by: Stoiko Ivanov <s.ivanov at proxmox.com>
---
 bin/proxmox-boot-tool        | 38 ++++++++--------
 proxmox-boot/zz-proxmox-boot | 88 ++++++++++--------------------------
 2 files changed, 45 insertions(+), 81 deletions(-)

diff --git a/bin/proxmox-boot-tool b/bin/proxmox-boot-tool
index af473a5..5397694 100755
--- a/bin/proxmox-boot-tool
+++ b/bin/proxmox-boot-tool
@@ -150,24 +150,26 @@ init_bootloader() {
 	echo "Mounting '$part' on '$esp_mp'."
 	mount -t vfat "$part" "$esp_mp"
 
-	if [ -d /sys/firmware/efi ]; then
-		echo "Installing systemd-boot.."
-		mkdir -p "$esp_mp/$PMX_ESP_DIR"
-		bootctl --path "$esp_mp" install
-
-		echo "Configuring systemd-boot.."
-		echo "timeout 3" > "$esp_mp/$PMX_LOADER_CONF.tmp"
-		echo "default proxmox-*" >> "$esp_mp/$PMX_LOADER_CONF.tmp"
-		mv "$esp_mp/$PMX_LOADER_CONF.tmp" "$esp_mp/$PMX_LOADER_CONF"
-	else
-		echo "Installing grub i386-pc target.."
-		grub-install.real \
-			--boot-directory $esp_mp \
-			--target i386-pc \
-			--no-floppy \
-			--bootloader-id='proxmox' \
-			"/dev/$PKNAME"
-	fi
+	echo "Installing systemd-boot.."
+	mkdir -p "$esp_mp/$PMX_ESP_DIR"
+	bootctl_args="--path ${esp_mp}"
+	if [ ! -d /sys/firmware/efi ]; then
+		bootctl_args="${bootctl_args} --no-variables"
+	fi
+
+	bootctl ${bootctl_args} install
+	echo "Configuring systemd-boot.."
+	echo "timeout 3" > "$esp_mp/$PMX_LOADER_CONF.tmp"
+	echo "default proxmox-*" >> "$esp_mp/$PMX_LOADER_CONF.tmp"
+	mv "$esp_mp/$PMX_LOADER_CONF.tmp" "$esp_mp/$PMX_LOADER_CONF"
+
+	echo "Installing grub i386-pc target.."
+	grub-install.real \
+		--boot-directory $esp_mp \
+		--target i386-pc \
+		--no-floppy \
+		--bootloader-id='proxmox' \
+		"/dev/$PKNAME"
 	echo "Unmounting '$part'."
 	umount "$part"
 
diff --git a/proxmox-boot/zz-proxmox-boot b/proxmox-boot/zz-proxmox-boot
index 27448b2..5609af2 100755
--- a/proxmox-boot/zz-proxmox-boot
+++ b/proxmox-boot/zz-proxmox-boot
@@ -75,16 +75,11 @@ update_esp_func() {
 		{ warn "creation of mountpoint ${mountpoint} failed - skipping"; return; }
 	mount "${path}" "${mountpoint}" || \
 		{ warn "mount of ${path} failed - skipping"; return; }
-	if [ -d /sys/firmware/efi ]; then
-		if [ ! -f "${mountpoint}/$PMX_LOADER_CONF" ]; then
-			warn "${path} contains no loader.conf - skipping"
-			return
-		fi
-		if [ ! -d "${mountpoint}/$PMX_ESP_DIR" ]; then
-			warn "${path}/$PMX_ESP_DIR does not exist- skipping"
-			return
-		fi
-	elif [ ! -d "${mountpoint}/grub" ]; then
+	if [ ! -f "${mountpoint}/$PMX_LOADER_CONF" ]; then
+		warn "${path} contains no loader.conf - skipping"
+		return
+	fi
+	if [ ! -d "${mountpoint}/grub" ]; then
 		warn "${path} contains no grub directory - skipping"
 		return
 	fi
@@ -94,17 +89,12 @@ update_esp_func() {
 	if [ -e "${PINNED_KERNEL_CONF}" ]; then
 	    pinned_kernel=$(get_first_line "${PINNED_KERNEL_CONF}")
 	fi
-	if [ -d /sys/firmware/efi ]; then
-		set_systemd_boot_default "${mountpoint}" "${pinned_kernel}"
-		remove_old_kernels_efi "${mountpoint}"
-	else
-		set_grub_default "${pinned_kernel}"
-		remove_old_kernels_legacy "${mountpoint}"
-		mount --bind "${mountpoint}" "/boot"
-		update-grub
-		umount /boot
-
-	fi
+	set_systemd_boot_default "${mountpoint}" "${pinned_kernel}"
+	set_grub_default "${pinned_kernel}"
+	remove_old_kernels "${mountpoint}"
+	mount --bind "${mountpoint}" "/boot"
+	update-grub
+	umount /boot
 
 	umount "${mountpoint}" || \
 		{ warn "umount of ${path} failed - failure"; exit 0; }
@@ -130,52 +120,23 @@ copy_and_config_kernels() {
 			continue
 		fi
 
-		if [ -d /sys/firmware/efi ]; then
-
-			warn "	Copying kernel and creating boot-entry for ${kver}"
-			KERNEL_ESP_DIR="${PMX_ESP_DIR}/${kver}"
-			KERNEL_LIVE_DIR="${esp}/${KERNEL_ESP_DIR}"
-			mkdir -p "${KERNEL_LIVE_DIR}"
-			cp --preserve=timestamps "${linux_image}" "${KERNEL_LIVE_DIR}/"
-			cp --preserve=timestamps "${initrd}" "${KERNEL_LIVE_DIR}/"
-
-			# create loader entry
-			cat > "${esp}/loader/entries/proxmox-${kver}.conf" <<- EOF
-				title    ${LOADER_TITLE}
-				version  ${kver}
-				options  ${CMDLINE}
-				linux    /${KERNEL_ESP_DIR}/vmlinuz-${kver}
-				initrd   /${KERNEL_ESP_DIR}/initrd.img-${kver}
-			EOF
-		else
-			warn "	Copying kernel ${kver}"
-			cp --preserve=timestamps "${linux_image}" "${esp}/"
-			cp --preserve=timestamps "${initrd}" "${esp}/"
-		fi
-	done
-
-}
-
-remove_old_kernels_efi() {
-	esp="$1"
-
-	for kerneldir in "${esp}/${PMX_ESP_DIR}"/*; do
-		if [ ! -d "${kerneldir}" ]; then
-			warn "	${kerneldir} is not a directory - skipping"
-			continue
-		fi
-
-		kver="$(echo "${kerneldir}" | sed -r "s#^${esp}/${PMX_ESP_DIR}/(.+)\$#\\1#")"
-
-		echo "${BOOT_KVERS}" | grep -q "${kver}" && continue;
-		warn "	Removing old version ${kver}"
-		rm -rf "${kerneldir}"
-		rm -f "${esp}/loader/entries/proxmox-${kver}.conf"
+		warn "	Copying kernel and creating boot-entry for ${kver}"
+		cp --preserve=timestamps "${linux_image}" "${esp}/"
+		cp --preserve=timestamps "${initrd}" "${esp}/"
+
+		# create loader entry
+		cat > "${esp}/loader/entries/proxmox-${kver}.conf" <<- EOF
+			title    ${LOADER_TITLE}
+			version  ${kver}
+			options  ${CMDLINE}
+			linux    /vmlinuz-${kver}
+			initrd   /initrd.img-${kver}
+		EOF
 	done
 
 }
 
-remove_old_kernels_legacy() {
+remove_old_kernels() {
 	esp="$1"
 
 	for kernel in "${esp}/"vmlinuz-*; do
@@ -185,6 +146,7 @@ remove_old_kernels_legacy() {
 		warn "	Removing old version ${kver}"
 		rm -rf "${esp}/vmlinuz-${kver}"
 		rm -rf "${esp}/initrd.img-${kver}"
+		rm -f "${esp}/loader/entries/proxmox-${kver}.conf"
 	done
 
 }
-- 
2.30.2






More information about the pve-devel mailing list