Round 12: U-Boot first boot black — diagnostic wrapper with green fill

This commit is contained in:
vhaudiquet
2026-08-30 09:50:52 +02:00
parent 2e3e33df61
commit 15ff044b33
6 changed files with 135 additions and 26 deletions
+36
View File
@@ -547,3 +547,39 @@ Panel shows the U-Boot banner (white/light-gray text on black, portrait
path or early crash; backlit black = reached handoff but driver probe
failed. The x0-FDT-zeros trap is bypassed: U-Boot uses its embedded DTB
and never reads the handoff FDT.
## Round 12 — first U-Boot boot: pitch black; diagnostic wrapper
Reboot with Round-11 payload `1fc74a0a…`: **pitch black, no backlight**.
Per the Round-11 decision tree the video driver's probe never ran (the
OVL/backlight revival is its first act). So either the image never
executed (but Round 10 proved the handoff path, and only the payload
contents changed) or U-Boot died between entry and the video probe — a
wide window (PIE fixup, relocation, DM scan, and notably `initr_env`
(MMC/clock probe) runs before `stdio_add_devices` in board_r.c, i.e.
before video probe and the banner).
### Localization flash (payload `9955943c…`)
The wrapper itself now carries the life sign, independent of U-Boot:
`uboot-wrapper.S` (linked at +0x40 inside the Image, immediate-encoded
PIC, no relocations) runs before U-Boot proper:
1. OVL revival + backlight (identical writes to the stub's stage0);
2. reads OVL_L0_ADDR, fills the scanout (guarded >= 0x40000000) with
full-screen green (0x8ca000 bytes = 1200*1920*4);
3. branches (imm26 patched at build time) to U-Boot's entry at
+0x40+wrapper_len (116 bytes).
Layout verified by disassembly before flashing: header
(code0 b +0x40, image_size 0x6d9ac, flags bit3, magic), wrapper
instruction sequence, patched tail branch, U-Boot intact at +0xB4.
Payload flashed, cmp + on-device vbutil verify OK.
### Decision tree
| observation | meaning |
|---|---|
| green screen + backlight | wrapper ran; U-Boot crashed before video probe |
| dark, no backlight | wrapper never executed — handoff/boot-path problem with THIS image |
| U-Boot banner | everything works (banner replaces the green) |
+40 -26
View File
@@ -1,53 +1,67 @@
#!/bin/sh
# build-uboot-payload.sh — wrap /home/vhaudiquet/u-boot/u-boot.bin with the
# 64-byte arm64 Image header (same contract as stub.S: depthcharge jumps to
# the first byte of the image, so code0 must branch past the header) and
# pack it into a dev-signed depthcharge FIT for mmcblk0p1.
# build-uboot-payload.sh — build the krane U-Boot payload for mmcblk0p1:
#
# Image header layout (linux/Documentation/arch/arm64/booting.rst, verified
# against depthcharge src/arch/arm/boot64.c):
# 0x00 code0 b +0x40 (branch past header; entry point)
# 0x04 code1 0
# 0x08 text_offset 0 (image sits AT the 2 MiB-aligned base)
# 0x10 image_size header + u-boot.bin size (LE, patched below)
# 0x18 flags bit3 = place anywhere (KASLR slot math)
# 0x20..0x37 reserved 0
# 0x38 magic 0x644d5241 "ARM\x64"
# 0x3c res5 0
# 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)
#
# then pack with mkdepthcharge (devkeys) and verify.
set -e
cd "$(dirname "$0")"
UBOOT_BIN="${UBOOT_BIN:-/home/vhaudiquet/u-boot/u-boot.bin}"
DTB="${DTB:-krane-sku176.dtb}"
OUT_IMG=krane-uboot.bin
WRAP_IMG=krane-uboot.bin
OUT_PAYLOAD=krane-uboot-payload.bin
python3 - "$UBOOT_BIN" "$OUT_IMG" <<'EOF'
# 1. assemble the diagnostic wrapper (raw binary, no relocations)
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'
import struct, sys
src, out = sys.argv[1], sys.argv[2]
uboot = open(src, 'rb').read()
uboot_path, out, wrap_len = sys.argv[1], sys.argv[2], int(sys.argv[3])
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
wrap_off = 0x40
uboot_off = wrap_off + wrap_len
total = uboot_off + len(uboot)
hdr = bytearray(64)
# code0: b .+0x40 => 0x14000000 | (0x40 >> 2)
hdr[0:4] = struct.pack('<I', 0x14000010)
# text_offset = 0 (left as zero)
struct.pack_into('<Q', hdr, 0x10, 64 + len(uboot)) # image_size
struct.pack_into('<Q', hdr, 0x18, 1 << 3) # flags: bit3
hdr[0x38:0x3c] = b'ARM\x64' # magic
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
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
wrapper = bytearray(wrapper)
wrapper[-4:] = struct.pack('<I', (imm & 0x03ffffff) | 0x14000000)
with open(out, 'wb') as f:
f.write(hdr)
f.write(wrapper)
f.write(uboot)
print("wrapped: %d = 64 + %d bytes" % (64 + len(uboot), len(uboot)))
print("layout: header 64, wrapper %d (0x40..0x%x), uboot %d, total %d" %
(wrap_len, uboot_off, len(uboot), total))
EOF
# 3. pack + verify
PYTHONPATH=/root/krane-fb-stub/src/depthcharge-tools python3 -m depthcharge_tools.mkdepthcharge \
-A arm64 \
-o "$OUT_PAYLOAD" \
-n "krane u-boot framebuffer console" \
-d "$OUT_IMG" \
-d "$WRAP_IMG" \
-b "$DTB"
echo "---- verify ----"
Binary file not shown.
BIN
View File
Binary file not shown.
+59
View File
@@ -0,0 +1,59 @@
/*
* 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).
*
* 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:
* - green screen + backlight on = wrapper ran, U-Boot crashed later
* - dark screen, no backlight = 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,
* OVL_L0_ADDR @ +0x0f40 (depthcharge device-era mtk_ddp.c).
* GPIO controller 0x10005000, dout block +0x100, 16 B per 32-pin
* group, set @ +4 (mt8183.h GpioRegs): DISP_PWM = pin 43 (bit 11,
* 0x10005114), EN_LCD_BL = pin 176 (bit 16, 0x10005154).
* Scanout geometry: 1200*1920*4 bpl-based = 0x8ca000 bytes, xRGB.
*/
.text
.globl _start
_start:
/* OVL_EN = 1 */
mov w2, #1
mov w3, #0x800c
movk w3, #0x1400, lsl #16
str w2, [x3]
/* OVL0_2L_EN = 1 */
mov w3, #0x900c
movk w3, #0x1400, lsl #16
str w2, [x3]
/* backlight on: pin 43 (DISP_PWM), dout set 0x10005114, bit 11 */
mov w2, #0x800
mov w3, #0x5114
movk w3, #0x1000, lsl #16
str w2, [x3]
/* backlight on: pin 176 (EN_LCD_BL), dout set 0x10005154, bit 16 */
mov w2, #0x10000
mov w3, #0x5154
movk w3, #0x1000, lsl #16
str w2, [x3]
/* live scanout address: OVL_L0_ADDR = 0x14008f40 */
mov w3, #0x8f40
movk w3, #0x1400, lsl #16
ldr w4, [x3]
/* fill only when the address looks like DRAM (>= 0x40000000) */
mov w5, #0x4000
movk w5, #0x4000, lsl #16
cmp w4, w5
b.lo 1f
/* fill the scanout with green (0x0000ff00): 0x8ca000/4 words */
mov w2, #0xff00
mov x6, #0x2800
movk x6, #0x23, lsl #16
2: str w2, [x4], #4
subs x6, x6, #1
b.ne 2b
1: b . /* PATCHED: branch to U-Boot entry */
BIN
View File
Binary file not shown.