code wiki / _hdl_build / _k_r2_001a_gate.nx
_k_r2_001a_gate.nx source
↩ module page · 287 lines · 13338 B
1// _k_r2_001a_gate.nx -- the K-R2-001a gate (virtio-MMIO transport HANDSHAKE). Drives the
2// full author->handshake chain with NO mocks: runs the REAL nx_virtio_hs_emit (the team
3// AUTHORS the rv64 handshake image + the TABLE-COMPUTED golden transcript from the spec),
4// then RUNS the image on the SOVEREIGN rv64 emulator (rv64im_min_sim with the new
5// rv64im_min_virtio device carved into load32/store32 -- the PRIMARY, gating lane: Nishi
6// owns the runtime) and asserts the captured serial transcript CONTAINS the emitter's
7// golden ("VIO ACK DRV FEAT OK\n" -- the driver verified magic/version/device-id, drove
8// Status through ACK/DRIVER/FEATURES_OK/DRIVER_OK, read HostFeatures, wrote GuestFeatures,
9// re-read Status to confirm FEATURES_OK stuck) AND the sovereign emu reports a clean
10// SiFive-finisher halt (BOOTSOV verdict=GREEN).
11//
12// Then the ALIGNMENT lane: qemu-system-riscv64 -machine virt -global
13// virtio-mmio.force-legacy=true with a REAL virtio-blk-device backing. qemu fills its
14// virtio-mmio slots in REVERSE (the blk device lands at the highest slot 0x10008000, not
15// the spec's sovereign base 0x10001000), so the gate authors a SECOND image from a derived
16// spec whose base = the qemu blk slot and runs THAT on qemu; the SAME handshake driver
17// completes against the REAL legacy virtio-blk transport and emits the SAME golden
18// transcript -> lanes AGREE on the handshake (alignment = handshake-completes-on-real-hw,
19// transcript-identical).
20//
21// Finally a TAMPER test: corrupt the magic-expected constant in the sovereign image -> the
22// driver's magic verify fails -> it branches PAST the whole handshake straight to the
23// finisher -> the transcript loses its golden -> the gate MUST go RED (proves the gate
24// bites, not a rubber stamp). Evidence -> knowledge/status/virtio_blk.log (VIRTGATE row;
25// the queue row's ||MARK= reads it). Sovereign orchestration (fork/dup3/execve/wait4).
26// license_tier: ORIGINAL
27import "nx_syscalls.nx"
28
29const G_QEMU_BASE: i64 = 0x10008000 // the slot qemu-virt assigns the first blk device
30
31func 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 }
32func 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 }
33func 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 }
34
35// run nx_virtio_hs_emit <spec>; return child wait status (0 = ok)
36func g_run_emit(spec: *u8) -> i64 {
37 let pid: i64 = sys_fork()
38 if pid == 0 {
39 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
40 if dn >= 0 { sys_dup3(dn, 1, 0) }
41 let argv: *i64 = sys_mmap(32) as *i64
42 argv[0] = "_offc/nx_virtio_hs_emit.elf" as *u8 as i64
43 argv[1] = spec as i64
44 argv[2] = 0
45 let envp: *i64 = sys_mmap(16) as *i64
46 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64
47 envp[1] = 0
48 sys_execve("_offc/nx_virtio_hs_emit.elf" as *u8, argv, envp)
49 sys_exit(127)
50 }
51 let st: *i64 = sys_mmap(16) as *i64
52 sys_wait4(pid, st, 0)
53 return st[0]
54}
55
56// run the SOVEREIGN rv64 emulator on binpath; serial -> outpath; return wait status
57func g_run_sov(binpath: *u8, outpath: *u8) -> i64 {
58 let pid: i64 = sys_fork()
59 if pid == 0 {
60 let ofd: i64 = sys_openat_wr(outpath, 0x1a4)
61 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) }
62 let argv: *i64 = sys_mmap(32) as *i64
63 argv[0] = "_offc/nx_boot_run_sov.elf" as *u8 as i64
64 argv[1] = binpath as i64
65 argv[2] = 0
66 let envp: *i64 = sys_mmap(16) as *i64
67 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64
68 envp[1] = 0
69 sys_execve("_offc/nx_boot_run_sov.elf" as *u8, argv, envp)
70 sys_exit(127)
71 }
72 let st: *i64 = sys_mmap(16) as *i64
73 sys_wait4(pid, st, 0)
74 return st[0]
75}
76
77// run qemu-system-riscv64 virt + legacy virtio-blk-device on binpath; serial -> outpath.
78// the backing image must exist; the gate creates a small raw file first via g_make_backing.
79func g_run_qemu(binpath: *u8, outpath: *u8, backing: *u8) -> i64 {
80 let pid: i64 = sys_fork()
81 if pid == 0 {
82 let ofd: i64 = sys_openat_wr(outpath, 0x1a4)
83 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) }
84 let argv: *i64 = sys_mmap(128) as *i64
85 argv[0] = "/usr/bin/qemu-system-riscv64" as *u8 as i64
86 argv[1] = "-machine" as *u8 as i64
87 argv[2] = "virt" as *u8 as i64
88 argv[3] = "-global" as *u8 as i64
89 argv[4] = "virtio-mmio.force-legacy=true" as *u8 as i64
90 argv[5] = "-nographic" as *u8 as i64
91 argv[6] = "-bios" as *u8 as i64
92 argv[7] = binpath as i64
93 argv[8] = "-drive" as *u8 as i64
94 argv[9] = "file=/tmp/_vqgate_backing.img,if=none,format=raw,id=hd0" as *u8 as i64
95 argv[10] = "-device" as *u8 as i64
96 argv[11] = "virtio-blk-device,drive=hd0" as *u8 as i64
97 argv[12] = 0
98 let envp: *i64 = sys_mmap(16) as *i64
99 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64
100 envp[1] = 0
101 sys_execve("/usr/bin/qemu-system-riscv64" as *u8, argv, envp)
102 sys_exit(127)
103 }
104 let st: *i64 = sys_mmap(16) as *i64
105 sys_wait4(pid, st, 0)
106 return st[0]
107}
108
109// create a small raw backing file for the qemu virtio-blk device (4 sectors of zeros).
110func g_make_backing(path: *u8) -> i64 {
111 let fd: i64 = sys_openat_wr(path, 0x1a4)
112 if fd < 0 { return 0 - 1 }
113 let z: *u8 = sys_mmap(2048)
114 var i: i64 = 0
115 while i < 2048 { z[i] = 0 as u8; i = i + 1 }
116 sys_write(fd, z, 2048)
117 sys_close(fd)
118 return 0
119}
120
121// read whole file into buf (cap-1 max); return byte count (0 if absent)
122func g_read(path: *u8, buf: *u8, cap: i64) -> i64 {
123 let fd: i64 = sys_openat_rd(path)
124 if fd < 0 { return 0 }
125 var n: i64 = 0
126 var go: i64 = 1
127 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 } }
128 sys_close(fd)
129 return n
130}
131
132// does buf[0,n) contain pat (length pl)? 1/0
133func g_buf_has(buf: *u8, n: i64, pat: *u8, pl: i64) -> i64 {
134 if pl <= 0 { return 0 }
135 var i: i64 = 0
136 while i + pl <= n {
137 var k: i64 = 0
138 var hit: i64 = 1
139 while k < pl { if buf[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } }
140 if hit == 1 { return 1 }
141 i = i + 1
142 }
143 return 0
144}
145
146func g_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
147
148// does line [ls,le) of buf begin with key? 1/0
149func g_line_is(buf: *u8, ls: i64, le: i64, key: *u8) -> i64 {
150 var k: i64 = 0
151 while key[k] != (0 as u8) {
152 if ls + k >= le { return 0 }
153 if buf[ls + k] != key[k] { return 0 }
154 k = k + 1
155 }
156 return 1
157}
158
159// author the qemu-alignment spec: copy the main spec, but replace the `base ` line value
160// with G_QEMU_BASE and the `out ` line with the qemu image path. Writes derived spec.
161func g_write_qemu_spec(mainspec: *u8, derived: *u8, qemu_out: *u8) -> i64 {
162 let buf: *u8 = sys_mmap(8192)
163 let n: i64 = g_read(mainspec, buf, 8192)
164 if n <= 0 { return 0 - 1 }
165 let ofd: i64 = sys_openat_wr(derived, 0x1a4)
166 if ofd < 0 { return 0 - 1 }
167 var ls: i64 = 0
168 while ls < n {
169 var le: i64 = ls
170 var scan: i64 = 1
171 while scan == 1 { if le >= n { scan = 0 } else { if buf[le] == (10 as u8) { scan = 0 } else { le = le + 1 } } }
172 // [ls,le) is one line (without newline). Rewrite base/out lines.
173 if g_line_is(buf, ls, le, "base " as *u8) == 1 {
174 g_fp(ofd, "base 0x10008000\n" as *u8)
175 } else {
176 if g_line_is(buf, ls, le, "out " as *u8) == 1 {
177 g_fp(ofd, "out " as *u8); g_fp(ofd, qemu_out); g_fp(ofd, "\n" as *u8)
178 } else {
179 sys_write(ofd, (buf as i64 + ls) as *u8, le - ls)
180 g_fp(ofd, "\n" as *u8)
181 }
182 }
183 ls = le + 1
184 }
185 sys_close(ofd)
186 return 0
187}
188
189func main() -> i64 {
190 let spec: *u8 = "knowledge/specs/virtio_blk_handshake_virt.spec" as *u8
191 let binpath: *u8 = "runtime/_hdl_build/_virtio_hs_virt.bin" as *u8
192 let goldpath: *u8 = "runtime/_hdl_build/_virtio_hs_virt.bin.gold" as *u8
193 let qemu_spec: *u8 = "/tmp/_vqgate_qemu.spec" as *u8
194 let qemu_bin: *u8 = "/tmp/_vqgate_qemu.bin" as *u8
195 let backing: *u8 = "/tmp/_vqgate_backing.img" as *u8
196 let tamper_bin: *u8 = "/tmp/_vqgate_tamper.bin" as *u8
197 let sov_serial: *u8 = "/tmp/_vqgate_sov.txt" as *u8
198 let qemu_serial: *u8 = "/tmp/_vqgate_qemu.txt" as *u8
199 let sov_tamper: *u8 = "/tmp/_vqgate_sov_tamper.txt" as *u8
200 g_p("=== virtio-MMIO handshake gate (K-R2-001a: SOVEREIGN rv64 transport + qemu virtio-blk alignment) ===\n" as *u8)
201
202 let lfd: i64 = sys_openat_append("knowledge/status/virtio_blk.log" as *u8, 0x1a4)
203
204 // STEP 1: author the SOVEREIGN handshake image (base 0x10001000) + the golden transcript.
205 let est: i64 = g_run_emit(spec)
206 if est != 0 {
207 g_p("VIRTGATE verdict=RED reason=emit-failed\n" as *u8)
208 if lfd >= 0 { g_fp(lfd, "VIRTGATE verdict=RED reason=emit-failed\n" as *u8); sys_close(lfd) }
209 sys_exit(1); return 1
210 }
211 let gold: *u8 = sys_mmap(512)
212 let gn: i64 = g_read(goldpath, gold, 512)
213 gold[gn] = 0 as u8
214 if gn <= 0 {
215 g_p("VIRTGATE verdict=RED reason=golden-missing\n" as *u8)
216 if lfd >= 0 { g_fp(lfd, "VIRTGATE verdict=RED reason=golden-missing\n" as *u8); sys_close(lfd) }
217 sys_exit(1); return 1
218 }
219
220 // STEP 2 (PRIMARY): the Nishi sovereign rv64 emulator RUNS the handshake image.
221 let sst: i64 = g_run_sov(binpath, sov_serial)
222 let sbuf: *u8 = sys_mmap(65536)
223 let sbn: i64 = g_read(sov_serial, sbuf, 65536)
224 let trans_ok: i64 = g_buf_has(sbuf, sbn, gold, gn) // serial CONTAINS golden
225 let halt_ok: i64 = g_buf_has(sbuf, sbn, "BOOTSOV verdict=GREEN" as *u8, 21)
226 var sov_ok: i64 = 0
227 if sst == 0 { if trans_ok == 1 { if halt_ok == 1 { sov_ok = 1 } } }
228
229 // STEP 3 (ALIGNMENT): author the qemu-base image (slot 0x10008000) + run qemu with a
230 // REAL legacy virtio-blk-device; assert the SAME golden transcript appears (lanes agree).
231 g_make_backing(backing)
232 g_write_qemu_spec(spec, qemu_spec, qemu_bin)
233 let qest: i64 = g_run_emit(qemu_spec)
234 var align: i64 = 0
235 if qest == 0 {
236 let qst: i64 = g_run_qemu(qemu_bin, qemu_serial, backing)
237 let qbuf: *u8 = sys_mmap(65536)
238 let qbn: i64 = g_read(qemu_serial, qbuf, 65536)
239 let qtrans: i64 = g_buf_has(qbuf, qbn, gold, gn)
240 if qst == 0 { if qtrans == 1 { align = 1 } }
241 }
242
243 // STEP 4 (TAMPER): corrupt the magic-expected constant in the sovereign image. Image
244 // layout (emitter-known): word0 lui t0, word1 lui t2, then verify_magic = lw(word2) +
245 // li-expected(words3-4) + bne(word5). The magic-expected li is at bytes 12..19; bump a
246 // byte of it so expected != 0x74726976 -> the magic verify fails -> driver jumps to the
247 // finisher -> transcript loses its golden. Gate MUST then go RED.
248 let ibuf: *u8 = sys_mmap(8192)
249 let ibn: i64 = g_read(binpath, ibuf, 8192)
250 ibuf[14] = (ibuf[14] + 1) as u8
251 let tfd: i64 = sys_openat_wr(tamper_bin, 0x1a4)
252 if tfd >= 0 { sys_write(tfd, ibuf, ibn); sys_close(tfd) }
253 let tst: i64 = g_run_sov(tamper_bin, sov_tamper)
254 let tbuf: *u8 = sys_mmap(65536)
255 let tbn: i64 = g_read(sov_tamper, tbuf, 65536)
256 let tamper_trans: i64 = g_buf_has(tbuf, tbn, gold, gn) // should now MISS
257 var tamper_bites: i64 = 0
258 if tamper_trans == 0 { tamper_bites = 1 }
259
260 g_p(" sovereign_emu=" as *u8)
261 if sov_ok == 1 { g_p("GREEN(transcript==golden+clean-halt)" as *u8) } else { g_p("RED" as *u8) }
262 g_p(" qemu_align=" as *u8)
263 if align == 1 { g_p("yes(real-virtio-blk @0x10008000)" as *u8) } else { g_p("no" as *u8) }
264 g_p(" tamper_bites=" as *u8)
265 if tamper_bites == 1 { g_p("yes\n" as *u8) } else { g_p("no\n" as *u8) }
266
267 var pass: i64 = 0
268 if sov_ok == 1 { if align == 1 { if tamper_bites == 1 { pass = 1 } } }
269
270 if pass == 1 {
271 g_p("VIRTGATE verdict=GREEN (sovereign rv64 emu drove the virtio-MMIO transport handshake; transcript==golden; clean halt; qemu virtio-blk-device cross-check AGREES; tamper REJECTED)\n" as *u8)
272 if lfd >= 0 {
273 g_fp(lfd, "VIRTGATE verdict=GREEN runtime=sovereign-emu transport=legacy-virtio-mmio device-id=2 handshake=ACK|DRIVER|FEATURES_OK|DRIVER_OK transcript==golden align_qemu=yes(virtio-blk-device) tamper=rejected golden=" as *u8)
274 g_fp(lfd, gold)
275 g_fp(lfd, " epoch=" as *u8); g_fn(lfd, sys_now_realtime_sec()); g_fp(lfd, "\n" as *u8); sys_close(lfd)
276 }
277 sys_exit(0); return 0
278 }
279 g_p("VIRTGATE verdict=RED (sov_ok/align/tamper not all green)\n" as *u8)
280 if lfd >= 0 {
281 g_fp(lfd, "VIRTGATE verdict=RED sov_ok=" as *u8); g_fn(lfd, sov_ok)
282 g_fp(lfd, " align=" as *u8); g_fn(lfd, align)
283 g_fp(lfd, " tamper_bites=" as *u8); g_fn(lfd, tamper_bites); g_fp(lfd, "\n" as *u8); sys_close(lfd)
284 }
285 sys_exit(1)
286 return 1
287}