sbl bringup: stublets, slots, maze, ffu-ref, b10 chain, docs

This commit is contained in:
SashegDev
2026-09-07 13:10:38 +00:00
parent 11facdfb45
commit c7e95b4194
6 changed files with 430 additions and 4 deletions
+114
View File
@@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""sbl_patch.py — reproduce all WIP file patches for SBL1 bring-up.
Usage: ./tools/sbl_patch.py fw/sbl/img0.elf out-dir/
Produces img0_bl.elf, img0_b2..b8.elf (cumulative variants, see STEPS).
Each step is documented with WHY (all WIP, to be replaced by real PBL).
"""
import os
import sys
SEG_OFF, SEG_VA = 0x3000, 0x8005800
BLX2BL = { # blx-imm -> bl (stay Thumb): set bit12 of 2nd halfword
0x802F658: ('d8f7c2ed', 'd8f7c2fd'),
0x802F660: ('d8f702ec', 'd8f702fc'),
}
NOPS = { # call -> NOP NOP (skip unmodellable init/assert; r0/r5 ignored)
0x802F664: 'e4f77efc', # bl walker (result ignored by caller)
0x802F672: 'e6f7bbfa', # bl 0x8015bec (assert-hang)
0x802F678: None, # bl 0x8018a78, see REDIRECT (installer runs!)
0x801B71E: '9847fee7', # blx r3 + b.n self (terminal assert, 4B)
0x8016184: 'fdf790fc', # bl 0x8013aa8 (subtree nopped, see b8)
}
REDIRECT = {
# bl target off-by-N fixes (verified by disasm + QEMU traces):
0x8013AA8: ('07f026be', '07f027be'), # jump-table case0: +2
0x802F678: ('e9f7fef9', 'e9f700fa'), # bl 0x8018a78 -> 0x8018a7c (+4)
}
POOLS = {
# literal pool words redirected to owned scratch (orig struct garbage):
0x801B76C: ('280b0508', '00000708'), # -> 0x08070000
}
def off(va):
return SEG_OFF + (va - SEG_VA)
def hx(d, va, n=4):
return d[off(va):off(va) + n].hex()
def set4(d, va, hexbytes):
d[off(va):off(va) + 4] = bytes.fromhex(hexbytes)
def main():
src, outdir = sys.argv[1], sys.argv[2]
os.makedirs(outdir, exist_ok=True)
base = bytearray(open(src, 'rb').read())
def save(d, name):
p = os.path.join(outdir, name)
open(p, 'wb').write(bytes(d))
print('wrote', p, len(d))
d = bytearray(base)
for va, (a, b) in BLX2BL.items():
assert hx(d, va) == a, (hex(va), hx(d, va))
set4(d, va, b)
save(d, 'img0_bl.elf')
# b2 = bl + walker NOP
o = off(0x802F664)
assert d[o:o + 4].hex() == 'e4f77efc'
d[o:o + 4] = bytes.fromhex('c046c046')
save(d, 'img0_b2.elf')
# b3 = b2 + 0x8015bec NOP
o = off(0x802F672)
assert d[o:o + 4].hex() == 'e6f7bbfa', hx(d, 0x802F672)
d[o:o + 4] = bytes.fromhex('c046c046')
save(d, 'img0_b3.elf')
# b4 = b3 + 0x8018a78 NOP
o = off(0x802F678)
assert d[o:o + 4].hex() == 'e9f7fef9', hx(d, 0x802F678)
d[o:o + 4] = bytes.fromhex('c046c046')
save(d, 'img0_b4.elf')
# b5 = b4 + jump-table +2
o = off(0x8013AA8)
assert d[o:o + 4].hex() == '07f026be'
d[o:o + 4] = bytes.fromhex('07f027be')
save(d, 'img0_b5.elf')
# b6 = b5 + terminal assert NOP (4B)
o = off(0x801B71E)
assert d[o:o + 4].hex() == '9847fee7'
d[o:o + 4] = bytes.fromhex('c046c046')
save(d, 'img0_b6.elf')
# b7 = b6 + redirect bl to installer entry (undoes b4 NOP)
o = off(0x802F678)
assert d[o:o + 4].hex() == 'c046c046'
d[o:o + 4] = bytes.fromhex('e9f700fa')
save(d, 'img0_b7.elf')
# b8 = b7 + subtree NOP + pool redirect
o = off(0x8016184)
assert d[o:o + 4].hex() == 'fdf790fc', hx(d, 0x8016184)
d[o:o + 4] = bytes.fromhex('c046c046')
o = off(0x801B76C)
assert d[o:o + 4].hex() == '280b0508'
d[o:o + 4] = bytes.fromhex('00000708')
save(d, 'img0_b8.elf')
# b9 = b8 + hole-call NOP (EDL-dead padding slide at 0x80068FC)
o = off(0x8008396)
assert d[o:o + 4].hex() == 'fef780f9', hx(d, 0x8008396)
d[o:o + 4] = bytes.fromhex('c046c046')
save(d, 'img0_b9.elf')
# b10 = b9 with installer-bl reverted to NOP (S2 lands mid-NOPs safely,
# falls into the 0x8013b7c call; installer skipped, structs via maze)
o = off(0x802F678)
assert d[o:o + 4].hex() == 'e9f700fa', hx(d, 0x802F678)
d[o:o + 4] = bytes.fromhex('c046c046')
save(d, 'img0_b10.elf')
if __name__ == '__main__':
main()