aboutsummarylogtreecommitdiffstats
diff options
context:
space:
mode:
authord10n2022-02-09 11:46:23 -0500
committerd10n2022-02-09 18:17:45 -0500
commit1b97fb4256a9449452ba86da7f5d14824c62acb6 (patch)
tree4fb91cc4a5866d2a413a77e85e8ad146cfa94e7d
downloadaur-1b97fb4256a9449452ba86da7f5d14824c62acb6.tar.gz
Create repository
-rw-r--r--.SRCINFO17
-rw-r--r--.gitignore6
-rw-r--r--90-unified-kernel-image-uefi-ucode.hook11
-rw-r--r--PKGBUILD24
-rw-r--r--README.md32
-rw-r--r--unified-kernel-image-backup.service14
-rw-r--r--unified-kernel-image-backup.sh122
-rw-r--r--unified-kernel-image-hooks.install11
8 files changed, 237 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..8c7c51e9b75b
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,17 @@
+pkgbase = unified-kernel-image-hooks
+ pkgdesc = Unified kernel image UEFI hooks: save the currently-booted efi image as a backup entry
+ pkgver = 1.0.0
+ pkgrel = 1
+ url = https://github.com/d10n/arch-unified-kernel-image-hooks
+ install = unified-kernel-image-hooks.install
+ arch = x86_64
+ license = GPL
+ depends = binutils
+ source = 90-unified-kernel-image-uefi-ucode.hook
+ source = unified-kernel-image-backup.service
+ source = unified-kernel-image-backup.sh
+ sha256sums = 6aa273c83faf1d15664bb2c39950ffdab0c540f5ace5dd58e531f9a9de515c54
+ sha256sums = c90ff05c0fb9629f09b1ab7bd672ff2a88dc6a3e6a474ac1c6d82096431c477b
+ sha256sums = 1d68aad096c55357e574291fe93c2c2be6bcd3e493edd4ea15da0c12ce0f0f38
+
+pkgname = unified-kernel-image-hooks
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..7d5c9c83be0b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+pkg/
+src/
+*.tar.zst
+*.tar.xz
+*.tar.gz
+
diff --git a/90-unified-kernel-image-uefi-ucode.hook b/90-unified-kernel-image-uefi-ucode.hook
new file mode 100644
index 000000000000..c7c77189e05a
--- /dev/null
+++ b/90-unified-kernel-image-uefi-ucode.hook
@@ -0,0 +1,11 @@
+[Trigger]
+Operation = Install
+Operation = Upgrade
+Type = Path
+Target = boot/*-ucode.img
+
+[Action]
+Description = Updating linux initcpios for microcode in unified uefi...
+When = PostTransaction
+Exec = /usr/share/libalpm/scripts/mkinitcpio-install
+NeedsTargets
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..6c13efe07188
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,24 @@
+# Maintainer: d10n <david at bitinvert dot com>
+pkgname=unified-kernel-image-hooks
+pkgver=1.0.0
+pkgrel=1
+pkgdesc="Unified kernel image UEFI hooks: save the currently-booted efi image as a backup entry"
+arch=(x86_64)
+url="https://github.com/d10n/arch-unified-kernel-image-hooks"
+license=('GPL')
+depends=(binutils)
+source=(
+ 90-unified-kernel-image-uefi-ucode.hook
+ unified-kernel-image-backup.service
+ unified-kernel-image-backup.sh
+ )
+install=unified-kernel-image-hooks.install
+sha256sums=('6aa273c83faf1d15664bb2c39950ffdab0c540f5ace5dd58e531f9a9de515c54'
+ 'c90ff05c0fb9629f09b1ab7bd672ff2a88dc6a3e6a474ac1c6d82096431c477b'
+ '1d68aad096c55357e574291fe93c2c2be6bcd3e493edd4ea15da0c12ce0f0f38')
+
+package() {
+ install -m755 -D unified-kernel-image-backup.sh "$pkgdir/usr/libexec/unified-kernel-image-hooks/unified-kernel-image-backup.sh"
+ install -m644 -D unified-kernel-image-backup.service "$pkgdir/usr/lib/systemd/system/unified-kernel-image-backup.service"
+ install -m644 -D 90-unified-kernel-image-uefi-ucode.hook "$pkgdir/usr/share/libalpm/hooks/90-unified-kernel-image-uefi-ucode.hook"
+}
diff --git a/README.md b/README.md
new file mode 100644
index 000000000000..01e4ca618ccb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+# arch-unified-kernel-image-hooks
+
+* Save a backup copy of the currently-booted unified kernel image UEFI entry
+* Update the unified kernel image when the microcode gets updated
+
+## Notes
+
+* Ensure that your EFI System Partition has enough available space to save an extra copy of each unified kernel image that you boot into.
+* The tool only works on local disks, which is probably what you have. Network EFI images are not backed up.
+* The tool currently supports images generated by mkinitcpio. Pull requests for other initramfs generators welcome.
+
+## Setup
+
+1. [Configure Unified Kernel Image creation](https://wiki.archlinux.org/title/Unified_kernel_image)
+2. Install the package. (`unified-kernel-image-hooks`)
+3. `systemctl enable unified-kernel-image-backup.service`
+4. Add the UEFI boot entry.
+ Examples (change --disk, --part, and --loader as necessary):
+ ```
+ efibootmgr -v --create --disk /dev/sda --part 1 --label 'Arch Linux (last booted kernel)' --loader '\EFI\ARCH\linux-x64-last.efi'
+ ```
+ ```
+ efibootmgr -v --create --disk /dev/nvme0n1 --part 1 --label 'Arch Linux (last booted kernel)' --loader '\EFI\ARCH\linux-x64-last.efi'
+ ```
+5. To create the first backup entry, either reboot, or run:
+ ```
+ /usr/libexec/unified-kernel-image-hooks/unified-kernel-image-backup.sh
+ ```
+
+## License
+
+GPL2
diff --git a/unified-kernel-image-backup.service b/unified-kernel-image-backup.service
new file mode 100644
index 000000000000..b2d18927534c
--- /dev/null
+++ b/unified-kernel-image-backup.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Save a backup of the currently-booted unified kernel image
+DefaultDependencies=no
+Requires=boot-complete.target
+After=local-fs.target boot-complete.target
+Conflicts=shutdown.target
+Before=shutdown.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/libexec/unified-kernel-image-hooks/unified-kernel-image-backup.sh
+
+[Install]
+WantedBy=basic.target
diff --git a/unified-kernel-image-backup.sh b/unified-kernel-image-backup.sh
new file mode 100644
index 000000000000..1cbcb2e7495d
--- /dev/null
+++ b/unified-kernel-image-backup.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+set -eu
+
+# unified-kernel-image-backup.sh
+# Saves a backup copy of the currently-booted unified kernel image
+# Depends on binutils
+
+# Limitations:
+# * The EFI partition must be mounted
+# * The EFI loader image must not have a ")" character in its path/name
+# * The EFI partition must have enough space to make the backup copy
+
+# Output:
+# * <image-name>-last.efi
+# * <image-name>-last.txt
+
+# Setup:
+# efibootmgr -v --create --disk /dev/sda --part 1 --label 'Arch Linux (last booted kernel)' --loader '\EFI\ARCH\linux-x64-last.efi'
+# -or-
+# efibootmgr -v --create --disk /dev/nvme0n1 --part 1 --label 'Arch Linux (last booted kernel)' --loader '\EFI\ARCH\linux-x64-last.efi'
+
+# 1. Find the currently-booted efi image
+# 2. Determine if it is an Arch unified kernel image
+# 3. Determine if it is already saved
+# 4. Save a copy of the currently-booted image
+
+
+# Example efibootmgr output:
+#BootCurrent: 0002
+#Timeout: 1 seconds
+#BootOrder: 0002,0000,0001,0004,0003
+#Boot0000* Arch Linux Grub HD(1,GPT,00000000-0000-4000-0000-000000000000,0x1000,0x1ff800)/File(\EFI\ARCH\grubx64.efi)
+#Boot0001* Linux Recovery HD(1,GPT,00000000-0000-4000-0000-000000000000,0x1000,0x1ff800)/File(\EFI\LinuxRecovery\grubx64.efi)
+#Boot0002* Arch Linux HD(1,GPT,00000000-0000-4000-0000-000000000000,0x1000,0x1ff800)/File(\EFI\ARCH\linux-x64.efi)
+#Boot0003* Arch Linux (last booted kernel) HD(1,GPT,00000000-0000-4000-0000-000000000000,0x1000,0x1ff800)/File(\EFI\ARCH\linux-x64-last.efi)
+#Boot0004* Windows Boot Manager HD(1,GPT,22222222-2222-4222-2222-222222222222,0x800,0x32000)/File(\EFI\MICROSOFT\BOOT\BOOTMGFW.EFI)WINDOWS.........x...B.C.D.O.B.J.E.C.T.=.{.9.d.e.a.8.6.2.c.-.5.c.d.d.-.4.e.7.0.-.a.c.c.1.-.f.3.2.b.3.4.4.d.4.7.9.5.}....................
+#Boot0010 Setup FvFile(33333333-3333-4333-3333-333333333333)
+#Boot0011 Boot Menu FvFile(55555555-5555-4555-5555-555555555555)
+
+# @see: UEFI Spec, version 2.9, 10.6.1.6 Text Device Node Reference
+
+# Assuming efibootmgr output is stable
+efibootmgr -v |
+ awk '
+ # Identify the current boot entry
+ /^BootCurrent:/ { bc = $2 }
+
+ # Get partition and file path information from the current boot entry
+ $1 ~ "^Boot" bc {
+ # The tab character separates the entry id/name from the device path.
+ # There may be tabs in the device path, so use sub() instead of $2 and FS="\t"
+ sub("^[^\t]*\t", "");
+ print $0;
+
+ # UEFI only supports GPT, so this pattern should be safe enough
+ guid_idx = match($0, "GPT,........-....-....-....-............");
+ if (!guid_idx) { exit 1; }
+
+ # Extract the EFI partition GUID from the device node
+ guid = substr($0, guid_idx + 4, RLENGTH - 4); # 4: length of "GPT,"
+ print guid;
+
+ # Extract the path to the EFI image
+ file_idx = match($0, "\\)/File\\([^)]*");
+ if (!file_idx) { exit 1; }
+
+ # Fix path separator for Linux
+ gsub("\\\\", "/");
+
+ print substr($0, file_idx + 7, RLENGTH - 7); # 7: length of ")/File("
+ }
+ ' |
+(
+IFS= read -r boot_entry_full
+printf '%s\n' "Found current boot entry: $boot_entry_full"
+IFS= read -r efi_partuuid
+IFS= read -r efi_bin
+
+# findmnt -P is safe to eval. This sets the variable TARGET
+eval "$(findmnt -P -o TARGET "/dev/disk/by-partuuid/$efi_partuuid")"
+
+case "$efi_bin" in
+ *-last.*)
+ if [ -e "${TARGET}${efi_bin%.*}.txt" ]; then
+ echo 'Probably booting a saved UEFI Unified Kernel Image; not saving last boot image'
+ exit 0
+ fi
+ ;;
+esac
+
+if ! objcopy -O binary --only-section .osrel "${TARGET}${efi_bin}" /dev/stdout | grep -qFx 'NAME="Arch Linux"'; then
+ # FIXME: does this work with the dracut-generated images?
+ echo 'Probably not a UEFI Unified Kernel Image; not saving last boot image'
+ exit 0
+fi
+
+efi_bin_save="${TARGET}${efi_bin%.*}-last.${efi_bin##*.}"
+efi_bin_save_txt="${efi_bin_save%.*}.txt"
+boot_uname_current="$(uname -r)"
+if [ -e "$efi_bin_save_txt" ]; then
+ boot_uname_saved="$(cat "$efi_bin_save_txt")"
+ if [ "$boot_uname_saved" = "$boot_uname_current" ]; then
+ echo 'UEFI Unified Kernel Image already saved'
+ exit 0
+ fi
+fi
+
+# FUTURE: save multiple versions and clean up old versions with a timer/hook?
+#efi_bin_save="${TARGET}${efi_bin%.*}-$(uname -r).${efi_bin##*.}"
+#if [ -e "$efi_bin_save" ]; then
+# exit 0;
+#fi
+
+echo 'Saving UEFI Unified Kernel Image'
+cp -av -- "${TARGET}${efi_bin}" "$efi_bin_save"
+printf '%s\n' "$boot_uname_current" >"$efi_bin_save_txt"
+)
+
+echo 'Done'
+
+#objcopy -O binary --only-section .osrel /boot/efi/EFI/arch/linux-x64.efi /dev/stdout
diff --git a/unified-kernel-image-hooks.install b/unified-kernel-image-hooks.install
new file mode 100644
index 000000000000..6895d2fb4b27
--- /dev/null
+++ b/unified-kernel-image-hooks.install
@@ -0,0 +1,11 @@
+## arg 1: the new package version
+post_install() {
+ cat <<'EOF'
+1. Enable the service:
+ systemctl enable unified-kernel-image-backup.service
+2. Add the UEFI entry:
+ (example command; replace --disk, --part, --label, and --loader as required):
+ efibootmgr -v --create --disk /dev/sda --part 1 --label 'Arch Linux (last booted kernel)' --loader '\EFI\ARCH\linux-x64-last.efi'
+3. Reboot to create the entry, or run /usr/libexec/unified-kernel-image-hooks/unified-kernel-image-backup.sh
+EOF
+}