#!/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 I40E 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 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" < /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"