Add mkimage to build and install the image from the latest signed kernel tag
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
work=$(dirname "$repo")/kernel
|
||||
src=$work/linux
|
||||
fwdir=$work/firmware
|
||||
initdir=$work/initramfs
|
||||
cpiolist=$work/initramfs.list
|
||||
|
||||
upstream=https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
|
||||
esp=/boot
|
||||
subdir=EFI/cabletest
|
||||
loader='\EFI\cabletest\cabletest.efi'
|
||||
label=cabletest
|
||||
|
||||
# Releases are signed by one of these two and nothing else is accepted.
|
||||
keys=(
|
||||
647F28654894E3BD457199BE38DBBDC86092693E
|
||||
ABAF11C65A2970B130ABE3C479BE3E4300411886
|
||||
)
|
||||
|
||||
# Nothing here can be loaded from disk at runtime, so every blob the drivers
|
||||
# ask for is linked into the image. The EDID is ours; the rest come from the
|
||||
# distro's linux-firmware.
|
||||
edid=edid/waveshare-1024x600.bin
|
||||
distrofw=(
|
||||
intel/ice/ddp/ice.pkg
|
||||
i915/adlp_dmc.bin
|
||||
i915/adlp_guc_70.bin
|
||||
i915/tgl_huc.bin
|
||||
)
|
||||
|
||||
cmdline="drm.edid_firmware=HDMI-A-1:$edid video=HDMI-A-1:e"
|
||||
|
||||
# Every setting the appliance depends on, re-asserted after the stored config
|
||||
# is loaded so a renamed or newly defaulted symbol cannot quietly drop one.
|
||||
wanty=(
|
||||
EFI_STUB BLK_DEV_INITRD INITRAMFS_COMPRESSION_NONE CMDLINE_BOOL
|
||||
PACKET INET DEVTMPFS PROC_FS SYSFS TMPFS
|
||||
ICE ICE_HWTS PTP_1588_CLOCK
|
||||
DRM_I915 DRM_FBDEV_EMULATION DRM_LOAD_EDID_FIRMWARE DRM_PANIC
|
||||
FB_DEVICE FRAMEBUFFER_CONSOLE VT_CONSOLE
|
||||
USB_XHCI_PCI USB_HID HID_MULTITOUCH INPUT_EVDEV
|
||||
CPU_FREQ_GOV_PERFORMANCE X86_INTEL_PSTATE
|
||||
)
|
||||
wantn=(MODULES BLOCK I40E IGC)
|
||||
|
||||
say() { printf '\n\033[36m== %s\033[0m\n' "$*"; }
|
||||
die() { printf '\033[31merror: %s\033[0m\n' "$*" >&2; exit 1; }
|
||||
|
||||
say "sudo is needed at the end, asking now so the build runs unattended"
|
||||
sudo -v
|
||||
|
||||
say "kernel source"
|
||||
if [ ! -d "$src/.git" ]; then
|
||||
echo "cloning $upstream (one time, several GB)"
|
||||
git clone "$upstream" "$src"
|
||||
fi
|
||||
git -C "$src" fetch --tags --prune origin
|
||||
# sed rather than head: head closes the pipe early, which under pipefail turns
|
||||
# the upstream SIGPIPE into a failed pipeline.
|
||||
tag=$(git -C "$src" tag -l 'v[0-9]*' --sort=-v:refname | grep -vE -- '-(rc|tree)' | sed -n 1p)
|
||||
[ -n "$tag" ] || die "no release tag found"
|
||||
|
||||
status=$(git -C "$src" verify-tag --raw "$tag" 2>&1) || die "$tag is not signed"
|
||||
signer=""
|
||||
for key in "${keys[@]}"; do
|
||||
case "$status" in *"VALIDSIG $key"*) signer=$key ;; esac
|
||||
done
|
||||
[ -n "$signer" ] || die "$tag is not signed by a pinned kernel.org key"
|
||||
echo "$tag verified against $signer"
|
||||
|
||||
git -C "$src" checkout -q --detach "$tag"
|
||||
|
||||
say "go binary"
|
||||
mkdir -p "$initdir"
|
||||
( cd "$repo" && CGO_ENABLED=0 go build -trimpath -o "$initdir/init" . )
|
||||
go version -m "$initdir/init" | grep -E 'vcs\.(revision|modified)' ||
|
||||
die "no VCS stamp; build from a git checkout so the image is traceable"
|
||||
|
||||
say "firmware"
|
||||
mkdir -p "$fwdir/$(dirname "$edid")"
|
||||
cp "$repo/kernel/$edid" "$fwdir/$edid"
|
||||
for f in "${distrofw[@]}"; do
|
||||
mkdir -p "$fwdir/$(dirname "$f")"
|
||||
if [ -e "/lib/firmware/$f" ]; then
|
||||
cp "/lib/firmware/$f" "$fwdir/$f"
|
||||
elif [ -e "/lib/firmware/$f.zst" ]; then
|
||||
zstd -qdf -o "$fwdir/$f" "/lib/firmware/$f.zst"
|
||||
else
|
||||
die "/lib/firmware/$f is missing; install linux-firmware"
|
||||
fi
|
||||
done
|
||||
|
||||
# The binary is embedded by the kernel link, so it has to exist before make.
|
||||
# /dev/console must be in the cpio: the kernel opens it for init's stdio before
|
||||
# anything has had a chance to mount devtmpfs over /dev.
|
||||
say "initramfs"
|
||||
cat > "$cpiolist" <<EOF
|
||||
dir /dev 0755 0 0
|
||||
nod /dev/console 0600 0 0 c 5 1
|
||||
dir /proc 0755 0 0
|
||||
dir /sys 0755 0 0
|
||||
file /init $initdir/init 0755 0 0
|
||||
EOF
|
||||
cat "$cpiolist"
|
||||
|
||||
say "configure"
|
||||
cp "$repo/kernel/config" "$src/.config"
|
||||
( cd "$src" && scripts/config \
|
||||
--disable MODULES \
|
||||
--enable EXPERT --disable BLOCK \
|
||||
--disable I40E --disable IGC \
|
||||
--enable DRM_LOAD_EDID_FIRMWARE \
|
||||
--set-str EXTRA_FIRMWARE "$edid ${distrofw[*]}" \
|
||||
--set-str EXTRA_FIRMWARE_DIR "$fwdir" \
|
||||
--set-str INITRAMFS_SOURCE "$cpiolist" \
|
||||
--disable INITRAMFS_COMPRESSION_GZIP --enable INITRAMFS_COMPRESSION_NONE \
|
||||
--enable CMDLINE_BOOL --set-str CMDLINE "$cmdline" \
|
||||
--disable DEBUG_INFO_DWARF5 --enable DEBUG_INFO_NONE \
|
||||
--disable LOCALVERSION_AUTO --set-str LOCALVERSION "-cabletest" )
|
||||
make -C "$src" olddefconfig
|
||||
|
||||
for s in "${wanty[@]}"; do
|
||||
grep -qx "CONFIG_$s=y" "$src/.config" || die "CONFIG_$s is not y after olddefconfig"
|
||||
done
|
||||
for s in "${wantn[@]}"; do
|
||||
grep -qx "# CONFIG_$s is not set" "$src/.config" || die "CONFIG_$s survived olddefconfig"
|
||||
done
|
||||
echo "${#wanty[@]} required and ${#wantn[@]} forbidden symbols check out"
|
||||
|
||||
say "build $tag"
|
||||
make -C "$src" -j"$(nproc)"
|
||||
|
||||
say "package"
|
||||
image=$src/arch/x86/boot/bzImage
|
||||
cpio -itv < "$src/usr/initramfs_data.cpio"
|
||||
[ -z "$(find "$src" -name '*.ko' -print -quit)" ] || die "modules were built"
|
||||
ls -l "$image"
|
||||
|
||||
say "install"
|
||||
[ "$(findmnt -no FSTYPE "$esp")" = vfat ] || die "$esp is not a mounted ESP"
|
||||
espdev=$(findmnt -no SOURCE "$esp")
|
||||
disk=/dev/$(lsblk -no PKNAME "$espdev")
|
||||
part=$(cat "/sys/class/block/$(basename "$espdev")/partition")
|
||||
|
||||
sudo mkdir -p "$esp/$subdir"
|
||||
sudo cp "$image" "$esp/$subdir/cabletest.efi"
|
||||
sync
|
||||
sudo cmp "$image" "$esp/$subdir/cabletest.efi"
|
||||
|
||||
bootnum=$(efibootmgr | awk -v l="$label" '$1 ~ /^Boot[0-9A-Fa-f]{4}/ && $2 == l {print substr($1, 5, 4)}')
|
||||
if [ -z "$bootnum" ]; then
|
||||
# A new entry is prepended to BootOrder, which would silently take over the
|
||||
# default boot, so the previous order is put back with ours on the end.
|
||||
order=$(efibootmgr | sed -n 's/^BootOrder: //p')
|
||||
sudo efibootmgr --create --disk "$disk" --part "$part" \
|
||||
--loader "$loader" --label "$label" > /dev/null
|
||||
bootnum=$(efibootmgr | awk -v l="$label" '$1 ~ /^Boot[0-9A-Fa-f]{4}/ && $2 == l {print substr($1, 5, 4)}')
|
||||
sudo efibootmgr -o "${order:+$order,}$bootnum" > /dev/null
|
||||
fi
|
||||
sudo efibootmgr -n "$bootnum" > /dev/null
|
||||
efibootmgr
|
||||
|
||||
say "$tag installed as Boot$bootnum, armed for the next reboot only"
|
||||
Reference in New Issue
Block a user