diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-04 18:42:36 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-04 18:42:36 -0400 |
| commit | 1f2073d4fbb1d412d9bbf373312e3c51b83db92a (patch) | |
| tree | a661537d7ec9510324e0a40a5a65e4b8c853f01b /debug/risc-v-gsp-rm-vm/sim/machine.py | |
| parent | c1adf2727983f5cace8ca0f5d1119ac2256c348e (diff) | |
| download | open-iov-1f2073d4fbb1d412d9bbf373312e3c51b83db92a.tar.gz open-iov-1f2073d4fbb1d412d9bbf373312e3c51b83db92a.zip | |
greeneye: GMMU/FBIF observability, PTE decoder and oracle, MPU/libos simulator wave
Simulator development wave (docs 42-44): GMMU page-table entry decode with its oracle/workflow harness, FBIF observability, and MPU/LIBOS device surfaces in the device model, plus refreshed boot/machine/profile data (tu104-570.144), the qemu-line results, and the new unit tests. Docs 00/06/35-41 updated to match; harness helpers and .gitignore included.
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/sim/machine.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/sim/machine.py | 80 |
1 files changed, 68 insertions, 12 deletions
diff --git a/debug/risc-v-gsp-rm-vm/sim/machine.py b/debug/risc-v-gsp-rm-vm/sim/machine.py index 9908753..7634ce1 100644 --- a/debug/risc-v-gsp-rm-vm/sim/machine.py +++ b/debug/risc-v-gsp-rm-vm/sim/machine.py @@ -19,6 +19,7 @@ import mmap import struct from .cycles import DEFAULT_MODEL +from .mpu import MSTATUS, WATCHED_CSRS, RiscvMpu from .decode import ( A_ADD, A_AND, @@ -84,6 +85,9 @@ R_ECALL = 6 #: Accepted ``unknown_mmio`` policies for accesses outside RAM/UART/the map. UNKNOWN_MMIO_MODES = ("fault", "lenient") +#: CSRs whose writes update the MMU model (M-mode protection unit + mstatus). +_MPU_CSRS = frozenset(WATCHED_CSRS) | {MSTATUS} + UART_BASE = 0x10000000 UART_SIZE = 0x100 @@ -232,6 +236,10 @@ class Machine: self.device_map = device_map self.devices = devices self.translator = translator # aperture -> RAM seam (sim.devices.dma) + self.mpu = RiscvMpu() # M-mode protection unit (sim.mpu) + #: Optional guest-ECALL service (``handle(machine) -> (handled, ret)``); + #: when absent (or unhandled) ``run`` stops with ``R_ECALL`` as before. + self.syscall_handler = None self.unknown_mmio = unknown_mmio self.learn_mmio = bool(learn_mmio) self.bias = bias # PC relocation for learned-map firmware addresses @@ -506,6 +514,10 @@ class Machine: a = b = 0 traced = trace is not None active = False + # M-mode protection unit (sim.mpu): translation is consulted only when + # an enabled entry exists; no match is treated as identity. + mpu = self.mpu + mpu_on = mpu.active # Modeled cycle accounting (sim.cycles): pure table lookups, no timing. cycle_base = self._cycle_base cycle_op = self._cycle_op @@ -520,7 +532,12 @@ class Machine: a = pc break - off = pc - base + fetch_pc = pc + if mpu_on: + translated = mpu.translate(pc) + if translated is not None: + fetch_pc = translated + off = fetch_pc - base if off < 0 or off + 4 > limit: reason = R_FAULT a = 1 @@ -558,6 +575,12 @@ class Machine: b = hit break o = ea - base + mem_ea = ea + if mpu_on: + translated = mpu.translate(ea) + if translated is not None: + mem_ea = translated + o = mem_ea - base if 0 <= o <= limit - size: if active: trace.mem(insn_pc, ea, size, False, self.insns + n) @@ -587,7 +610,7 @@ class Machine: pc = nxt else: try: - v = self._mmio_load(ea, size, pc) + v = self._mmio_load(mem_ea, size, pc) except Fault as f: reason = R_FAULT a = f.cause @@ -613,6 +636,12 @@ class Machine: b = hit break o = ea - base + mem_ea = ea + if mpu_on: + translated = mpu.translate(ea) + if translated is not None: + mem_ea = translated + o = mem_ea - base value = x[r2] if 0 <= o <= limit - size: if active: @@ -627,17 +656,20 @@ class Machine: ram[o] = value & 0xFF # Self-modifying code: drop any cached decode overlapping # the written range (firmware patches code at runtime). - p = ea & ~1 - end = ea + size - while p < end: - cache.pop(p, None) - p += 2 + # Both the virtual address and its translated backing are + # dropped so a fetch through either mapping re-decodes. + for target in ((ea, mem_ea) if mem_ea != ea else (ea,)): + p = target & ~1 + end = target + size + while p < end: + cache.pop(p, None) + p += 2 if counting: cycle_sum += cycle_mem pc = nxt else: try: - self._mmio_store(ea, size, value, pc) + self._mmio_store(mem_ea, size, value, pc) except Fault as f: reason = R_FAULT a = f.cause @@ -864,6 +896,9 @@ class Machine: a = 2 b = csr break + if csr in _MPU_CSRS: + mpu.on_csr_write(csr, self.csrs.get(csr, 0)) + mpu_on = mpu.active pc = nxt elif kind == K_AMO: @@ -938,9 +973,20 @@ class Machine: elif kind == K_ECALL: if single_step: pc = nxt + elif self.syscall_handler is not None: + handled, result = self.syscall_handler(self, pc) + if not handled: + reason = R_ECALL + a = pc + b = x[5] # syscall number (t0), for diagnostics + break + if result is not None: + x[10] = result & MASK64 + pc = nxt else: reason = R_ECALL a = pc + b = x[5] break elif kind == K_MRET: @@ -975,15 +1021,25 @@ class Machine: # -- guest memory helpers (AMO) ---------------------------------------- def _guest_load(self, addr: int, width: int, pc: int = 0) -> int: - off = addr - self.ram_base + mem = addr + if self.mpu.active: + translated = self.mpu.translate(addr) + if translated is not None: + mem = translated + off = mem - self.ram_base if 0 <= off <= self.ram_size - width: if width == 8: return self._u64.unpack_from(self.ram, off)[0] return self._u32.unpack_from(self.ram, off)[0] - return self._mmio_load(addr, width, pc) + return self._mmio_load(mem, width, pc) def _guest_store(self, addr: int, width: int, value: int, pc: int = 0) -> None: - off = addr - self.ram_base + mem = addr + if self.mpu.active: + translated = self.mpu.translate(addr) + if translated is not None: + mem = translated + off = mem - self.ram_base if 0 <= off <= self.ram_size - width: if width == 8: self._u64p(self.ram, off, value) @@ -995,7 +1051,7 @@ class Machine: self._cache.pop(p, None) p += 2 return - self._mmio_store(addr, width, value, pc) + self._mmio_store(mem, width, value, pc) #: Task-facing alias: the native simulator machine is :class:`Machine`. |
