code wiki / _hdl_build / _drv_proto_gate.nx

_drv_proto_gate.nx source

↩ module page · 187 lines · 10380 B

1// _drv_proto_gate.nx -- the gate for DRIVER-PROTOCOL-FROM-SPEC (X-DRV-W1). NO mocks. 2// 3// Drives the GENERIC emitter end to end: runs the REAL nx_drv_proto_emit on TWO different driver 4// SPECS (op-lists), runs EACH emitted image on the SOVEREIGN rv64 emulator (nx_boot_run_sov, with 5// the legacy virtio-MMIO blk @0x10001000 + net @0x10002000 device models attached), and asserts: 6// 7// (1) BLK -- spec A (virtio-blk, DeviceID=2) drives the FULL register/ring/irq transaction 8// (handshake -> queue config -> descriptor lay -> avail/used ring -> status writeback -> 9// sector-data round-trip): the captured serial CONTAINS golden A + the emu reports a clean 10// SiFive-finisher halt. The device genuinely DMA-walked the ring the driver laid (the driver 11// verifies QueueDescPeek/UsedIdxPeek/StatPeek/SectPeek read-backs), so a stuck device cannot 12// fake it. 13// (2) NET -- spec B (virtio-net, DeviceID=1) drives a DIFFERENT op-list against a DIFFERENT 14// device class: serial CONTAINS golden B + clean halt. 15// (3) DISTINCT -- golden A != golden B AND both non-empty, BOTH authored by the SAME emitter 16// binary. Two different op-lists -> two different working drivers proves the protocol STATE 17// MACHINE is synthesized FROM THE SPEC, not a fixed virtio-blk template (the no-false-green 18// keystone: a fixed template could not produce two distinct device-class drivers). 19// (4) TAMPER -- two independent corruptions of the BLK image, each must drop golden A: 20// t1: bump the device-base lui immediate (byte 7) -> all MMIO reads target a non-device 21// address -> the identity verify fails -> the whole transcript collapses (proves the 22// driver REALLY talks to the device at the spec's base; a no-op driver would be immune). 23// t2: bump the magic-EXPECTED constant (byte 15, the first verify's li high byte) -> the 24// identity verify mismatches -> transcript collapses (proves the VERIFY logic is real, 25// not a rubber stamp). 26// 27// Evidence -> knowledge/status/driver_spec.log (DRVPROTOGATE row; the queue row's ||MARK= reads 28// it). Sovereign orchestration (fork/dup3/execve/wait4), no gcc/.sh. license_tier: ORIGINAL 29import "nx_syscalls.nx" 30 31const EMIT_ELF: *u8 = "_offc/nx_drv_proto_emit.elf" 32const SOV_ELF: *u8 = "_offc/nx_boot_run_sov.elf" 33 34func 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 } 35func 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 } 36func 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 } 37 38// run prog with one arg (a1, may be null); serial/stdout -> outpath; return WEXITSTATUS (or 128+sig). 39func g_run1(prog: *u8, a1: *u8, outpath: *u8) -> i64 { 40 let pid: i64 = sys_fork() 41 if pid == 0 { 42 let ofd: i64 = sys_openat_wr(outpath, 0x1a4) 43 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) } 44 let argv: *i64 = sys_mmap(32) as *i64 45 argv[0] = prog as i64 46 var k: i64 = 1 47 if a1 != (0 as *u8) { argv[k] = a1 as i64; k = k + 1 } 48 argv[k] = 0 49 let envp: *i64 = sys_mmap(16) as *i64 50 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 51 sys_execve(prog, argv, envp) 52 sys_exit(127) 53 } 54 let st: *i64 = sys_mmap(16) as *i64 55 sys_wait4(pid, st, 0) 56 let sig: i64 = st[0] & 0x7f 57 if sig != 0 { return 128 + sig } 58 return (st[0] >> 8) & 0xff 59} 60 61// read whole file into buf (cap-1 max); return byte count (0 if absent). 62func g_read(path: *u8, buf: *u8, cap: i64) -> i64 { 63 let fd: i64 = sys_openat_rd(path) 64 if fd < 0 { return 0 } 65 var n: i64 = 0 66 var go: i64 = 1 67 while go == 1 { let r: i64 = sys_read(fd, (buf as i64 + n) as *u8, cap - 1 - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap - 1 { go = 0 } } 68 sys_close(fd) 69 return n 70} 71 72// does buf[0,n) contain pat (length pl)? 1/0 73func g_buf_has(buf: *u8, n: i64, pat: *u8, pl: i64) -> i64 { 74 if pl <= 0 { return 0 } 75 var i: i64 = 0 76 while i + pl <= n { 77 var k: i64 = 0; var hit: i64 = 1 78 while k < pl { if buf[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } } 79 if hit == 1 { return 1 } 80 i = i + 1 81 } 82 return 0 83} 84 85func g_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 86 87// are two NUL-terminated strings equal? 1/0 88func g_streq(a: *u8, b: *u8) -> i64 { 89 var i: i64 = 0 90 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 91 if b[i] != (0 as u8) { return 0 } 92 return 1 93} 94 95// emit a driver from spec, run it on the sovereign emu; return 1 iff serial CONTAINS golden + 96// clean SiFive halt. golden read from <out>.gold; out path passed in. serialpath = scratch. 97func g_emit_run(spec: *u8, out: *u8, goldout: *u8, gbuf: *u8, gcap: i64, serialpath: *u8) -> i64 { 98 let est: i64 = g_run1(EMIT_ELF, spec, "/tmp/_drvproto_emit.out" as *u8) 99 if est != 0 { return 0 } 100 let gn: i64 = g_read(goldout, gbuf, gcap) 101 if gn <= 0 { return 0 } 102 gbuf[gn] = 0 as u8 103 let rst: i64 = g_run1(SOV_ELF, out, serialpath) 104 let sbuf: *u8 = sys_mmap(65536) 105 let sbn: i64 = g_read(serialpath, sbuf, 65536) 106 let has: i64 = g_buf_has(sbuf, sbn, gbuf, gn) 107 let halt: i64 = g_buf_has(sbuf, sbn, "BOOTSOV verdict=GREEN" as *u8, 21) 108 if rst == 0 { if has == 1 { if halt == 1 { return 1 } } } 109 return 0 110} 111 112// run the BLK image with byte[pos] bumped by 1; return 1 iff golden A is now ABSENT (tamper bites). 113func g_tamper(srcbin: *u8, pos: i64, golden: *u8, gn: i64, tampbin: *u8, serialpath: *u8) -> i64 { 114 let ibuf: *u8 = sys_mmap(16384) 115 let ibn: i64 = g_read(srcbin, ibuf, 16384) 116 if ibn <= pos { return 0 } 117 ibuf[pos] = (ibuf[pos] + 1) as u8 118 let tfd: i64 = sys_openat_wr(tampbin, 0x1a4) 119 if tfd < 0 { return 0 } 120 sys_write(tfd, ibuf, ibn); sys_close(tfd) 121 let rst: i64 = g_run1(SOV_ELF, tampbin, serialpath) 122 let sbuf: *u8 = sys_mmap(65536) 123 let sbn: i64 = g_read(serialpath, sbuf, 65536) 124 let has: i64 = g_buf_has(sbuf, sbn, golden, gn) 125 if has == 0 { return 1 } // golden gone -> tamper bites 126 return 0 127} 128 129func main() -> i64 { 130 g_p("=== driver-protocol-from-spec gate (X-DRV-W1: op-list spec -> emitted rv64 driver -> real virtio device on sovereign emu) ===\n" as *u8) 131 let lfd: i64 = sys_openat_append("knowledge/status/driver_spec.log" as *u8, 0x1a4) 132 133 let blk_out: *u8 = "runtime/_hdl_build/_drv_proto_blk.bin" as *u8 134 let blk_gold: *u8 = "runtime/_hdl_build/_drv_proto_blk.bin.gold" as *u8 135 let net_out: *u8 = "runtime/_hdl_build/_drv_proto_net.bin" as *u8 136 let net_gold: *u8 = "runtime/_hdl_build/_drv_proto_net.bin.gold" as *u8 137 138 let gA: *u8 = sys_mmap(2048) 139 let gB: *u8 = sys_mmap(2048) 140 141 // (1) BLK full register/ring/irq transaction on the sovereign emu. 142 let blk_ok: i64 = g_emit_run("knowledge/specs/drv_proto_blk_virt.spec" as *u8, blk_out, blk_gold, gA, 2048, "/tmp/_drvproto_blk_serial.txt" as *u8) 143 // (2) NET handshake (different device class, DeviceID=1) on the sovereign emu. 144 let net_ok: i64 = g_emit_run("knowledge/specs/drv_proto_net_virt.spec" as *u8, net_out, net_gold, gB, 2048, "/tmp/_drvproto_net_serial.txt" as *u8) 145 146 // (3) DISTINCT: two op-lists -> two different drivers (same emitter binary). 147 var distinct: i64 = 0 148 if g_strlen(gA) > 0 { if g_strlen(gB) > 0 { if g_streq(gA, gB) == 0 { distinct = 1 } } } 149 150 // (4) TAMPER x2 on the BLK image: device-base lui imm (byte 7) + magic-expected li high (byte 15). 151 let gAn: i64 = g_strlen(gA) 152 let t1: i64 = g_tamper(blk_out, 7, gA, gAn, "/tmp/_drvproto_t1.bin" as *u8, "/tmp/_drvproto_t1.txt" as *u8) 153 let t2: i64 = g_tamper(blk_out, 15, gA, gAn, "/tmp/_drvproto_t2.bin" as *u8, "/tmp/_drvproto_t2.txt" as *u8) 154 var tamper_bites: i64 = 0 155 if t1 == 1 { if t2 == 1 { tamper_bites = 1 } } 156 157 g_p(" blk_full_txn=" as *u8) 158 if blk_ok == 1 { g_p("GREEN(VIO..SECT: handshake+queue+descriptor+avail/used+status+sector roundtrip, clean halt)" as *u8) } else { g_p("RED" as *u8) } 159 g_p(" net_handshake=" as *u8) 160 if net_ok == 1 { g_p("GREEN(NET..RUN: DeviceID=1 @0x10002000, clean halt)" as *u8) } else { g_p("RED" as *u8) } 161 g_p(" distinct=" as *u8) 162 if distinct == 1 { g_p("yes(goldenA!=goldenB, same emitter binary)" as *u8) } else { g_p("no" as *u8) } 163 g_p(" tamper_bites=" as *u8) 164 if tamper_bites == 1 { g_p("yes(base-imm + magic-const corrupt -> golden drops)\n" as *u8) } else { g_p("no\n" as *u8) } 165 166 var pass: i64 = 0 167 if blk_ok == 1 { if net_ok == 1 { if distinct == 1 { if tamper_bites == 1 { pass = 1 } } } } 168 169 if pass == 1 { 170 g_p("DRVPROTOGATE verdict=GREEN (the GENERIC nx_drv_proto_emit synthesized a full virtio-blk register/ring/irq driver AND a virtio-net handshake driver from two op-list SPECS; BOTH completed against the real device models on the sovereign rv64 emu with clean halts; the protocol state machine is DATA-driven [distinct device classes from distinct op-lists]; two independent BLK tampers REJECTED -- driver-from-spec, author=emitter)\n" as *u8) 171 if lfd >= 0 { 172 g_fp(lfd, "DRVPROTOGATE verdict=GREEN keystone=driver-protocol-from-spec composes=emitter-of-emitters+HWMAP runtime=sovereign-emu transport=legacy-virtio-mmio blk_full_txn=VIO..SECT net_handshake=NET..RUN goldenA=" as *u8) 173 g_fp(lfd, gA); g_fp(lfd, " goldenB=" as *u8); g_fp(lfd, gB) 174 g_fp(lfd, " distinct=yes tamper=rejected(base-imm+magic-const) epoch=" as *u8); g_fn(lfd, sys_now_realtime_sec()); g_fp(lfd, "\n" as *u8); sys_close(lfd) 175 } 176 sys_exit(0); return 0 177 } 178 g_p("DRVPROTOGATE verdict=RED (blk_ok/net_ok/distinct/tamper not all green)\n" as *u8) 179 if lfd >= 0 { 180 g_fp(lfd, "DRVPROTOGATE verdict=RED blk_ok=" as *u8); g_fn(lfd, blk_ok) 181 g_fp(lfd, " net_ok=" as *u8); g_fn(lfd, net_ok) 182 g_fp(lfd, " distinct=" as *u8); g_fn(lfd, distinct) 183 g_fp(lfd, " t1=" as *u8); g_fn(lfd, t1); g_fp(lfd, " t2=" as *u8); g_fn(lfd, t2); g_fp(lfd, "\n" as *u8); sys_close(lfd) 184 } 185 sys_exit(1) 186 return 1 187}