code wiki / _hdl_build / _k_r2_001c3_gate.nx
_k_r2_001c3_gate.nx
buildroot/runtime/_hdl_build/_k_r2_001c3_gate.nx
about
_k_r2_001c3_gate.nx -- the K-R2-001c3 gate (virtio-NET FRAME LOOPBACK; the THIRD and final
slice of the K-R2-001c net virtqueue epic). It is the K-R2-001b3 sector-data round-trip gate
applied to the SECOND virtio device, virtio-net (DeviceID=1) @ base 0x10002000. NO mocks:
runs the REAL nx_virtio_hs_emit (the SAME shared emitter the blk b-series + the net c1/c2 use
-- data-only on base/device-id/banner/queue-config/descriptor/avail-used/frame, so it stays
byte-for-byte backward-compatible), then RUNS the emitted image on the SOVEREIGN rv64 emulator
(rv64im_min_sim + the second rv64im_min_virtio net instance @ 0x10002000 -- the PRIMARY, gating
lane: Nishi owns the runtime). After the c2 queue-config the net driver lays a frame (a
virtio-net WIRE_TLV header word: flags/gso_type/hdr_len packed into the first 32-bit word) +
payload into a tx descriptor's data buffer in guest RAM, publishes the descriptor on the AVAIL
ring, kicks QueueNotify -> the net QueueNotify now triggers nx_virtio_notify_dma on s.virtio_net
(the device-instance-generic DMA walk: desc-read + avail/used + the data round-trip), so the
device FOLLOWS desc[head].addr into guest RAM, DMA-READS the frame's first word, and latches it
into QueueSectPeek. The driver reads QueueSectPeek BACK (lwu) and verifies it == the sent frame
word -> emits the trailing " FRAME" canary. The gate asserts the captured serial transcript
CONTAINS the emitter's golden ("VNET ACK DRV FEAT OK VQ DESC USED STAT FRAME\n") AND the
sovereign emu reports a clean SiFive-finisher halt. The blk device @ 0x10001000 is left
BYTE-UNTOUCHED (its own gates VIRTGATE..SECTGATE still pass, re-proven by re-run).
Then the ALIGNMENT lane: qemu-system-riscv64 -machine virt -global
virtio-mmio.force-legacy=true with a REAL virtio-blk-device (first) + a REAL
virtio-net-device (second). qemu fills its virtio-mmio slots in REVERSE, so the first device
(blk) lands at the top slot 0x10008000 and the SECOND device (net) lands at the next slot DOWN,
0x10007000. The gate authors a SECOND net image from a base-rewritten spec (base = the qemu net
reverse-slot 0x10007000) and runs THAT on qemu; the SAME loopback driver lays the SAME tx
descriptor + the SAME avail ring + the SAME frame word into qemu guest RAM and kicks the real
QueueNotify (the real transport walks the ring). The sovereign-only QueueDescPeek/
QueueUsedIdxPeek/QueueStatPeek/QueueSectPeek RO peek registers (0x060/0x064/0x068/0x06C) are a
SIM modelling device -- they read 0 on the real qemu virtio-net transport -- so the descriptor-
DMA + used + status + FRAME read-back verifies drop " DESC"/" USED"/" STAT"/" FRAME" there;
the gate asserts the PREFIX golden ("VNET ACK DRV FEAT OK VQ") appears, proving the driver runs
IDENTICALLY against the REAL virtio-net transport through the handshake + queue-config + tx-
descriptor lay + avail publish + QueueNotify kick (lanes AGREE on the real-hardware-driveable
behaviour; the frame round-trip proof itself is the sovereign PRIMARY lane, the same alignment
semantics the blk b3 SECTGATE established).
Finally a TAMPER test: corrupt the FRAME-EXPECTED constant in the sovereign image (the driver
loads its own QueueSectPeek frame read-back into t3 via `lwu t3,0x06C(t2)` and compares against
the li-loaded expected in t4; the expected li is the lui/addi following the unique SectPeek
read-back load). Bumping the addi's high immediate byte makes the read-back verify branch PAST
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 50 | const G_QSECTPEEK_LOAD_WORD: i64 = 0x06c3ee03 // lwu t3, 0x06C(t2) (QueueSectPeek frame read-back) |
| 51 | const G_QEMU_BASE: i64 = 0x10007000 // the slot qemu-virt assigns the SECOND device (net) |
functions
| 53 | func g_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } |
| 54 | func g_fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } |
| 55 | func g_fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 } |
| 58 | func g_run_emit(spec: *u8) -> i64 |
| 79 | func g_run_sov(binpath: *u8, outpath: *u8) -> i64 |
| 103 | func g_run_qemu(binpath: *u8, outpath: *u8, backing: *u8) -> i64 |
| 136 | func g_make_backing(path: *u8) -> i64 |
| 148 | func g_read(path: *u8, buf: *u8, cap: i64) -> i64 |
| 159 | func g_buf_has(buf: *u8, n: i64, pat: *u8, pl: i64) -> i64 called by 1: main |
| 173 | func g_w32(buf: *u8, o: i64) -> i64 called by 1: g_find_sectpeek_load |
| 184 | func g_find_sectpeek_load(buf: *u8, n: i64) -> i64 |
| 193 | func g_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } called by 1: main |
| 196 | func g_line_is(buf: *u8, ls: i64, le: i64, key: *u8) -> i64 called by 1: g_write_qemu_spec |
| 209 | func g_write_qemu_spec(mainspec: *u8, derived: *u8, qemu_out: *u8) -> i64 |
| 236 | func main() -> i64 |