1 Commits

Author SHA1 Message Date
marfrit 694be88964 v3 patcher: full-body trampolines + site bisection subsets
Root cause of counted_v2 brick identified:

v2 copied only ONE non-load body instruction into each trampoline (picks
the first after the LDR). For poll patterns of form

    LDR   Wx, [Xbase, #off]
    AND   Wx, Wx, #mask     ; no flag update
    CMP   Wx, #expected     ; sets flags
    B.cond .retry

— 9 of the 16 sites in v1.19 have this shape — the final CMP was silently
dropped. The trampoline's B.inv_cond tested whatever flags happened to be
set before entry, producing effectively random branch decisions once
under the trampoline. Result: boot crashes before the UART banner,
observed as 'power LED off' brick.

Fix in v3: copy the ENTIRE loop body (LDR + all intermediate instructions,
in original order) into each trampoline. Size is now 4*(N+6) where N is
body length (28 bytes for body=2, 36 for body=3).

Also in v3:
- --sites subset flag for bisection (all/early/mid/late/none/index list)
- decode_sites.py helper that tries to identify which MMIO register each
  site polls (best effort — the materialized_base scanner is naive and
  picks up stale MOVZ targets, but cluster grouping by blob offset is
  reliable and sufficient for bisection)

Site clusters in v1.19:
  0..7   early (0x07b78..0x07f08): SGRF + PHY firmware state machine
  8..10  mid   (0x09124..0x0aaf8): DfiStatus / training start
  11..15 late  (0x0d154..0x0d378): UctWriteProt / CalBusy / late

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 01:06:51 +02:00