Add linux-aarch64 kernel compatibility shim (#222)
* Add linux-aarch64-pkgbase-shim
Arch Linux ARM's kernel packages install the kernel as /boot/Image and ship
no usr/lib/modules/<ver>/{pkgbase,vmlinuz}, which is how mkinitcpio and
limine-entry-tool find kernels. One pacman hook, ordered 85- so it runs
before 90-mkinitcpio-install, writes both files into every package-owned
modules directory that lacks pkgbase; the usual hook then builds the UKI and
writes the Limine entry. It also covers kernels already present when the
shim itself is installed, cleans up the leftover directories of removed
kernels, and never touches a directory that has pkgbase, so it retires by
removal once archlinuxarm/PKGBUILDs#2215 (or its successor) lands.
Added to the aarch64 workflow's ISO package set.
* linux-aarch64-pkgbase-shim: leave the rebuild to limine-update when the 90 hook is masked
omarchy-iso's installer points 90-mkinitcpio-install.hook at /dev/null in
the target during the chroot phase and runs limine-update itself afterwards.
When the shim is installed in that phase it writes pkgbase and vmlinuz and
would otherwise start a UKI build that finalize_limine_boot throws away.
* linux-aarch64-pkgbase-shim: pkgrel 2
The aarch64 repo build only rebuilds packages whose version moved, so the
previous script fix never reached the repository.
* Trim aarch64 kernel shim comments
* Refresh shim kernel images safely on reinstall
* Run package regression suites in existing CI
* Cover shim ownership and failed-copy handling
* Handle shared kernel-directory ownership in the ARM boot shim
* Limit the CI change to the package test scripts
* Warn when a kernel directory's pkgbase names another package
---------
Co-authored-by: Jimmy Van Veen <jimmy.van.veen@gmail.com>
Co-authored-by: Jim Martin <jimmartin@gmail.com>
This commit is contained in:
6 files changed
+323
No files matched your search
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"source": "local"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Run before mkinitcpio and Limine discover installed kernels.
|
||||
[Trigger]
|
||||
Type = Path
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Operation = Remove
|
||||
Target = usr/lib/modules/*/
|
||||
|
||||
[Trigger]
|
||||
Type = Package
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Target = linux-aarch64-pkgbase-shim
|
||||
|
||||
[Action]
|
||||
Description = Writing pkgbase and vmlinuz for Arch Linux ARM kernels...
|
||||
When = PostTransaction
|
||||
Exec = /usr/share/libalpm/scripts/linux-aarch64-pkgbase-shim
|
||||
NeedsTargets
|
||||
@@ -0,0 +1,26 @@
|
||||
# Maintainer: Jimmy Van Veen
|
||||
|
||||
# Add kernel metadata required by mkinitcpio and Limine on Arch Linux ARM.
|
||||
|
||||
pkgname=linux-aarch64-pkgbase-shim
|
||||
pkgver=1
|
||||
pkgrel=4
|
||||
pkgdesc="Writes usr/lib/modules/<ver>/{pkgbase,vmlinuz} for Arch Linux ARM kernels so mkinitcpio and Limine hooks find them"
|
||||
arch=('aarch64')
|
||||
url="https://github.com/omacom/omarchy-pkgs"
|
||||
license=('MIT')
|
||||
depends=('bash' 'diffutils' 'pacman')
|
||||
optdepends=('limine-mkinitcpio-hook: rebuild the UKI and Limine entry when the shim is installed after the kernel')
|
||||
options=('!debug')
|
||||
source=(
|
||||
'85-linux-aarch64-pkgbase-shim.hook'
|
||||
'linux-aarch64-pkgbase-shim'
|
||||
'README.package.md'
|
||||
)
|
||||
sha256sums=('SKIP' 'SKIP' 'SKIP')
|
||||
|
||||
package() {
|
||||
install -Dm644 85-linux-aarch64-pkgbase-shim.hook "${pkgdir}/usr/share/libalpm/hooks/85-linux-aarch64-pkgbase-shim.hook"
|
||||
install -Dm755 linux-aarch64-pkgbase-shim "${pkgdir}/usr/share/libalpm/scripts/linux-aarch64-pkgbase-shim"
|
||||
install -Dm644 README.package.md "${pkgdir}/usr/share/doc/${pkgname}/README.md"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# linux-aarch64-pkgbase-shim
|
||||
|
||||
Arch Linux ARM installs its kernel as `/boot/Image` instead of
|
||||
`usr/lib/modules/<ver>/vmlinuz`. Limine discovers the kernel through
|
||||
`modules.builtin`, but needs `vmlinuz` beside it to build a boot entry.
|
||||
|
||||
This package is one pacman hook. After a kernel package is installed or
|
||||
upgraded (`usr/lib/modules/*/`), and when the shim itself is installed, it
|
||||
writes into each package-owned modules directory without native kernel metadata:
|
||||
|
||||
- `pkgbase`: compatibility metadata naming the package that owns the directory
|
||||
- `vmlinuz`: a copy of `/boot/Image` (the owner must own that too)
|
||||
|
||||
Reinstalling a kernel refreshes the shim's copy when the image changes, even
|
||||
if the module-directory version is unchanged. Package-owned files are preserved.
|
||||
When the kernel and its headers share ownership of the module directory, the
|
||||
shim uses the owner of `/boot/Image`, after confirming that it also owns the
|
||||
directory. Headers-package ownership alone does not qualify a directory.
|
||||
|
||||
It runs as `85-`, before `90-mkinitcpio-install`, so the usual hook then builds
|
||||
the initramfs/UKI and the Limine entry. If that hook would not run in the same
|
||||
transaction (the shim installed after the kernel, or a kernel package that
|
||||
does not touch `usr/lib/initcpio/`), the script runs
|
||||
`limine-mkinitcpio-install` itself. Leftover directories of removed kernels
|
||||
that hold nothing but these two files are cleaned up.
|
||||
|
||||
## Retirement
|
||||
|
||||
Delete this package when `linux-aarch64` ships `vmlinuz` in its kernel module
|
||||
directory. Package-owned metadata is never modified, so both approaches can coexist
|
||||
during the transition.
|
||||
@@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
# Supply pkgbase and vmlinuz metadata missing from Arch Linux ARM kernels.
|
||||
set -uo pipefail
|
||||
|
||||
readonly SELF=linux-aarch64-pkgbase-shim
|
||||
readonly ROOT=${OMARCHY_KERNEL_SHIM_ROOT:-}
|
||||
readonly IMAGE=$ROOT/boot/Image
|
||||
readonly LIMINE_INSTALL_SCRIPT=$ROOT/usr/share/libalpm/scripts/limine-mkinitcpio-install
|
||||
|
||||
declare -A DIRS=()
|
||||
modules_in_transaction=0
|
||||
self_in_transaction=0
|
||||
rebuild=0
|
||||
failed=0
|
||||
|
||||
owner_of() {
|
||||
pacman -Qqo "${1#"$ROOT"}" 2>/dev/null
|
||||
}
|
||||
|
||||
# NeedsTargets requires consuming every line from stdin.
|
||||
while IFS= read -r line; do
|
||||
case $line in
|
||||
usr/lib/modules/*)
|
||||
v=${line#usr/lib/modules/}
|
||||
v=${v%%/*}
|
||||
[[ -n $v ]] && DIRS["$ROOT/usr/lib/modules/$v"]=1
|
||||
modules_in_transaction=1
|
||||
;;
|
||||
"$SELF")
|
||||
self_in_transaction=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Cover kernels already present when the shim itself is installed.
|
||||
if ((self_in_transaction)); then
|
||||
for d in "$ROOT"/usr/lib/modules/*/; do
|
||||
[[ -d $d ]] && DIRS["${d%/}"]=1
|
||||
done
|
||||
fi
|
||||
|
||||
for dir in "${!DIRS[@]}"; do
|
||||
[[ -d $dir ]] || continue
|
||||
# Not a packaged kernel (a leftover or DKMS-only directory).
|
||||
owners=$(owner_of "$dir") || continue
|
||||
owner=$(owner_of "$IMAGE") || continue
|
||||
# The kernel and its headers can both own the directory. Use the image's
|
||||
# single owner, provided it is also one of the directory's owners.
|
||||
[[ -n $owner && $owner != *$'\n'* ]] || continue
|
||||
if ! printf '%s\n' "$owners" | grep -Fx -- "$owner" >/dev/null; then
|
||||
echo "$SELF: $owner owns $IMAGE but not $dir, leaving it alone" >&2
|
||||
continue
|
||||
fi
|
||||
# Preserve package-owned files; refresh metadata previously written by the shim.
|
||||
owner_of "$dir/pkgbase" >/dev/null && continue
|
||||
owner_of "$dir/vmlinuz" >/dev/null && continue
|
||||
if [[ -e $dir/pkgbase && $(<"$dir/pkgbase") != "$owner" ]]; then
|
||||
echo "$SELF: $dir/pkgbase does not name $owner, leaving $dir alone" >&2
|
||||
continue
|
||||
fi
|
||||
if [[ -f $dir/pkgbase ]] && cmp -s "$IMAGE" "$dir/vmlinuz"; then
|
||||
continue
|
||||
fi
|
||||
image_tmp=$(mktemp "$dir/.vmlinuz.XXXXXX") || { failed=1; continue; }
|
||||
if ! cp --preserve=mode "$IMAGE" "$image_tmp" || ! mv -f "$image_tmp" "$dir/vmlinuz"; then
|
||||
echo "$SELF: failed to copy $IMAGE to $dir/vmlinuz" >&2
|
||||
rm -f "$image_tmp"
|
||||
failed=1
|
||||
continue
|
||||
fi
|
||||
if ! printf '%s\n' "$owner" >"$dir/pkgbase"; then
|
||||
failed=1
|
||||
continue
|
||||
fi
|
||||
echo "$SELF: wrote pkgbase ($owner) and vmlinuz in $dir"
|
||||
# Rebuild when the transaction will not trigger mkinitcpio itself.
|
||||
if ! ((modules_in_transaction)) || ! pacman -Qlq "$owner" 2>/dev/null | grep '^/usr/lib/initcpio/' >/dev/null; then
|
||||
rebuild=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove directories containing only stale shim metadata.
|
||||
for dir in "$ROOT"/usr/lib/modules/*/; do
|
||||
dir=${dir%/}
|
||||
[[ -f $dir/pkgbase && -f $dir/vmlinuz ]] || continue
|
||||
owner_of "$dir" >/dev/null && continue
|
||||
owner_of "$dir/pkgbase" >/dev/null && continue
|
||||
owner_of "$dir/vmlinuz" >/dev/null && continue
|
||||
[[ -z $(find "$dir" -mindepth 1 ! -name pkgbase ! -name vmlinuz -print -quit) ]] || continue
|
||||
rm -f "$dir/pkgbase" "$dir/vmlinuz" && rmdir "$dir" && echo "$SELF: removed leftover $dir"
|
||||
done
|
||||
|
||||
# Respect the installer's deferred boot-image build.
|
||||
deferred_hook=$ROOT/etc/pacman.d/hooks/90-mkinitcpio-install.hook
|
||||
if ((rebuild)) && [[ -L $deferred_hook && $(readlink "$deferred_hook") == /dev/null ]]; then
|
||||
echo "$SELF: $deferred_hook is masked, leaving the rebuild to limine-update"
|
||||
rebuild=0
|
||||
fi
|
||||
|
||||
if ((rebuild)); then
|
||||
if [[ -x $LIMINE_INSTALL_SCRIPT ]]; then
|
||||
echo rebuild | "$LIMINE_INSTALL_SCRIPT" || failed=1
|
||||
else
|
||||
echo "$SELF: $LIMINE_INSTALL_SCRIPT not found; run mkinitcpio for the new kernel yourself" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
exit "$failed"
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
package_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
scratch=$(mktemp -d)
|
||||
trap 'rm -rf "$scratch"' EXIT
|
||||
export OMARCHY_KERNEL_SHIM_ROOT=$scratch
|
||||
export SHIM_NATIVE=0 SHIM_KERNEL_PRESENT=1
|
||||
export SHIM_IMAGE_OWNER=linux-aarch64
|
||||
export SHIM_DIR_OWNERS=linux-aarch64
|
||||
|
||||
pacman() {
|
||||
if [[ $1 == -Qlq ]]; then
|
||||
printf '/usr/lib/initcpio/install/test\n'
|
||||
return 0
|
||||
fi
|
||||
case $2 in
|
||||
/boot/Image)
|
||||
printf '%s\n' "$SHIM_IMAGE_OWNER"
|
||||
;;
|
||||
/usr/lib/modules/test)
|
||||
((SHIM_KERNEL_PRESENT)) || return 1
|
||||
printf '%s\n' "$SHIM_DIR_OWNERS"
|
||||
;;
|
||||
/usr/lib/modules/test/pkgbase | /usr/lib/modules/test/vmlinuz)
|
||||
[[ $SHIM_NATIVE == 1 || $2 == /usr/lib/modules/test/"$SHIM_NATIVE" ]] || return 1
|
||||
printf 'linux-aarch64\n'
|
||||
;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
export -f pacman
|
||||
|
||||
modules=$scratch/usr/lib/modules/test
|
||||
mkdir -p "$modules" "$scratch/boot" "$scratch/etc/pacman.d/hooks" \
|
||||
"$scratch/usr/share/libalpm/scripts"
|
||||
printf 'first-kernel' >"$scratch/boot/Image"
|
||||
cat >"$scratch/usr/share/libalpm/scripts/limine-mkinitcpio-install" <<'SCRIPT'
|
||||
#!/bin/bash
|
||||
cat >>"$OMARCHY_KERNEL_SHIM_ROOT/rebuilds"
|
||||
SCRIPT
|
||||
chmod +x "$scratch/usr/share/libalpm/scripts/limine-mkinitcpio-install"
|
||||
|
||||
run_shim() {
|
||||
printf '%s\n' "$1" | bash "$package_dir/linux-aarch64-pkgbase-shim"
|
||||
}
|
||||
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ $(<"$modules/pkgbase") == linux-aarch64 ]]
|
||||
cmp "$scratch/boot/Image" "$modules/vmlinuz"
|
||||
[[ $(stat -c %a "$modules/vmlinuz") == $(stat -c %a "$scratch/boot/Image") ]]
|
||||
[[ ! -e $scratch/rebuilds ]]
|
||||
echo 'ok - kernel installation supplies metadata before the normal rebuild hook'
|
||||
|
||||
for SHIM_DIR_OWNERS in $'linux-aarch64\nlinux-aarch64-headers' \
|
||||
$'linux-aarch64-headers\nlinux-aarch64'; do
|
||||
rm "$modules/pkgbase" "$modules/vmlinuz"
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ $(<"$modules/pkgbase") == linux-aarch64 ]]
|
||||
cmp "$scratch/boot/Image" "$modules/vmlinuz"
|
||||
done
|
||||
echo 'ok - shared kernel and headers directories use the image owner in either order'
|
||||
SHIM_DIR_OWNERS=linux-aarch64
|
||||
|
||||
printf 'replacement-kernel' >"$scratch/boot/Image"
|
||||
run_shim usr/lib/modules/test/
|
||||
cmp "$scratch/boot/Image" "$modules/vmlinuz"
|
||||
echo 'ok - reinstalling the same kernel version refreshes its image'
|
||||
|
||||
printf 'shim-upgrade' >"$scratch/boot/Image"
|
||||
run_shim linux-aarch64-pkgbase-shim
|
||||
[[ $(<"$scratch/rebuilds") == rebuild ]]
|
||||
run_shim linux-aarch64-pkgbase-shim
|
||||
[[ $(wc -l <"$scratch/rebuilds") == 1 ]]
|
||||
echo 'ok - unchanged images do not trigger redundant rebuilds'
|
||||
|
||||
ln -s /dev/null "$scratch/etc/pacman.d/hooks/90-mkinitcpio-install.hook"
|
||||
printf 'deferred-kernel' >"$scratch/boot/Image"
|
||||
run_shim linux-aarch64-pkgbase-shim
|
||||
cmp "$scratch/boot/Image" "$modules/vmlinuz"
|
||||
[[ $(wc -l <"$scratch/rebuilds") == 1 ]]
|
||||
echo 'ok - the installer can defer boot-image regeneration'
|
||||
|
||||
for SHIM_NATIVE in pkgbase vmlinuz; do
|
||||
printf 'package-owned' >"$modules/vmlinuz"
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ $(<"$modules/vmlinuz") == package-owned ]]
|
||||
done
|
||||
echo 'ok - either package-owned metadata file prevents replacement'
|
||||
|
||||
SHIM_NATIVE=0
|
||||
SHIM_IMAGE_OWNER=another-kernel
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ $(<"$modules/vmlinuz") == package-owned ]]
|
||||
SHIM_IMAGE_OWNER=linux-aarch64
|
||||
echo 'ok - a different kernel image owner prevents replacement'
|
||||
|
||||
SHIM_DIR_OWNERS=linux-aarch64-headers
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ $(<"$modules/vmlinuz") == package-owned ]]
|
||||
SHIM_DIR_OWNERS=$'linux-aarch64\nlinux-aarch64-headers'
|
||||
SHIM_IMAGE_OWNER=$'linux-aarch64\nlinux-aarch64-headers'
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ $(<"$modules/vmlinuz") == package-owned ]]
|
||||
SHIM_DIR_OWNERS=linux-aarch64
|
||||
SHIM_IMAGE_OWNER=linux-aarch64
|
||||
echo 'ok - headers-only directories and ambiguous image ownership prevent replacement'
|
||||
|
||||
printf 'another-kernel\n' >"$modules/pkgbase"
|
||||
run_shim usr/lib/modules/test/ 2>"$scratch/warning"
|
||||
[[ $(<"$modules/vmlinuz") == package-owned ]]
|
||||
grep -Fq 'pkgbase does not name linux-aarch64' "$scratch/warning"
|
||||
printf 'linux-aarch64\n' >"$modules/pkgbase"
|
||||
echo 'ok - a pkgbase naming another package is reported and preserved'
|
||||
|
||||
(
|
||||
# shellcheck disable=SC2329 # Invoked by the shim in a child shell.
|
||||
cp() { return 1; }
|
||||
export -f cp
|
||||
if run_shim usr/lib/modules/test/; then
|
||||
echo 'not ok - a failed image copy was accepted' >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ $(<"$modules/vmlinuz") == package-owned ]]
|
||||
)
|
||||
echo 'ok - failed copies preserve the previous kernel image'
|
||||
|
||||
SHIM_KERNEL_PRESENT=0
|
||||
mkdir -p "$modules/updates/dkms"
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ -d $modules/updates/dkms && -f $modules/vmlinuz ]]
|
||||
rmdir "$modules/updates/dkms" "$modules/updates"
|
||||
echo 'ok - kernel removal preserves DKMS leftovers'
|
||||
run_shim usr/lib/modules/test/
|
||||
[[ ! -d $modules ]]
|
||||
echo 'ok - kernel removal cleans up leftover shim metadata'
|
||||
Reference in new issue
Block a user