code wiki / _hdl_build / nx_virtio_hs_emit.nx
nx_virtio_hs_emit.nx
buildroot/runtime/_hdl_build/nx_virtio_hs_emit.nx
about
nx_virtio_hs_emit.nx -- the virtio-MMIO HANDSHAKE emitter (K-R2-001a of the kernel-up
ladder). A NEW transport bring-up IS A SPEC FILE: reads the legacy virtio-MMIO
register block (base + offsets), the device identity (magic/version/device-id), the
status-progression bits, and the banner from knowledge/specs/virtio_blk_handshake_virt
.spec and AUTHORS a bare-metal rv64 flat image whose driver performs the REAL device-
initialization handshake (virtio v1.2 sec 3.1):
verify MagicValue == "virt", Version, DeviceID == 2 (block) -> emit "VIO "
Status |= ACKNOWLEDGE | DRIVER -> emit "ACK "
read HostFeatures, write GuestFeatures, Status |= FEATURES_OK -> emit "DRV "
re-read Status, confirm FEATURES_OK stuck -> emit "FEAT "
Status |= DRIVER_OK -> emit "OK\n"
write the SiFive finisher -> clean halt.
Any verify that fails BRANCHES PAST the rest of the handshake straight to the finisher,
so the transcript loses its tail (the DRIVER_OK "OK\n" canary, and the segments before
it) -- that is what the gate's tamper test exploits. Zero hand-written machine code:
the emitter is a tiny rv64 encoder (lui/addi/lw/sw/sb + B-type bne/beq + R-type and +
jal) and the IMAGE + the GOLDEN transcript are TABLE-COMPUTED from the spec. The image
is authored in TWO passes (a measure pass that fixes the finisher byte-offset, then the
real pass that backfills the fail-branch targets) so every forward branch is
structurally derived, never typed -- byte-reproducibly.
nx_virtio_hs_emit <specpath> -> writes the flat image to the spec's `out` and the
table-computed golden transcript to <out>.gold
VERDICT log -> knowledge/status/virtio_blk.log (VIRTEMIT rows, the gate's evidence).
Sovereign: syscalls only, no gcc/.sh. license_tier: ORIGINAL
X-DRV-W1 stage A refactor: the rv64 mini-encoder + the four shape-op families (WIRE_TLV /
COMMAND_QUEUE / STATE_MACHINE / STRUCT_WALK) now live in the DEVICE-AGNOSTIC nx_driver_shapes
library, and every vh_* encoder/emit function below DELEGATES to its ds_* twin. The virtio
identity lives ONLY in the spec-derived cfg[] table threaded into vh_emit_image -- the shape
library contains zero virtio knowledge. The op bodies are byte-for-byte the same code path as
before (a thin pass-through), so this emitter re-emits its image BYTE-IDENTICALLY (the stage-A
regression guard the gate proves).
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_driver_shapes.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
| 35 | const VH_MAGIC_8192: i64 = 8192 |
| 38 | const VH_UART: i64 = 0x10000000 // NS16550A THR (write a byte = transmit) |
| 39 | const VH_FIN: i64 = 0x100000 // SiFive test finisher (write to exit) |
| 40 | const VH_PASS: i64 = 0x5555 // FINISHER_PASS low half -> clean halt |
| 42 | const RV_X0: i64 = 0 |
| 43 | const RV_T0: i64 = 5 // UART base |
| 44 | const RV_T1: i64 = 6 // scratch / transcript byte |
| 45 | const RV_T2: i64 = 7 // device base |
| 46 | const RV_T3: i64 = 28 // loaded register value (actual) |
| 47 | const RV_T4: i64 = 29 // expected constant |
| 48 | const RV_T5: i64 = 30 // finisher base / feature scratch |
| 51 | const VC_OFF_MAGIC: i64 = 0 |
| 52 | const VC_OFF_VERSION: i64 = 1 |
| 53 | const VC_OFF_DEVICEID: i64 = 2 |
| 54 | const VC_OFF_VENDORID: i64 = 3 |
| 55 | const VC_OFF_HOSTFEAT: i64 = 4 |
| 56 | const VC_OFF_GUESTFEAT: i64 = 5 |
| 57 | const VC_OFF_STATUS: i64 = 6 |
| 58 | const VC_MAGIC: i64 = 7 |
| 59 | const VC_VERSION: i64 = 8 |
| 60 | const VC_DEVICEID: i64 = 9 |
| 61 | const VC_HOSTFEAT: i64 = 10 |
| 62 | const VC_ACK: i64 = 11 |
| 63 | const VC_DRIVER: i64 = 12 |
| 64 | const VC_FEATOK: i64 = 13 |
| 65 | const VC_DRIVEROK: i64 = 14 |
| 66 | const VC_BASE: i64 = 15 |
| 68 | const VC_OFF_QSEL: i64 = 16 |
| 69 | const VC_OFF_QNUMMAX: i64 = 17 |
| 70 | const VC_OFF_QNUM: i64 = 18 |
| 71 | const VC_OFF_QALIGN: i64 = 19 |
| 72 | const VC_OFF_QPFN: i64 = 20 |
| 73 | const VC_OFF_QNOTIFY: i64 = 21 |
| 74 | const VC_QSEL: i64 = 22 |
| 75 | const VC_QALIGN: i64 = 23 |
| 76 | const VC_QNUM: i64 = 24 |
| 77 | const VC_QPFN: i64 = 25 |
| 78 | const VC_QNOTIFY: i64 = 26 |
| 82 | const VC_QEND: i64 = 27 |
| 84 | const VC_OFF_QDESCPEEK: i64 = 27 |
| 85 | const VC_OFF_DESC_ADDR: i64 = 28 |
| 86 | const VC_OFF_DESC_LEN: i64 = 29 |
| 87 | const VC_OFF_DESC_FLAGS:i64 = 30 |
| 88 | const VC_OFF_DESC_NEXT: i64 = 31 |
| 89 | const VC_RING_ADDR: i64 = 32 |
| 90 | const VC_DESC_ADDR_LO: i64 = 33 |
| 91 | const VC_DESC_LEN: i64 = 34 |
| 92 | const VC_DESC_FLAGS: i64 = 35 |
| 93 | const VC_DESC_NEXT: i64 = 36 |
| 97 | const VC_DEND: i64 = 37 |
| 99 | const VC_OFF_QUSEDIDXPEEK: i64 = 37 |
| 100 | const VC_AVAIL_RING_OFF: i64 = 38 |
| 101 | const VC_AVAIL_IDX_OFF: i64 = 39 |
| 102 | const VC_USED_RING_OFF: i64 = 40 |
| 103 | const VC_USED_IDX_OFF: i64 = 41 |
| 104 | const VC_AVAIL_HEAD: i64 = 42 |
| 105 | const VC_AVAIL_IDX_VAL: i64 = 43 |
| 106 | const VC_USED_IDX_EXP: i64 = 44 |
| 111 | const VC_DEND2: i64 = 45 |
| 113 | const VC_OFF_QSTATPEEK: i64 = 45 |
| 114 | const VC_STAT_BUF_ADDR: i64 = 46 |
| 115 | const VC_STAT_BUF_LO: i64 = 47 |
| 116 | const VC_BLK_S_OK: i64 = 48 |
| 117 | const VC_STAT_EXPECTED: i64 = 49 |
| 122 | const VC_DEND3: i64 = 50 |
| 124 | const VC_OFF_QSECTPEEK: i64 = 50 |
| 125 | const VC_OFF_DATA_SECTOR: i64 = 51 |
| 126 | const VC_SECT_PATTERN: i64 = 52 |
| 127 | const VC_SECT_DATA_EXP: i64 = 53 |
| 128 | const VC_N: i64 = 54 |
functions
| 130 | func vh_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } |
| 131 | func vh_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 } |
| 132 | func vh_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 } |
| 133 | func vh_hex(fd: i64, v: i64) -> i64 { let d: *u8=sys_mmap(16); var i: i64=0; while i<8{let nib: i64=(v >> ((7-i)*4)) & 0xf; if nib<10{d[i]=(48+nib) as u8} else {d[i]=(87+nib) as u8} i=i+1}; sys_write(fd,d,8); return 0 } |
| 139 | func vh_w32(buf: *u8, off: i64, w: i64) -> i64 { return ds_w32(buf, off, w) } |
| 140 | func vh_li32(buf: *u8, off: i64, rd: i64, val: i64) -> i64 { return ds_li32(buf, off, rd, val) } calls 1: ds_li32 |
| 141 | func vh_li32u(buf: *u8, off: i64, rd: i64, val: i64) -> i64 { return ds_li32u(buf, off, rd, val) } |
| 142 | func vh_load(rd: i64, rs1: i64, f3: i64, imm: i64) -> i64 { return ds_load(rd, rs1, f3, imm) } |
| 143 | func vh_emit_str(buf: *u8, off: i64, s: *u8, n: i64) -> i64 { return ds_emit_str(buf, off, s, n) } |
| 145 | func vh_emit_verify(buf: *u8, off: i64, regoff: i64, expected: i64, fail_off: i64) -> i64 { return ds_emit_verify(buf, off, regoff, expected, fail_off) } |
| 146 | func vh_emit_verify_u(buf: *u8, off: i64, regoff: i64, expected: i64, fail_off: i64) -> i64 { return ds_emit_verify_u(buf, off, regoff, expected, fail_off) } |
| 147 | func vh_emit_regwrite(buf: *u8, off: i64, regoff: i64, val: i64) -> i64 { return ds_emit_regwrite(buf, off, regoff, val) } |
| 148 | func vh_emit_checkbit(buf: *u8, off: i64, regoff: i64, mask: i64, fail_off: i64) -> i64 { return ds_emit_checkbit(buf, off, regoff, mask, fail_off) } |
| 150 | func vh_emit_memstore(buf: *u8, off: i64, base_reg: i64, memoff: i64, f3: i64, val: i64) -> i64 { return ds_emit_memstore(buf, off, base_reg, memoff, f3, val) } |
| 152 | func vh_emit_finisher(buf: *u8, off: i64) -> i64 { return ds_emit_finisher(buf, off) } |
| 160 | func vh_emit_image(buf: *u8, cfg: *i64, tail: *u8, segs: *i64, fail_off: i64, stage_mode: i64) -> i64 |
| 281 | func vh_parse_num(buf: *u8, p: i64, le: i64, endp: *i64) -> i64 called by 1: vh_num_field |
| 315 | func vh_num_field(buf: *u8, ls: i64, le: i64, key: *u8, out: *i64) -> i64 |
| 328 | func vh_str_field(buf: *u8, ls: i64, le: i64, key: *u8, out: *u8) -> i64 called by 1: main |
| 342 | func vh_log(name: *u8, bytes: i64, golden: *u8, verdict: *u8) -> i64 |
| 353 | func main(argc: i64, argv: *i64) -> i64 |