Round 18: vectors-before-_start discovered; wrapper-only 4K isolator flash
This commit is contained in:
+23
@@ -711,3 +711,26 @@ contiguous — wfi hang expected) + 8 KiB zero tail padding → total
|
||||
|---|---|
|
||||
| green | total size innocent → the 0x1000 alignment padding/placement is the killer (re-test padding content) |
|
||||
| black | total size (image_size value) alone gates the handoff |
|
||||
|
||||
## Round 18 — total size ruled out; wrapper-only isolator
|
||||
|
||||
R17 (R16 content + 8 KiB tail pad, total 457964 > dead 453432):
|
||||
**green** — total size ruled out. The only remaining structural
|
||||
difference between ran (R12/13/16/17: U-Boot contiguous at 0xB4) and
|
||||
dead (R14/15: U-Boot at 0x1000 behind interior zero pad): the interior
|
||||
pad + shifted placement. Also discovered: the U-Boot binary does NOT
|
||||
start at _start — `arch/arm/cpu/u-boot.lds` places 0x40 bytes of
|
||||
`.vectors` first, so link _start = 0x4C000140 (all prior alignment math
|
||||
shifts by 0x40; the PIE requirement is runtime _start ≡ link _start
|
||||
mod 4K AND start.S's wfi check demands runtime _start ≡ 0 mod 4K, so
|
||||
link _start must be 4K-aligned too).
|
||||
|
||||
### Test B (payload 9485c59e…, flashed, cmp+vbutil OK, body 0x14000)
|
||||
|
||||
4 KiB image: header + wrapper v3 (magenta + 3 blinks + ~5 s hold) +
|
||||
zeros to 0x1000 + NO U-Boot, tail branch patched to self (hang):
|
||||
|
||||
| observation | conclusion |
|
||||
|---|---|
|
||||
| magenta + blinks + hang | interior pad innocent; the trigger is U-Boot content/placement at 0x1000 |
|
||||
| black, nothing | depthcharge rejects the padded image before any execution |
|
||||
|
||||
+27
-14
@@ -4,15 +4,21 @@
|
||||
# 0x0000 64-byte arm64 Image header (code0 = b +0x40, image_size,
|
||||
# flags bit3, magic at 0x38 — booting.rst contract, verified
|
||||
# against depthcharge src/arch/arm/boot64.c)
|
||||
# 0x0040 uboot-wrapper.S (diagnostic: revive display + green fill,
|
||||
# then branch to U-Boot; branch imm26 patched below)
|
||||
# 0x0040+ uboot.bin (u-boot-nodtb.bin + embedded control DTB)
|
||||
# 0x0040 uboot-wrapper.S (diagnostic: revive display + magenta fill +
|
||||
# blink train, then branch to U-Boot; branch imm26 patched)
|
||||
# 0x0040+ uboot.bin (u-boot-nodtb.bin + embedded control DTB),
|
||||
# contiguous — NO interior padding.
|
||||
#
|
||||
# U-Boot's PIE fixup requires the run-vs-link delta to be 4K-aligned:
|
||||
# CONFIG_TEXT_BASE must equal 0x4c000000 + the U-Boot file offset. The
|
||||
# script verifies this against the _start symbol in u-boot.sym.
|
||||
#
|
||||
# then pack with mkdepthcharge (devkeys) and verify.
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
UBOOT_BIN="${UBOOT_BIN:-/home/vhaudiquet/u-boot/u-boot.bin}"
|
||||
UBOOT_SYM="${UBOOT_SYM:-/home/vhaudiquet/u-boot/u-boot.sym}"
|
||||
DTB="${DTB:-krane-sku176.dtb}"
|
||||
WRAP_IMG=krane-uboot.bin
|
||||
OUT_PAYLOAD=krane-uboot-payload.bin
|
||||
@@ -22,30 +28,38 @@ aarch64-linux-gnu-gcc -c uboot-wrapper.S -o uboot-wrapper.o
|
||||
aarch64-linux-gnu-objcopy -O binary uboot-wrapper.o uboot-wrapper.bin
|
||||
WRAP_LEN=$(stat -c %s uboot-wrapper.bin)
|
||||
|
||||
# 2. header + wrapper + u-boot, patch both branches
|
||||
python3 - "$UBOOT_BIN" "$WRAP_IMG" "$WRAP_LEN" <<'EOF'
|
||||
# 2. header + wrapper + u-boot, patch the wrapper's tail branch
|
||||
python3 - "$UBOOT_BIN" "$UBOOT_SYM" "$WRAP_IMG" "$WRAP_LEN" <<'EOF'
|
||||
import struct, sys
|
||||
|
||||
uboot_path, out, wrap_len = sys.argv[1], sys.argv[2], int(sys.argv[3])
|
||||
uboot_path, sym_path, out = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
wrap_len = int(sys.argv[4])
|
||||
uboot = open(uboot_path, 'rb').read()
|
||||
wrapper = open('uboot-wrapper.bin', 'rb').read()
|
||||
assert len(wrapper) == wrap_len
|
||||
|
||||
# wrapper entry at 0x40, U-Boot entry right after the wrapper
|
||||
# wrapper entry at 0x40, U-Boot right after the wrapper (contiguous)
|
||||
wrap_off = 0x40
|
||||
uboot_off = wrap_off + wrap_len
|
||||
total = uboot_off + len(uboot)
|
||||
|
||||
# verify the U-Boot link address matches its runtime placement
|
||||
for line in open(sym_path):
|
||||
parts = line.split()
|
||||
if len(parts) == 3 and parts[2] == '_start':
|
||||
start = int(parts[0], 16)
|
||||
break
|
||||
else:
|
||||
raise SystemExit('_start not found in u-boot.sym')
|
||||
assert start == 0x4c000000 + uboot_off, \
|
||||
"TEXT_BASE/_start 0x%x != expected 0x%x" % (start, 0x4c000000 + uboot_off)
|
||||
|
||||
hdr = bytearray(64)
|
||||
hdr[0:4] = struct.pack('<I', (0x40 >> 2) | 0x14000000) # code0: b +0x40
|
||||
struct.pack_into('<Q', hdr, 0x10, total) # image_size
|
||||
struct.pack_into('<Q', hdr, 0x18, 1 << 3) # flags: bit3
|
||||
# U-Boot requires its runtime _start to be 4K-aligned (start.S checks
|
||||
# `adr _start` & 0xfff and hangs in wfi otherwise; it uses ADRP+ADD with
|
||||
# lo12 relocations during the PIE fixup). depthcharge loads the image at
|
||||
# a 2 MiB-aligned slot, so place U-Boot at the next 4 KiB boundary.
|
||||
uboot_off = (wrap_off + wrap_len + 0xfff) & ~0xfff
|
||||
total = uboot_off + len(uboot)
|
||||
hdr[0x38:0x3c] = b'ARM\x64' # magic
|
||||
|
||||
# patch the wrapper's trailing `b .` to jump to the U-Boot entry
|
||||
br_off = wrap_off + wrap_len - 4
|
||||
imm = (uboot_off - br_off) // 4
|
||||
@@ -55,7 +69,6 @@ wrapper[-4:] = struct.pack('<I', (imm & 0x03ffffff) | 0x14000000)
|
||||
with open(out, 'wb') as f:
|
||||
f.write(hdr)
|
||||
f.write(wrapper)
|
||||
f.write(bytes(uboot_off - wrap_off - wrap_len))
|
||||
f.write(uboot)
|
||||
print("layout: header 64, wrapper %d (0x40..0x%x), uboot %d @0x%x, total %d" %
|
||||
(wrap_len, uboot_off, len(uboot), uboot_off, total))
|
||||
|
||||
+11
-7
@@ -1,16 +1,15 @@
|
||||
/*
|
||||
* krane diagnostic wrapper — runs before U-Boot proper after the
|
||||
* depthcharge handoff (MMU off, caches off, arbitrary 2 MiB-aligned
|
||||
* load slot; position-independent: immediate-encoded addresses only).
|
||||
* depthcharge handoff (MMU off, caches off; position-independent:
|
||||
* immediate-encoded addresses only).
|
||||
*
|
||||
* Purpose: prove that the payload actually executes and revive the
|
||||
* display before U-Boot gets a chance to crash, so a dark screen can be
|
||||
* attributed unambiguously:
|
||||
* - magenta screen + backlight on, then 3 slow blinks = wrapper ran,
|
||||
* U-Boot crashed later (bands from the U-Boot checkpoints narrow
|
||||
* the window further)
|
||||
* - dark screen, no blink train = wrapper never executed
|
||||
* - blink train repeating forever = watchdog reset loop
|
||||
* - magenta screen + backlight on, 3 slow blinks, magenta held ~5 s,
|
||||
* then U-Boot takes over: wrapper ran
|
||||
* - blink train repeating periodically: watchdog reset loop
|
||||
* - dark screen, no blink train: wrapper never executed
|
||||
*
|
||||
* Register sources (all verified on device, see RESEARCH.md rounds 4/10):
|
||||
* OVL0 base 0x14008000: OVL_EN @ +0x000c, OVL0_2L_EN @ +0x100c,
|
||||
@@ -83,6 +82,11 @@ _start:
|
||||
bl delay
|
||||
subs w11, w11, #1
|
||||
b.ne 6b
|
||||
/* hold magenta for ~5 s so the phase cannot be missed */
|
||||
mov w12, #20
|
||||
7: bl delay
|
||||
subs w12, w12, #1
|
||||
b.ne 7b
|
||||
1: b . /* PATCHED: branch to U-Boot entry */
|
||||
|
||||
/* ~250 ms delay using the arch timer */
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user