simulation: tripwire + PC-bucketed diff + bitflip sweep
Ship the new simulation & verification stack under simulation/:
- mmio_regions.py — address → region classifier (DDRCTL, DDRPHY,
OTP, SRAM, …). Shared by every other tool so trace output is
scannable without memorising the memory map.
- sim_tripwire.py — Bin-style per-access capture. Records
(seq, insn_tick, pc, addr, size, rw, val, region, fn_name) per
MMIO access. PCResolver bisects the vendor funs table parsed
from ddr_conservative_asm.s.
- tripwire_diff.py — PC-bucketed difflib.SequenceMatcher diff of
two tripwire CSVs. Buckets by fn_name so bitflip-induced control
flow divergence doesn't cascade noise.
- training_sim.py — DDR training simulator with --mode pass and
--mode bitflip (flip first N reads per training status, exercise
retry paths). BITFLIP_ONLY env var narrows to a single addr for
the sweep.
- bitflip_sweep.py — Flip each of 23 training-status addresses
one-at-a-time and tabulate retry convergence. Surfaces which
function(s) react to a transient fault by writing different
downstream register values.
Plus:
- mmio_diff.py updated: region-tagged divergence output,
--show-regions histogram, --tripwire-out-{vendor,rebuilt} CSV
capture, --capture-stack-writes for stack-allocated buffer diffs.
- debug_probes/tp_slot_{probe,writes}.py — ad-hoc Unicorn probes
for chasing a single-slot divergence in an SRAM buffer. Kept as
reference examples of how to extend the tripwire toolchain.
The stack found 6 silicon-hostile bugs in the rebuilt blob that
mmio_diff's write-sequence gate was structurally blind to, including
three ld-unresolved-symbol NULL derefs (case-mismatched externs,
missing DATA_SYMS) and one C-early-return-skips-shared-tail bug
where vendor's asm fell through to the tail via `b` after a `ret`.
This commit is contained in:
@@ -14,8 +14,27 @@ n## Prerequisites
|
||||
|
||||
|
||||
|
||||
Decompilation, analysis, and patching of the closed-source Rockchip RK3588
|
||||
DDR initialization binary blobs.
|
||||
Decompilation, analysis, patching, and **pre-silicon simulation** of the
|
||||
closed-source Rockchip RK3588 DDR initialization binary blobs.
|
||||
|
||||
The project has three layers:
|
||||
1. **Static RE** — Ghidra-exported decompiled C + disassembly +
|
||||
annotated register map (`ddr_annotated.c`, `rk3588_ddr.h`).
|
||||
2. **Patch + flash** — `patch_prod.py` rewrites specific poll loops
|
||||
in the vendor blob to work around known hangs. Validated under
|
||||
Unicorn via `blob_emu.py` before flash.
|
||||
3. **Matching-decomp rebuild + simulation** — the goal is a buildable
|
||||
working DDR blob (not bit-identical reproduction). Per-function C
|
||||
ports are spliced into the vendor blob; `mmio_diff.py` gates
|
||||
behavioral equivalence by MMIO write sequence. The `simulation/`
|
||||
subdir adds read-side tripwire capture, PC-bucketed diff, and
|
||||
per-address bitflip fault injection for retry-path validation.
|
||||
|
||||
> "Markus' insistence on simulation before flashing paid off. Big
|
||||
> time. Again." — 2026-04-21. Tripwire + PC-bucket diff caught three
|
||||
> silent NULL-derefs hidden behind `mmio_diff=3173/3173` green.
|
||||
> `ld --unresolved-symbols=ignore-all` had zeroed undefined
|
||||
> DATA_SYMS externs; silicon would have bricked.
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -73,8 +92,26 @@ gcc -O2 -o ddr_emu ddr_emu2.c -lunicorn -lm
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `ddr_emu2.c` | Unicorn-based C emulator with MMIO stubs |
|
||||
| `blob_emu.py` | Python Unicorn harness — runs a blob, stubs MMIO, captures UART TX |
|
||||
| `mmio_diff.py` | Runs vendor + rebuilt, diffs MMIO write sequences; region-tagged output |
|
||||
| Ghidra project | On oppenheimer (CT131): `/opt/work/ghidra_project/` |
|
||||
|
||||
### Simulation & Verification Stack (`simulation/`)
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `simulation/mmio_regions.py` | Address → region classifier (`DDRCTL`, `DDRPHY`, `OTP`, `SRAM`, …) |
|
||||
| `simulation/sim_tripwire.py` | Bin-style per-access capture with PC → fn name resolver |
|
||||
| `simulation/tripwire_diff.py` | PC-bucketed SequenceMatcher diff of two tripwire CSVs |
|
||||
| `simulation/training_sim.py` | DDR-training simulator: `pass` and `bitflip-first-pass` modes |
|
||||
| `simulation/bitflip_sweep.py` | Flip each training-status addr one-at-a-time, report retry convergence |
|
||||
| `simulation/README.md` | Synopsis + usage for the above |
|
||||
|
||||
### Debug Probes (`debug_probes/`)
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `debug_probes/tp_slot_probe.py` | Snapshot the `tp` timing buffer at fn_5540's read site |
|
||||
| `debug_probes/tp_slot_writes.py` | List every write to a specific `tp` slot, both vendor and rebuilt |
|
||||
|
||||
### Ghidra Export Scripts
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
|
||||
Reference in New Issue
Block a user