Align every FIT sub-image to 0x800, and check it

mkimage -p only places the FIRST payload. The rest are packed contiguously, and
U-Boot reads each by dividing its data-position by the 512-byte block size with a
truncating divide -- so a payload that is not block-aligned is read from the
wrong offset. Measured: without -B this script emitted the kernel at 0x9A94,
data-position % 512 = 148, which is exactly the failing shape.

That failure is on record. flare-edge 9387cff (2026-09-01) hit it on a boot_b
FIT: "unaligned sub-images fail the RESC loader's sha256 and the logo silently
falls back to 'No resource file'". It landed on -B 0x200, inferred from noticing
the proven image was "512-aligned" without checking for a larger factor.

The proven images are aligned to 0x800, not merely to 512. Measured on the pair
that boots this board today: boot.img fdt/kernel/resource at 0x800 / 0x12800 /
0x3A7800, recovery.img at 0x800 / 0x12800 / 0x3F8800 -- every one a multiple of
2048. So 0x800 satisfies everything 0x200 does, since every 0x800 multiple is a
0x200 multiple, and additionally reproduces the vendor layout exactly. The cost
is at most 2 KiB of padding. Where a remembered rule and a booting image
disagree, match the image.

The alignment is now also asserted at build time rather than trusted. It runs on
every build because the failure it catches is silent -- a wrong offset does not
fail the build, it fails on a panel, and only sometimes visibly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T2D2KtdgwbhbF6Mo64eUrn
This commit is contained in:
Noah
2026-09-04 16:16:33 -06:00
co-authored by Claude Opus 5
parent 3d8a683d68
commit 054790dde6
+35 -2
View File
@@ -130,8 +130,41 @@ cat > "$WORKDIR/boot.its" <<'ITS'
};
ITS
echo "== FIT (external data, -E -p 0x800)"
( cd "$WORKDIR" && mkimage -f boot.its -E -p 0x800 boot.img >/dev/null )
# - SUB-IMAGE ALIGNMENT (`-B 0x800`). `-p` only places the FIRST payload; the
# rest are packed contiguously, and U-Boot reads each one by dividing its
# data-position by the 512-byte block size with a TRUNCATING divide. A
# payload that is not block-aligned is therefore read from the wrong offset:
# the RESC loader's sha256 fails and logo.bmp silently does not load
# (observed 2026-09-01, flare-edge 9387cff).
#
# MEASURED, both directions. Without -B, this script produced kernel at
# 0x9A94 (data-position % 512 = 148) -- misaligned, exactly the failing
# shape. The vendor images that actually boot this board are aligned to
# 0x800, not merely to 512: boot.img has fdt/kernel/resource at 0x800,
# 0x12800, 0x3A7800 and recovery.img at 0x800, 0x12800, 0x3F8800 -- every
# one a multiple of 2048.
#
# 9387cff recorded `-B 0x200` from that failure. It is right but weaker than
# it needed to be: it was inferred from noticing the proven image was
# "512-aligned" without checking for a larger factor. 0x800 satisfies
# everything 0x200 does (every 0x800 multiple is a 0x200 multiple) and
# additionally reproduces the vendor layout exactly, for at most 2 KiB of
# padding. When the two disagree, match the image that is known to boot.
echo "== FIT (external data, -E -p 0x800 -B 0x800)"
( cd "$WORKDIR" && mkimage -f boot.its -E -p 0x800 -B 0x800 boot.img >/dev/null )
# Every payload must land on a 0x800 boundary. This is the check that would have
# caught the unaligned build before it reached a panel, so it runs on every
# build rather than living in a separate tool nobody remembers to invoke.
for _n in fdt kernel resource; do
_pos="$(fdtget -t u "$WORKDIR/boot.img" "/images/$_n" data-position 2>/dev/null || true)"
[ -n "$_pos" ] || continue
if [ $(( _pos % 2048 )) -ne 0 ]; then
echo "FATAL: /images/$_n data-position $_pos is not 0x800-aligned;" >&2
echo " U-Boot's block divide would read it from the wrong offset" >&2
exit 1
fi
done
# 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