b38: S21 table-walker router

This commit is contained in:
lumia-emu
2026-09-14 00:34:52 +00:00
parent d3e2efe7ba
commit 8aef555346
5 changed files with 169 additions and 6 deletions
+12
View File
@@ -190,6 +190,18 @@
`[sp+0x2C]` валиден → исходный pop; иначе r0=sl + re-run `[sp+0x2C]` валиден → исходный pop; иначе r0=sl + re-run
(идемпотентная математика). Эпилог `pop.w` (4B) → `b.w S20`. (идемпотентная математика). Эпилог `pop.w` (4B) → `b.w S20`.
## b38: S21 table-walker router (2026-09-13)
- Голый table-walker (`0x8007916`, mid-входы без пушей) снимает
`pop.w 0x28`, читает saved-FP (`0x85FFEB0`) как pc → ARM fill-дрейф
(STM-clobbers!). S21 (32B @0x08006D5A): `[sp+0x24]` валиден →
исходный pop; иначе `b.w S19`. Эпилог `pop.w` (4B) → `b.w S21`.
## b37: S20 clock-dispatcher router (2026-09-13)
- Голый clock-диспетчер (`0x800EB80`, без пушей) снимает `pop.w 0x30`
за проход → марш sp к верху IMEM. S20 (34B @0x08006D38):
`[sp+0x2C]` валиден → исходный pop; иначе r0=sl + re-run
(идемпотентная математика). Эпилог `pop.w` (4B) → `b.w S20`.
## maze v2 (2026-09-13) ## maze v2 (2026-09-13)
- Maze с чётным lr уходил в ARM-дрейф (STM-clobbers + IMEM fault). - Maze с чётным lr уходил в ARM-дрейф (STM-clobbers + IMEM fault).
Maze v2 (24B): возврат только при odd Thumb lr из DDR, иначе hang Maze v2 (24B): возврат только при odd Thumb lr из DDR, иначе hang
+1 -1
View File
@@ -5,7 +5,7 @@
set -e set -e
cd "$(dirname "$0")/.." cd "$(dirname "$0")/.."
QEMU=~/qemu-src/qemu-8.2.2/build/qemu-system-arm QEMU=~/qemu-src/qemu-8.2.2/build/qemu-system-arm
B=${1:-b37} B=${1:-b38}
IMG=fw/img/emmc-real.img IMG=fw/img/emmc-real.img
if [ ! -f "$IMG" ]; then if [ ! -f "$IMG" ]; then
echo "no $IMG — сначала: python3 tools/ffu_extract.py fw/dl/RM1127_059X5R5_orig.ffu --emmc-user fw/img/user-real.bin" echo "no $IMG — сначала: python3 tools/ffu_extract.py fw/dl/RM1127_059X5R5_orig.ffu --emmc-user fw/img/user-real.bin"
+22 -4
View File
@@ -104,15 +104,15 @@ static void saimaa_tmr_init(Object *obj)
/* Stubs region handle for set_readonly after scaffold implant. */ /* Stubs region handle for set_readonly after scaffold implant. */
static MemoryRegion *saimaa_stubs_mr; static MemoryRegion *saimaa_stubs_mr;
/* DDRLOW stub trap [0x08006B80,0x08006D60): serves the scaffolded bytes /* DDRLOW stub trap [0x08006B80,0x08006D80): serves the scaffolded bytes
* (S/maze/S6/banner/S7/S9/S10/S16/S17/S18/S20 stubs) on read/fetch, * (S/maze/S6/banner/S7/S9/S10/S16/S17/S18/S20/S21 stubs) on read/fetch,
* ignores SBL heap-clobber writes. Uni parity: deferred-restore guard * ignores SBL heap-clobber writes. Uni parity: deferred-restore guard
* in sbl_uni.py (wider: [0x080068C0,0x08006D60), also covers PBL stub). * in sbl_uni.py (wider: [0x080068C0,0x08006D80), also covers PBL stub).
* Snapshot is taken AFTER ELF load + all stub writes (readback). * Snapshot is taken AFTER ELF load + all stub writes (readback).
* PBL stub [0x080068C0,0x080068F4) and the ELF-text gap below stay plain * PBL stub [0x080068C0,0x080068F4) and the ELF-text gap below stay plain
* RAM: PBL runs once (if at all), gap holds real hot SBL code. */ * RAM: PBL runs once (if at all), gap holds real hot SBL code. */
#define SAIMAA_DSTUB_BASE 0x08006B80 #define SAIMAA_DSTUB_BASE 0x08006B80
#define SAIMAA_DSTUB_SIZE 0x000001E0 #define SAIMAA_DSTUB_SIZE 0x00000200
static uint8_t saimaa_dstub_mem[SAIMAA_DSTUB_SIZE]; static uint8_t saimaa_dstub_mem[SAIMAA_DSTUB_SIZE];
static uint64_t saimaa_dstub_read(void *opaque, hwaddr off, unsigned size) static uint64_t saimaa_dstub_read(void *opaque, hwaddr off, unsigned size)
@@ -698,6 +698,24 @@ static void saimaa_machine_init(MachineState *machine)
cpu_physical_memory_write(0x08006D22 + k, &word, 4); cpu_physical_memory_write(0x08006D22 + k, &word, 4);
} }
} }
/* S21 stublet at 0x08006D5A (32B, b38): table-walker router.
* [sp+0x24] valid-code? => original pop.w (legit return);
* else b.w S19 (sbl_main post-logger restart). */
{
static const uint8_t s21[] = {
0x09, 0x9b, 0x13, 0xf0, 0x01, 0x0f, 0x09, 0xd0,
0x1a, 0x0e, 0x08, 0x2a, 0x01, 0xd1, 0xbd, 0xe8,
0xf0, 0x9f, 0x1a, 0x0f, 0x08, 0x2a, 0x01, 0xd1,
0xbd, 0xe8, 0xf0, 0x9f, 0xff, 0xf7, 0xd9, 0xbf,
};
size_t k;
for (k = 0; k < sizeof(s21); k += 4) {
uint32_t word = 0;
size_t n = sizeof(s21) - k < 4 ? sizeof(s21) - k : 4;
__builtin_memcpy(&word, &s21[k], n);
cpu_physical_memory_write(0x08006D5A + k, &word, 4);
}
}
/* S20 stublet at 0x08006D38 (34B, b37): clock-dispatcher /* S20 stublet at 0x08006D38 (34B, b37): clock-dispatcher
* router. [sp+0x2C] valid-code? => original pop.w (legit); * router. [sp+0x2C] valid-code? => original pop.w (legit);
* else r0=sl + b.w dispatcher re-run (idempotent math). */ * else r0=sl + b.w dispatcher re-run (idempotent math). */
+127
View File
@@ -2171,6 +2171,7 @@ def main():
save(d, 'img0_b36.elf') save(d, 'img0_b36.elf')
# b37 = b36 + S20 clock-dispatcher router (0x800EB96 pop.w -> b.w): # b37 = b36 + S20 clock-dispatcher router (0x800EB96 pop.w -> b.w):
# naked dispatcher (no pushes!) pops 0x30/pass, marching sp to IMEM # naked dispatcher (no pushes!) pops 0x30/pass, marching sp to IMEM
# top. S20 (34B @0x08006D38, scaffold): [sp+0x2C] valid-code? # top. S20 (34B @0x08006D38, scaffold): [sp+0x2C] valid-code?
@@ -2294,6 +2295,132 @@ def main():
save(d, 'img0_b37.elf') save(d, 'img0_b37.elf')
# b38 = b37 + S21 table-walker router (0x8007916 pop.w -> b.w S21):
# naked table-walker (mid-entries, no pushes!) pops 0x28, reading
# saved-FP (0x85FFEB0) as pc -> ARM fill-drift (STM-clobbers!).
# S21 (32B @0x08006D5A, scaffold): [sp+0x24] valid-code? original
# pop.w (legit); else b.w S19 (sbl_main restart, bounded).
d = bytearray(base)
for va, (a, b) in BLX2BL.items():
set4(d, va, b)
for va, exp, new in [
(0x802F664, 'e4f77efc', 'c046c046'),
(0x802F672, 'e6f7bbfa', 'c046c046'),
(0x802F678, 'e9f7fef9', 'c046c046'),
(0x801B71E, '9847fee7', 'c046c046'),
(0x8008396, 'fef780f9', 'c046c046'),
(0x8016184, 'fdf790fc', 'c046c046'),
(0x801B76C, '280b0508', '00000708'),
(0x8017AFC, 'bde8fc87', 'eef74fb8'),
(0x802F690, '9847fee7', 'c046c046'),
(0x801671C, '9847fee7', 'c046c046'),
(0x8013BAC, 'f8bd0a4a', 'f3f730b8'),
(0x801B6BE, 'bde8f081', 'ebf7c3ba'),
(0x8016720, '10bd0000', 'f0f7b2ba'),
(0x8034810, 'bde8fc87', 'd2f76eba'),
(0x8007798, 'bde8f08f', 'fff7c3ba'),
(0x8016334, 'f0f7a4ff', 'c046c046'),
(0x8016342, 'f0f79eef', 'f0f79dbf'),
(0x802F9A0, 'ffe70648', 'd7f7c4b9'),
(0x802F9B2, 'fee78817', 'd7f7bbb9'),
(0x802F9A2, 'c4b943f2', 'd7f7c3b9'),
(0x800EB96, 'bde8fe8f', 'f8f7cfb8'),
(0x8007916, 'bde8f09f', 'fff720ba'),
]:
assert hx(d, va) == exp, (hex(va), hx(d, va))
set4(d, va, new)
# Full bl idiom at 0x8006682 (bl + pop, 6B) -> NOPs (see b18).
o = off(0x8006682)
assert d[o:o + 6].hex() == '00f001f807bd', hx(d, 0x8006682, 6)
d[o:o + 6] = bytes.fromhex('c046c046c046')
o = off(0x8013AA8)
assert d[o:o + 4].hex() == '07f026be', hx(d, 0x8013AA8)
d[o:o + 4] = bytes.fromhex('c046c046')
o = off(0x8013BA6)
assert d[o:o + 2].hex() == 'b888', (hex(0x8013BA6), hx(d, 0x8013BA6, 2))
d[o:o + 2] = bytes.fromhex('ff20')
# Helper-pop S16 chain (see b25).
o = off(0x8007B66)
assert d[o:o + 2].hex() == '10bd', hx(d, 0x8007B66, 2)
d[o:o + 2] = bytes.fromhex('6047')
# Clock S11 (see b24).
o = off(0x800E988)
assert d[o:o + 2].hex() == '10bd', hx(d, 0x800E988, 2)
d[o:o + 2] = bytes.fromhex('7047')
# Poll re-init skip (see b27).
o = off(0x8007748)
assert d[o:o + 2].hex() == '96b1', hx(d, 0x8007748, 2)
d[o:o + 2] = bytes.fromhex('14e0')
# Poll-epilogue add NOP (see b28).
o = off(0x8007794)
assert d[o:o + 2].hex() == '07b0', hx(d, 0x8007794, 2)
d[o:o + 2] = bytes.fromhex('c046')
# Partition wrap-check (see b33).
o = off(0x801844E)
assert d[o:o + 2].hex() == '04d3', hx(d, 0x801844E, 2)
d[o:o + 2] = bytes.fromhex('04e0')
# Hang-site neutralize (see b34).
o = off(0x8018458)
assert d[o:o + 2].hex() == 'fee7', hx(d, 0x8018458, 2)
d[o:o + 2] = bytes.fromhex('ffe7')
save(d, 'img0_b38.elf')
+7 -1
View File
@@ -431,6 +431,12 @@ def main():
# S18 stublet (10B @0x08006D22, b29): poll-epilogue router. # S18 stublet (10B @0x08006D22, b29): poll-epilogue router.
# movw/movt ip + bx ip to sbl_main 0x802f6a9 (post-dispatcher). # movw/movt ip + bx ip to sbl_main 0x802f6a9 (post-dispatcher).
mu.mem_write(0x08006D22, bytes.fromhex("4ff2a96cc0f6020c6047")) mu.mem_write(0x08006D22, bytes.fromhex("4ff2a96cc0f6020c6047"))
# S21 stublet (32B @0x08006D5A, b38): table-walker router.
# [sp+0x24] valid-code? => original pop.w (legit return);
# else b.w S19 (sbl_main post-logger restart, bounded table work).
mu.mem_write(0x08006D5A, bytes.fromhex(
"099b13f0010f09d01a0e082a01d1bde8f09f1a0f082a"
"01d1bde8f09ffff7d9bf"))
# S20 stublet (34B @0x08006D38, b37): clock-dispatcher router. # S20 stublet (34B @0x08006D38, b37): clock-dispatcher router.
# [sp+0x2C] valid-code? => original pop.w (legit return); # [sp+0x2C] valid-code? => original pop.w (legit return);
# else r0=sl (PBL tables) + b.w dispatcher re-run (idempotent math). # else r0=sl (PBL tables) + b.w dispatcher re-run (idempotent math).
@@ -524,7 +530,7 @@ def main():
# --- end parity --- # --- end parity ---
# stub range is readonly on HW/QEMU: ignore SBL heap-clobber writes, # stub range is readonly on HW/QEMU: ignore SBL heap-clobber writes,
# keep maze/stublets intact (restore-on-write with reentrancy guard) # keep maze/stublets intact (restore-on-write with reentrancy guard)
STUB_LO, STUB_HI = 0x080068C0, 0x08006D60 # +S7/S9/S10/S16/S17/S18/S20 STUB_LO, STUB_HI = 0x080068C0, 0x08006D80 # +S7/S9/S10/S16/S17/S18/S20/S21
stub_snap = bytes(mu.mem_read(STUB_LO, STUB_HI - STUB_LO)) stub_snap = bytes(mu.mem_read(STUB_LO, STUB_HI - STUB_LO))
_inww = [False] _inww = [False]
_swn = [0] _swn = [0]