diff options
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/docs/36-GSP-DEVICE-MODEL.md')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/docs/36-GSP-DEVICE-MODEL.md | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/docs/36-GSP-DEVICE-MODEL.md b/debug/risc-v-gsp-rm-vm/docs/36-GSP-DEVICE-MODEL.md new file mode 100644 index 0000000..9516fd5 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/docs/36-GSP-DEVICE-MODEL.md @@ -0,0 +1,175 @@ +# 36 — GSP device model (in development) + +> **Status: in development (2026-10-03, S1 work package).** This page +> documents the `sim/devices/` device model, the versioned +> `sim/profiles/` documents and the real-firmware boot-ladder results. It is +> the companion to `35-GREENEYE-SIMULATOR-DESIGN.md` §3 (Phase S) and +> `06-ACCURACY.md`. Development-only: nothing here authorises GPU hardware, +> kernel modules, mdev, guest access or reboots. +> +> **See also:** `37-SIM-QEMU-LINE.md` (the B0–B2 device model on the frozen +> simulator-vs-QEMU checks) and `40-NEW-VERSION-TRIAGE.md` (one-command triage +> of a new image through this ladder). + +## 1. What this is + +The device model gives the native RV64 core (`sim/machine.py`) real MMIO +semantics for the windows the real GSP firmware touches while booting, so a +bounded run advances **past the QEMU first fault** with evidence instead of +lenient zero-reads. Modeled devices take precedence over the lenient +device-map/unknown fallback; an access inside a modeled window that the +device does not implement is still reported as unknown (never silently +zeroed). Every modeled register carries an **evidence kind**: + +* **header** — a hardware register/field map (offset, width, access type, + field positions, reset/alignment); +* **firmware use** — the disassembled firmware code that reads/writes it; +* **observed access** — the address/width/direction/PC/value sequence seen in + a real run; +* **shim** — reset-time state the real SEC2 booter/host would provide; always + an explicit, session-recorded assumption, never a device claim. + +If a window cannot be proven, none of it is modeled and it is listed as an +unknown (§6). + +## 2. Architecture + +``` +sim/profiles/<name>.json versioned profile: windows, chip id, load layout, + │ DMA aperture windows, boot-shim values + ▼ +sim/devices/__init__.py registry_from_profile(profile, machine) + │ + ├─ base.py DeviceRegistry: range+size decode, access log, + │ JSON state/snapshot, peek() debugger surface + ├─ pmc.py PMC/master block (NV_PMC_BOOT_42 chip ID) + ├─ falcon.py falcon block: IRQ, MAILBOX0/1, DEBUGINFO, DMA, + │ FBIF control/transcfg + ├─ priscv.py RISC-V-local block: IRQ mask, trace, error regs + ├─ timer.py PTIMER (modeled virtual time; opt-in) + ├─ csb.py CSB/TRANSCOM message window seam (B3 landing) + ├─ fwsec.py WPR2 address pair (FWSEC state unmodeled) + ├─ pmu.py PMU stub: observes, never fakes + ├─ dma.py aperture → RAM translation seam (FBGPA/SYSGPA) + └─ irq.py falcon + RISC-V-local IRQ aggregation + ▼ +sim/machine.py Machine(devices=..., translator=..., reset_regs=...) + ▼ +sim/gsp_boot.py bounded real-firmware run + session + rung +``` + +`Machine` consults devices after RAM/UART and before the device map/lenient +fallback; the aperture translator (`dma.py`) is consulted first so +FBGPA/SYSGPA memory accesses resolve to RAM. Overlapping device windows +resolve last-registered-first, and a window that does not model an access +defers to the next matching window (safe fallback), so a narrow overlay can +serve some offsets without hiding the wider device. `Machine.device_state()` +and the `greeneye-sim-devices/1` snapshot expose all device state as +serialisable data (snapshot/restore support is additive and not yet wired to +moments). + +## 3. Modeled inventory + +Offsets are relative to each block base. `RW` semantics are storage unless +noted; every unlisted offset is unhandled and logged. + +| Block | Window(s) (PRIV unless noted) | Modeled registers | Evidence | +|---|---|---|---| +| PMC | `+0x0` (size 0x1000) | `BOOT_42` @0xA00: ARCHITECTURE 28:24, IMPLEMENTATION 23:20, MAJOR 19:16, MINOR 15:12, MINOR_EXT 11:8, CHIP_ID 28:20 (TU104 = 0x164), read-only | header + firmware use + observed (first MMIO) | +| Falcon | `+0x110000`, alias `0x300000000` | `IRQSSET` 0x000 (`irq_status \|=`), `IRQSCLR` 0x004 (`&= ~`), `IRQSTAT` 0x008 (read), `MAILBOX0/1` 0x040/0x044, `OS` 0x080, `DEBUGINFO` 0x094, `CPUCTL` 0x100, `BOOTVEC` 0x104, `DMACTL` 0x10c, `DMATRFBASE` 0x110, `DMATRFMOFFS` 0x114, `DMATRFCMD` 0x118 (transfer on write), `DMATRFFBOFFS` 0x11c, `DMATRFBASE1` 0x128, `FBIF_TRANSCFG(0..7)` 0x600, `FBIF_CTL` 0x624 | header + firmware use + observed | +| RISC-V local | `+0x111000`, alias `0x300001000` | `IRQMSET` 0x2ac, `IRQMCLR` 0x2b0, `IRQMASK` 0x2b4 (read), `IRQDEST` 0x2b8, `IRQTYPE` 0x2bc, `TRACECTL` 0x344, `TRACE_RDIDX` 0x348, `TRACE_WTIDX` 0x34c, `PRIV_ERR_STAT` 0x360, `PRIV_ERR_INFO` 0x364 (read), `PRIV_ERR_ADDR` 0x368 (read), `HUB_ERR_STAT` 0x36c | header + observed | +| PTIMER | `+0x9000` | `TIME_0` aperture 0x9400 / block `+0x400` (NSEC 31:5), `TIME_1` aperture 0x9410 / block `+0x410` (NSEC 28:0); value = instruction count × `ns_per_insn` (**modeled**, not calibrated) | header + **modeled** time | +| WPR2 | `+0x1FA000` | `WPR2_ADDR_LO` 0x1FA824, `WPR2_ADDR_HI` 0x1FA828 (4 KiB alignment; HI points at the last 128 KiB block) | header + firmware use | +| CSB/TRANSCOM | profile-declared | none by default; a profile may declare individual registers with width/value and `rw`/`ro`/`wo`/`w1c`/`set`/`clear` semantics | none yet (B3 landing point) | +| PMU | profile-declared | none; the stub records accesses and returns unhandled | none yet | +| DMA seam | FBGPA/SYSGPA (profile) | GPU-physical → RAM windows for falcon DMA and aperture loads/stores; unmapped transfers are refused and recorded | address-map header + firmware use | + +Falcon DMA follows the header field semantics: `size = 1 << (SIZE+2)`, +`IMEM`/`DMEM` aperture select, `WRITE` direction, address +`((BASE1<<32 | BASE) << 8) + FBOFFS`, `IDLE` set on success and `ERROR` on a +refused transfer. Which FB/SYS aperture a DMA address targets (the +`FBIF_TRANSCFG.TARGET` decode) is **not proven yet** and is listed in §6. + +### 3.1 Boot shim (declared assumptions) + +The firmware's `_start` consumes boot arguments the real SEC2 booter/host +writes; the simulator reconstructs them from the documented structure layout +and records each as an assumption in `session.json.boot_shim.assumptions`: + +* `NV_RISCV_BOOT_PARAMS` at a RAM address (bootType `NVRM`, size 120, + version 1, core-dump buffer, one `WPRM` libos init arg); +* a `GspFwWprMeta` (magic/revision/verified and a self-consistent FB layout); +* raw-image mirror at the DMEM aperture base so the app's own relocation copy + is self-consistent (it is not: see §6); +* `a0`–`a5` register arguments (bootargs PA/VA, ELF PA/size, load base, WPR + id). + +The DEBUGINFO **host-consume** behaviour is also a shim: the firmware writes a +boot-stage marker and polls bits 22:20 until they clear, and no self-clearing +path exists in the firmware, so the host side is modelled as consuming the +stage marker on read. The device never changes a read value except for this +documented shim, and the shim is profile-enabled and session-recorded. + +## 4. Boot ladder results (observed, 2026-10-03) + +| Rung | Claim | Evidence | +|---|---|---| +| **B0** | flat image loads; first MMIO is the unmodelled PMC `BOOT_42` read at `0x2000_0000_0000_0A00` | `tests/test_sim_devices.py` (B0 classification) | +| **B1** | device model serves the whole boot path: **0 unknown MMIO, 0 unhandled in windows**, deterministic 2M-instruction run stopping at the boot-halt/report loop (`0x4010928`) | `run_boot(use_shim=False)`; sessions `dumps/gsp-boot-b1-run1`, `dumps/gsp-boot-b1-run2`; test `test_no_shim_b1_device_model_serves_boot` | +| **B2** | with the shim, the firmware passes the chip gate, MPU/vector setup, the bootargs consumer (`0x4007A30`) and reaches its **relocation copy** (`0x4007B7C`), then stops at a known unknown (DMEM runspace) | sessions `dumps/gsp-boot-b2-run1`, `dumps/gsp-boot-b2-run2`; test `test_shim_reaches_relocation_b2` | + +Reproduction (read-only; no hardware): + +```bash +cd open-iov/debug/risc-v-gsp-rm-vm +python3 -m sim.gsp_boot --instructions 2000000 --record dumps/gsp-boot-b2-run1 +python3 -m unittest tests.test_sim_devices -v +``` + +Two-run determinism is asserted by `test_two_runs_identical` and was checked +at the recorded B2 sessions: identical instruction count (14 682), stop +reason/PC (`fault @ 0x400EA0C`), device-state SHA-256 +(`3fa264b9…`) and register file. The B1 no-shim run is likewise identical +across runs (2 000 000 instructions, budget stop at `0x4010928`, device-state +SHA-256 `88eb07b7…`). + +## 5. Session evidence + +Each `run_boot` invocation writes a `greeneye-session/1` directory with: + +* `session.json` — firmware SHA-256, profile name, load layout, rung, + milestones, stop reason/PC, unknown-MMIO counts, device-state SHA-256, + device-access counts and the full boot-shim assumption list; +* `blobs/device-state.json` — the `greeneye-sim-devices/1` snapshot of every + device (registers, IRQ state, DMA windows/counters, shim flags); +* `events.jsonl` — the normal session event stream (`gsp_boot` note). + +## 6. Unknowns (explicitly not modeled / not verified) + +1. **DMEM runspace content.** The app's relocation copy reads the DMEM + aperture (`0x1_0000_0000+`) and writes it to the `0x400E000` runtime + region; the bootloader-provided content is not reconstructed, so the copy + writes zeros and the run stops at `0x400EA0C` (illegal instruction). This + is the B2 ceiling today. +2. **CSB/TRANSCOM register semantics.** No message-window poll has been + observed yet, so no register is modeled. B3 waits for the first observed + poll; the `csb.py` seam and profile register declarations are in place. +3. **PMU.** No PMU register access observed; stub only. +4. **FWSEC state machine.** Only the WPR2 address pair is modeled; FWSEC + execution is not. +5. **DMA aperture selection.** `FBIF_TRANSCFG.TARGET`/`MEM_TYPE` decode is + not proven; only the profile's DMA windows decide what an address means. +6. **Interrupt delivery.** Falcon/RISC-V IRQ state is aggregated and + serialisable, but mstatus/mie/mip/mtvec trap entry and interrupt injection + are not modelled. +7. **PTIMER calibration.** Values are modeled from the instruction count with + a placeholder `ns_per_insn`; no firmware PTIMER read has been observed and + no timing claim is made. +8. **MPU translation.** The firmware programs its MPU CSRs (observed), but + the machine does not enforce translations; the libos private mapping is + served by explicit device aliases and the FBGPA/SYSGPA seam, not by an MPU + model. + +Nothing in this page is a silicon-accuracy claim; `06-ACCURACY.md` fidelity +levels apply (L0/L1 modelled, L2 modelled-not-calibrated, L3 partial and +listed above). |
