#!/usr/bin/env bash # Build the FIT image GL.iNet's U-Boot boots from the GL-MT6000's `kernel' # partition (p6, 32 MiB), for one Guix system generation: # kernel-1 the system's Image, LZMA-compressed, loaded at 0x48000000 # fdt-1 mt7986a-glinet-gl-mt6000.dtb with the Guix command line in # /chosen/bootargs-append (GL's U-Boot passes empty bootargs; # linux-mt6000 carries OpenWrt's bootargs-append patch) # initrd-1 the system's initrd # Same layout as OpenWrt's MT6000 FIT (kernel-1, fdt-1, config-1), plus the # ramdisk OpenWrt's initramfs image also carries. # # Usage: scripts/mt6000-fit.sh /gnu/store/...-system OUTPUT.itb set -euo pipefail sys=${1:?usage: $0 SYSTEM OUTPUT.itb} out=$(realpath -m "${2:?usage: $0 SYSTEM OUTPUT.itb}") limit=$((32 * 1024 * 1024)) export PATH=$HOME/.local/bin:$PATH # The package's main output: name-version, no -static/-doc suffix. tool() { guix build "$1" 2>/dev/null | grep -E -- "-$1-[0-9][^-]*\$"; } mkimage=$(tool u-boot-tools)/bin/mkimage dtc=$(tool dtc)/bin fdtput=$dtc/fdtput xz=$(tool xz)/bin/xz params=$(cat "$sys/parameters") # root=LABEL or root=UUID, as Guix's bootloader configurations do. (`guix # system image' gives the image's system its root partition's UUID.) root=$(sed -n 's/.*(root-device (file-system-label "\([^"]*\)")).*/\1/p' <<<"$params") if [ -z "$root" ]; then bytes=$(sed -n 's/.*(root-device (uuid [a-z0-9]* #vu8(\([0-9 ]*\)))).*/\1/p' <<<"$params") [ -n "$bytes" ] || { echo "$0: no label or UUID root in $sys/parameters" >&2; exit 1; } hex=$(printf '%02x' $bytes) root=${hex:0:8}-${hex:8:4}-${hex:12:4}-${hex:16:4}-${hex:20:12} fi kargs=$(sed -n 's/.*(kernel-arguments (\([^)]*\))).*/\1/p' <<<"$params" | tr -d '"') cmdline="root=$root gnu.system=$sys gnu.load=$sys/boot $kargs" kernel=$(readlink -f "$sys/kernel") initrd=$(readlink -f "$sys/initrd") dtb=$kernel/lib/dtbs/mediatek/mt7986a-glinet-gl-mt6000.dtb [ -f "$dtb" ] || { echo "$0: $dtb missing" >&2; exit 1; } work=$(mktemp -d) trap 'rm -rf "$work"' EXIT "$xz" --format=lzma -9 -c "$kernel/Image" > "$work/Image.lzma" cp "$dtb" "$work/board.dtb" chmod u+w "$work/board.dtb" # Leading space: appended to whatever U-Boot passes (nothing, here). "$fdtput" -t s "$work/board.dtb" /chosen bootargs-append " $cmdline" # (Board fixes for GL's firmware and this kernel: in the DTB, from # mt7986a-glinet-gl-mt6000-guix.dtsi.) cp "$initrd" "$work/initrd" cat > "$work/image.its" <; images { kernel-1 { description = "Linux ($(basename "$kernel"))"; data = /incbin/("Image.lzma"); type = "kernel"; arch = "arm64"; os = "linux"; compression = "lzma"; load = <0x48000000>; entry = <0x48000000>; hash-1 { algo = "crc32"; }; hash-2 { algo = "sha1"; }; }; fdt-1 { description = "mt7986a-glinet-gl-mt6000"; data = /incbin/("board.dtb"); type = "flat_dt"; arch = "arm64"; compression = "none"; hash-1 { algo = "crc32"; }; }; initrd-1 { description = "Guix initrd"; data = /incbin/("initrd"); type = "ramdisk"; arch = "arm64"; os = "linux"; compression = "none"; hash-1 { algo = "crc32"; }; }; }; configurations { default = "config-1"; config-1 { description = "$(basename "$sys")"; kernel = "kernel-1"; fdt = "fdt-1"; ramdisk = "initrd-1"; }; }; }; EOF # mkimage runs dtc; /incbin paths are relative to the work directory. (cd "$work" && PATH=$dtc:$PATH "$mkimage" -f image.its "$out" >/dev/null) size=$(stat -c %s "$out") if [ "$size" -gt "$limit" ]; then echo "$0: $out is $size bytes, over the 32 MiB kernel partition" >&2 exit 1 fi echo "$out: $size bytes; command line: $cmdline"