sbl bringup: stublets, slots, maze, ffu-ref, b10 chain, docs
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
"""edp_carve.py — точная нарезка ELF из Emergency Payload (.edp) по program headers.
|
||||
Использование: ./tools/edp_carve.py fw/dl/edp-archorg-1127.edp out-dir/
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def elf_span(d, off):
|
||||
assert d[off:off + 4] == b"\x7fELF", "not ELF"
|
||||
entry = struct.unpack("<I", d[off + 24:off + 28])[0]
|
||||
phoff = struct.unpack("<I", d[off + 28:off + 32])[0]
|
||||
phnum = struct.unpack("<H", d[off + 44:off + 46])[0]
|
||||
end = 0
|
||||
segs = []
|
||||
for i in range(phnum):
|
||||
p = off + phoff + i * 32
|
||||
ptype, poff, pv, pp, pfsz, pmsz, flg, al = struct.unpack("<IIIIIIII", d[p:p + 32])
|
||||
if ptype == 1: # PT_LOAD
|
||||
segs.append((pv, pfsz, pmsz, flg))
|
||||
end = max(end, poff + pfsz)
|
||||
return entry, segs, end
|
||||
|
||||
|
||||
def main():
|
||||
src, outdir = sys.argv[1], sys.argv[2]
|
||||
d = open(src, "rb").read()
|
||||
offs = []
|
||||
i = 0
|
||||
while True:
|
||||
i = d.find(b"\x7fELF", i)
|
||||
if i < 0:
|
||||
break
|
||||
offs.append(i)
|
||||
i += 1
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
print(f"{len(offs)} ELFs")
|
||||
for n, o in enumerate(offs):
|
||||
try:
|
||||
entry, segs, end = elf_span(d, o)
|
||||
except Exception as e:
|
||||
print(n, f"off={o} PARSE-FAIL {e}")
|
||||
continue
|
||||
open(f"{outdir}/img{n}.elf", "wb").write(d[o:o + end])
|
||||
mem = sum(s[2] for s in segs)
|
||||
print(f"img{n}: off={o} size={end} entry={entry:#x} mem={mem} "
|
||||
+ " ".join(f"[{v:#x}+{ms:#x}{'X' if fl & 1 else ''}]" for v, fz, ms, fl in segs))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -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()
|
||||
@@ -0,0 +1,65 @@
|
||||
import struct
|
||||
|
||||
M = '/root/qemu-src/qemu-8.2.2/hw/arm/saimaa.c'
|
||||
src = open(M).read()
|
||||
|
||||
start = src.find(' /* Boot scaffolding for SBL1 BringUp')
|
||||
assert start > 0, 'scaffold start not found'
|
||||
end_marker = 'printf("saimaa: SBL1 %s loaded'
|
||||
end = src.find(end_marker, start)
|
||||
assert end > 0, 'scaffold end not found'
|
||||
line_start = src.rfind('\n', 0, end) + 1
|
||||
|
||||
blob = open('/tmp/stubs3.bin', 'rb').read()
|
||||
print('stub blob len', len(blob))
|
||||
c_array = ', '.join('0x%02x' % b for b in blob)
|
||||
|
||||
S10_A = '0x08062001'
|
||||
S2 = '0x08062013'
|
||||
S10_B = '0x08062021'
|
||||
S6_A = '0x08062033'
|
||||
|
||||
new_block = ''' /* Boot scaffolding for SBL1 BringUp (WIP stub-driven PBL):
|
||||
* pop-compensation stublets at 0x08062000 pin sp and route onward,
|
||||
* so repeated pops always hit valid slots. */
|
||||
{
|
||||
static const unsigned char stub_blob[] = { %s };
|
||||
uint32_t magic = 0x00000000; /* IMEM poll spins WHILE equal */
|
||||
uint32_t S = 0x08062100, STUB = 0x08062120;
|
||||
uint32_t w;
|
||||
uint16_t h0 = 0x2000, h1 = 0x4770; /* movs r0,#0; bx lr */
|
||||
size_t k;
|
||||
uint32_t v;
|
||||
for (k = 0; k < sizeof(stub_blob); k += 4) {
|
||||
uint32_t word;
|
||||
__builtin_memcpy(&word, &stub_blob[k], 4);
|
||||
cpu_physical_memory_write(0x08062000 + k, &word, 4);
|
||||
}
|
||||
/* pointer maze in owned RAM for SBL1 struct chains */
|
||||
w = S + 8;
|
||||
cpu_physical_memory_write(S, &w, 4);
|
||||
cpu_physical_memory_write(S + 8, &STUB, 4);
|
||||
cpu_physical_memory_write(STUB, &h0, 2);
|
||||
cpu_physical_memory_write(STUB + 2, &h1, 2);
|
||||
cpu_physical_memory_write(0x087c29d18, &S, 4);
|
||||
cpu_physical_memory_write(0x08050b28, &S, 4);
|
||||
cpu_physical_memory_write(0x08070000, &S, 4);
|
||||
/* pop-site slots -> stublets (sp values from cpu traces) */
|
||||
v = %s; /* S1 pop10 */
|
||||
cpu_physical_memory_write(0x085FFF14, &v, 4);
|
||||
v = %s; /* S2 pop2 */
|
||||
cpu_physical_memory_write(0x085FFF1C, &v, 4);
|
||||
v = %s; /* S3 pop10 */
|
||||
cpu_physical_memory_write(0x085FFF44, &v, 4);
|
||||
cpu_physical_memory_write(0x085FFF7C, &v, 4);
|
||||
v = %s; /* S4 pop6 (stublet chains S5) */
|
||||
cpu_physical_memory_write(0x085FFF34, &v, 4);
|
||||
cpu_physical_memory_write(0x08600944, &magic, 4);
|
||||
printf("saimaa: stub-scaffold live\\n");
|
||||
}
|
||||
{
|
||||
''' % (c_array, S10_A, S2, S10_B, S6_A)
|
||||
|
||||
src = src[:start] + new_block + src[line_start:]
|
||||
open(M, 'w').write(src)
|
||||
print('CANONICAL SCAFFOLD v2 OK')
|
||||
Reference in New Issue
Block a user