diff --git a/build/mk-bootimg.sh b/build/mk-bootimg.sh new file mode 100755 index 0000000..642150f --- /dev/null +++ b/build/mk-bootimg.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# Package a bootable boot.img from a kernel this SDK built. +# +# build-kernel.sh produces a zImage and a dtb; this turns them into the image +# the board's U-Boot will actually boot, which was the last thing keeping the +# device build tied to the vendor SDK. The format is not negotiable and was +# established the hard way during M2 bring-up (kernel/docs/m2-boot-on-c8a3.md): +# +# - EXTERNAL-DATA FIT (`mkimage -E -p 0x800`). The FDT metadata stays tiny and +# the kernel/fdt/resource payloads are appended after it. An ordinary +# embedded-data FIT is rejected outright: "FIT: No fit blob". +# - A `resource` MULTI SUB-IMAGE IS MANDATORY. Rockchip's U-Boot reads the DTB +# over its RESC: path from a resource image holding `rk-kernel.dtb` (plus +# any boot logos). Without one: "Failed to load DTB, ret=-19". +# - SYSMEM SENTINEL LOAD ADDRESSES: fdt load 0xffffff00, kernel load/entry +# 0xffffff01. These tell U-Boot's sysmem to place the images itself. Real +# low addresses collide and come back as "No fit blob". +# +# The board's U-Boot has CONFIG_FIT_SIGNATURE off, so the image is not signed. +# +# Usage: +# mk-bootimg.sh --kernel zImage --dtb rv1106-warden.dtb --out boot.img +# [--logo FILE] [--logo-kernel FILE] [--logo-recovery FILE] +# [--resource-tool PATH] +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KERNEL=""; DTB=""; OUT=""; RTOOL="" +LOGO=""; LOGO_KERNEL=""; LOGO_RECOVERY="" + +while [ $# -gt 0 ]; do + case "$1" in + --kernel) KERNEL="${2:?}"; shift 2 ;; + --dtb) DTB="${2:?}"; shift 2 ;; + --out) OUT="${2:?}"; shift 2 ;; + --logo) LOGO="${2:?}"; shift 2 ;; + --logo-kernel) LOGO_KERNEL="${2:?}"; shift 2 ;; + --logo-recovery) LOGO_RECOVERY="${2:?}"; shift 2 ;; + --resource-tool) RTOOL="${2:?}"; shift 2 ;; + -h|--help) sed -n '2,25p' "$0"; exit 0 ;; + *) echo "FATAL: unknown argument '$1'" >&2; exit 1 ;; + esac +done + +[ -n "$KERNEL" ] && [ -f "$KERNEL" ] || { echo "FATAL: --kernel: no such file" >&2; exit 1; } +[ -n "$DTB" ] && [ -f "$DTB" ] || { echo "FATAL: --dtb: no such file" >&2; exit 1; } +[ -n "$OUT" ] || { echo "FATAL: --out is required" >&2; exit 1; } +command -v mkimage >/dev/null || { + echo "FATAL: mkimage not on PATH (Debian/Ubuntu: u-boot-tools)" >&2; exit 1; } + +# resource_tool is a Rockchip host tool. It has no free-standing source here, so +# it is taken from the vendor SDK when one is present rather than vendored as a +# binary; --resource-tool overrides. FAILS CLOSED, because a boot.img built +# without a resource image looks fine and does not boot. +if [ -z "$RTOOL" ]; then + for c in \ + "$HERE/../tools/resource_tool" \ + "${WARDEN_VENDOR_SDK:-$HERE/../../../sdk}/sysdrv/tools/pc/toolkits/resource_tool" \ + "$HOME/projects/scada/flare-edge/sdk/sysdrv/tools/pc/toolkits/resource_tool" + do + [ -x "$c" ] && { RTOOL="$c"; break; } + done +fi +[ -n "$RTOOL" ] && [ -x "$RTOOL" ] || { + echo "FATAL: resource_tool not found; pass --resource-tool PATH" >&2; exit 1; } + +WORKDIR="$(mktemp -d)" +trap 'rm -rf "$WORKDIR"' EXIT + +# resource_tool packs files under a root dir by their names, and U-Boot looks +# for the DTB under the fixed name rk-kernel.dtb. +cp "$DTB" "$WORKDIR/rk-kernel.dtb" +RES_FILES=(rk-kernel.dtb) +for pair in "$LOGO:logo.bmp" "$LOGO_KERNEL:logo_kernel.bmp" "$LOGO_RECOVERY:logo_recovery.bmp"; do + src="${pair%%:*}"; dst="${pair##*:}" + [ -n "$src" ] || continue + [ -f "$src" ] || { echo "FATAL: logo '$src' not found" >&2; exit 1; } + cp "$src" "$WORKDIR/$dst" + RES_FILES+=("$dst") +done + +echo "== resource.img (${RES_FILES[*]})" +( cd "$WORKDIR" && "$RTOOL" --pack --root=. --image=resource.img "${RES_FILES[@]}" >/dev/null ) +[ -s "$WORKDIR/resource.img" ] || { echo "FATAL: resource_tool produced nothing" >&2; exit 1; } + +cp "$KERNEL" "$WORKDIR/kernel" +cp "$WORKDIR/resource.img" "$WORKDIR/resource" +cp "$DTB" "$WORKDIR/fdt" + +cat > "$WORKDIR/boot.its" <<'ITS' +/dts-v1/; +/ { + description = "FIT image with Linux kernel, FDT blob and resource"; + images { + fdt { + data = /incbin/("fdt"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + load = <0xffffff00>; + hash { algo = "sha256"; }; + }; + kernel { + data = /incbin/("kernel"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "none"; + entry = <0xffffff01>; + load = <0xffffff01>; + hash { algo = "sha256"; }; + }; + resource { + data = /incbin/("resource"); + type = "multi"; + arch = "arm"; + compression = "none"; + hash { algo = "sha256"; }; + }; + }; + configurations { + default = "conf"; + conf { + rollback-index = <0x0>; + kernel = "kernel"; + fdt = "fdt"; + multi = "resource"; + }; + }; +}; +ITS + +echo "== FIT (external data, -E -p 0x800)" +( cd "$WORKDIR" && mkimage -f boot.its -E -p 0x800 boot.img >/dev/null ) + +# A FIT whose metadata swelled to the size of the whole image is an +# embedded-data build, which this U-Boot rejects. Catch it here rather than on +# a panel that will not come back. +meta="$(od -An -tu4 -j4 -N4 --endian=big "$WORKDIR/boot.img" | tr -d ' ')" +total="$(stat -c %s "$WORKDIR/boot.img")" +if [ "${meta:-0}" -gt 65536 ] || [ "${meta:-0}" -ge "$total" ]; then + echo "FATAL: FIT metadata is ${meta} bytes of a ${total}-byte image: that is an" >&2 + echo " embedded-data FIT and U-Boot will report 'No fit blob'." >&2 + exit 1 +fi + +install -m 0644 "$WORKDIR/boot.img" "$OUT" +echo "boot.img: $OUT ($(stat -c %s "$OUT") bytes, FIT metadata ${meta} bytes)" diff --git a/build/warden_defconfig b/build/warden_defconfig index e0fabac..29b2b1a 100644 --- a/build/warden_defconfig +++ b/build/warden_defconfig @@ -1308,3 +1308,48 @@ CONFIG_DEBUG_UART_PHYS=0xff4c0000 CONFIG_DEBUG_UART_VIRT=0xff4c0000 CONFIG_DEBUG_UART_8250_WORD=y CONFIG_EARLY_PRINTK=y + +# +# WardenOS platform networking. +# +# These were absent, and their absence is not visible until the panel is in +# the field: the kernel boots, the UI runs, and then the mesh never comes up, +# every iptables rule fails to load, and a tagged port carries nothing. The +# shipping 5.10 kernel has all three, so a 6.18 image without them is a +# REGRESSION against what is on the panel today -- caught by diffing the two +# device configs, not by anything that fails at build time. +# +# WireGuard: flared's mesh to FLARE (wg0). Needs the UDP tunnel helper. +CONFIG_WIREGUARD=y +CONFIG_NET_UDP_TUNNEL=y +# VLAN: the MikroTik app configures tagged ports and the panel terminates them. +CONFIG_VLAN_8021Q=y +# Netfilter: S35iptables and router mode. Scoped to what the scripts actually +# use -- filter + nat tables, MASQUERADE, and the state/limit matches -- rather +# than the vendor kernel's full 124-symbol suite. +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_NAT=y +CONFIG_NF_NAT_MASQUERADE=y +CONFIG_NETFILTER_XTABLES=y +# ...which in turn gates on the legacy xtables core, another 6.18 split. +CONFIG_NETFILTER_XTABLES_LEGACY=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_NAT=y +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=y +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +# 6.18 SPLIT THE LEGACY TABLES OUT. IP_NF_FILTER and IP_NF_NAT depend on +# IP_NF_IPTABLES_LEGACY, which did not exist in 5.10 -- so copying the vendor +# kernel's symbol list verbatim yields a kernel where `iptables` has no filter +# or nat table and every rule in S35iptables fails. Our userspace drives legacy +# iptables, not nft, so this is the table set to enable. +CONFIG_IP_NF_IPTABLES_LEGACY=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_MANGLE=y