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