From cd1f2528e8243fed3ce80d5170ef93928e4e7284 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Tue, 6 Oct 2026 19:28:39 -0400 Subject: risc-v-gsp-rm-debugger: land docs 45-53 + harness/sim tool set with tests rm_capture (chunked decode), launch_audit, state_seed/state_decode, valprobe, rehost, contracts+run_contracts, host_traffic, gmmu_walk, msgq_attach, libos_port, log_decode, server_snapshot; doc index updates in the tool overview, operations pages and the repo README. --- debug/risc-v-gsp-rm-vm/tests/test_gmmu_walk.py | 243 +++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 debug/risc-v-gsp-rm-vm/tests/test_gmmu_walk.py (limited to 'debug/risc-v-gsp-rm-vm/tests/test_gmmu_walk.py') diff --git a/debug/risc-v-gsp-rm-vm/tests/test_gmmu_walk.py b/debug/risc-v-gsp-rm-vm/tests/test_gmmu_walk.py new file mode 100644 index 0000000..f438068 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/tests/test_gmmu_walk.py @@ -0,0 +1,243 @@ +"""Tests for the functional GMMU walker (sim/gmmu_walk.py, docs/48). + +The golden vector is a captured channel PDB (numeric entries); the synthetic +trees are built with the module's own encoders and must round-trip. No +hardware, no modules, no guest, no network. + +Run:: + + python3 -m unittest tests.test_gmmu_walk -v +""" +from __future__ import annotations + +import contextlib +import io +import json +import os +import struct +import sys +import unittest + +HERE = os.path.dirname(os.path.abspath(__file__)) +TOOL_ROOT = os.path.abspath(os.path.join(HERE, "..")) +if TOOL_ROOT not in sys.path: + sys.path.insert(0, TOOL_ROOT) + +from sim.gmmu_walk import ( # noqa: E402 + FAULT_INVALID_APERTURE, + FAULT_PTE_INVALID, + FAULT_TABLE_MISSING, + FAULT_UNSUPPORTED, + FAULT_OUT_OF_RANGE, + WALK_FORMAT, + MemoryView, + WalkError, + channel_pdb_fixture, + encode_dual_slot, + encode_pde_pointer, + encode_pte, + main, + walk, +) + + +def _tree(root_pa: int, va: int, target_pa: int | None, *, base: int = 0x50000000, + read_only: bool = False) -> MemoryView: + i0 = (va >> 47) & 0x3 + i1 = (va >> 38) & 0x1FF + i2 = (va >> 29) & 0x1FF + i3 = (va >> 21) & 0xFF + i4 = (va >> 12) & 0x1FF + pd2, pd1, pd0, pt = base + 0x1000, base + 0x2000, base + 0x3000, base + 0x4000 + mem = MemoryView() + page = bytearray(0x1000) + struct.pack_into("> 47) & 0x3 + i1 = (va >> 38) & 0x1FF + i2 = (va >> 29) & 0x1FF + i3 = (va >> 21) & 0xFF + pd2, pd1, pd0 = 0x51001000, 0x51002000, 0x51003000 + page = bytearray(0x1000) + struct.pack_into("> 47) & 0x3 + i1 = (va >> 38) & 0x1FF + i2 = (va >> 29) & 0x1FF + i3 = (va >> 21) & 0xFF + pd2, pd1, pd0, pt = 0x52001000, 0x52002000, 0x52003000, 0x52004000 + mem = MemoryView() + page = bytearray(0x1000) + struct.pack_into("> 16) & 0x1FF) * 8, + encode_pte(pa, page_size="64k")) + mem.add(pt, bytes(page)) + report = walk(va, root_pa=0x52000000, mem=mem, page_mode="auto") + self.assertEqual(report["status"], "ok") + self.assertEqual(report["page_mode_used"], "64k") + self.assertEqual(report["evidence"], "modeled") + + +class FaultTests(unittest.TestCase): + def test_missing_table_page(self): + root_pa, mem = channel_pdb_fixture() + report = walk(0x100000, root_pa=root_pa, mem=MemoryView()) + self.assertEqual(report["status"], "fault") + self.assertEqual(report["fault"], FAULT_TABLE_MISSING) + + def test_invalid_leaf(self): + mem = _tree(0x60000000, 0x204608000, None) # leaf entry stays zero + report = walk(0x204608000, root_pa=0x60000000, mem=mem) + self.assertEqual(report["status"], "fault") + self.assertEqual(report["fault"], FAULT_PTE_INVALID) + + def test_invalid_pde_aperture(self): + root_pa = 0x60000000 + mem = MemoryView() + page = bytearray(0x1000) + struct.pack_into("