b38: S21 table-walker router
This commit is contained in:
@@ -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
@@ -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
@@ -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). */
|
||||||
|
|||||||
@@ -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
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user