code wiki / _hdl_build / _mmu_gate.nx
_mmu_gate.nx source
↩ module page · 204 lines · 11540 B
1// _mmu_gate.nx -- gate for the Sv39 PAGE-TABLE-WALK device (virtual-memory-paging-mmu). NO mocks.
2//
3// (1) WALK WORKS -- emits the MMU driver (via nx_drv_proto_emit) + runs it on the sovereign emu:
4// it lays a Sv39 gigapage page table, programs satp, and the device WALKS the table -> the
5// mapped VA 0xC0009000 translates to PA 0x80009000 ("MAP") and an unmapped VA faults ("FLT").
6// Serial must contain "MAPFLT" + a clean halt.
7// (2) TAMPER device-base -- bump the device-base lui imm (byte 7): the MMU regs are missed, the
8// walk never runs, "MAP" drops (the driver really talks to the MMU device).
9// (3) TAMPER bad-PTE -- run the variant whose leaf PTE has V=0: the mapped VA walk FAULTS, the
10// PADDR verify fails, "MAP" drops -> the Sv39 walk genuinely reads + validates the page table
11// (translation is not a rubber stamp).
12//
13// Evidence -> knowledge/status/mmu.log (MMUGATE row). Sovereign. license_tier: ORIGINAL
14import "nx_syscalls.nx"
15import "nx_gate_verdict.nx"
16
17const M_EMIT: *u8 = "_offc/nx_drv_proto_emit.elf"
18const M_SOV: *u8 = "_offc/nx_boot_run_sov.elf"
19const M_SPEC: *u8 = "knowledge/specs/drv_proto_mmu.spec"
20const M_BIN: *u8 = "runtime/_hdl_build/_drv_proto_mmu.bin"
21const M_BADSPEC: *u8 = "knowledge/specs/drv_proto_mmu_badpte.spec"
22const M_BADBIN: *u8 = "runtime/_hdl_build/_drv_proto_mmu_badpte.bin"
23
24func 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 }
25func 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 }
26func g_fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" as *u8,1)}; 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 }
27
28func g_run(prog: *u8, a1: *u8, outpath: *u8) -> i64 {
29 let pid: i64 = sys_fork()
30 if pid == 0 {
31 if outpath != (0 as *u8) { let ofd: i64 = sys_openat_wr(outpath, 0x1a4); if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) } }
32 let argv: *i64 = sys_mmap(32) as *i64
33 argv[0] = prog as i64
34 var k: i64 = 1
35 if a1 != (0 as *u8) { argv[k] = a1 as i64; k = k + 1 }
36 argv[k] = 0
37 let envp: *i64 = sys_mmap(16) as *i64
38 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
39 sys_execve(prog, argv, envp)
40 sys_exit(127)
41 }
42 let st: *i64 = sys_mmap(16) as *i64
43 sys_wait4(pid, st, 0)
44 let sg: i64 = st[0] & 0x7f
45 if sg != 0 { return 128 + sg }
46 return (st[0] >> 8) & 0xff
47}
48
49func g_read(path: *u8, buf: *u8, cap: i64) -> i64 {
50 let fd: i64 = sys_openat_rd(path)
51 if fd < 0 { return 0 }
52 var n: i64 = 0
53 var go: i64 = 1
54 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 } }
55 sys_close(fd)
56 return n
57}
58
59func g_has(buf: *u8, n: i64, pat: *u8, pl: i64) -> i64 {
60 if pl <= 0 { return 0 }
61 var i: i64 = 0
62 while i + pl <= n { var k: i64=0; var hit: i64=1; while k<pl { if buf[i+k]!=pat[k]{hit=0;k=pl}else{k=k+1} } if hit==1 { return 1 } i=i+1 }
63 return 0
64}
65
66func g_emit_run(spec: *u8, bin: *u8, serial: *u8) -> i64 {
67 if g_run(M_EMIT, spec, "/tmp/_mmu_emit.out" as *u8) != 0 { return 0 }
68 g_run(M_SOV, bin, serial)
69 let sb: *u8 = sys_mmap(65536); let sn: i64 = g_read(serial, sb, 65536)
70 let halt: i64 = g_has(sb, sn, "BOOTSOV verdict=GREEN" as *u8, 21)
71 let mapflt: i64 = g_has(sb, sn, "MAPFLT" as *u8, 6)
72 if halt == 1 { if mapflt == 1 { return 1 } }
73 return 0
74}
75
76// Scan ONLY the emulator's serial line for `pat`. Returns 1=present, 0=absent, -1=NO SERIAL LINE.
77//
78// ★FIXED 2026-08-07. This used to grep the WHOLE captured file. That is unsafe by construction:
79// on a transcript mismatch nx_boot_run_sov prints the EXPECTED GOLDEN INLINE --
80// BOOTSOV verdict=RED reason=transcript-mismatch ... expected=[MAPFLT] got=[]
81// -- so a whole-file search for "MAP" finds the EMULATOR'S OWN DIAGNOSTIC and an absence tooth
82// INVERTS. MEASURED: tooth 3 (bad-PTE) read FAIL for exactly this reason while the driver was
83// behaving perfectly -- the serial really was empty, and the word MAP the tooth found was the
84// runner quoting what it had hoped to see.
85// A DETECTOR THAT GREPS A WHOLE LOG FOR A TOKEN BREAKS THE DAY THE LOG STARTS QUOTING THAT TOKEN.
86//
87// -1 is deliberately DISTINCT from 0: "I could not find the serial line" is not "the token was
88// absent". Every caller below tests `== 0`, so a -1 never silently credits an absence tooth.
89func g_serial_has(serial: *u8, pat: *u8, pl: i64) -> i64 {
90 if pl <= 0 { return 0 - 1 }
91 let sb: *u8 = sys_mmap(65536); let sn: i64 = g_read(serial, sb, 65536)
92 let key: *u8 = "SOVEREIGN-EMU serial: " as *u8
93 var kl: i64 = 0
94 while key[kl] != (0 as u8) { kl = kl + 1 }
95 var i: i64 = 0
96 var start: i64 = 0 - 1
97 var scan: i64 = 1
98 while scan == 1 {
99 if i + kl > sn { scan = 0 } else {
100 var k: i64 = 0
101 var hit: i64 = 1
102 while k < kl { if sb[i+k] != key[k] { hit = 0; k = kl } else { k = k + 1 } }
103 if hit == 1 { start = i + kl; scan = 0 } else { i = i + 1 }
104 }
105 }
106 if start < 0 { return 0 - 1 }
107 var e: i64 = start
108 var go: i64 = 1
109 while go == 1 {
110 if e >= sn { go = 0 } else {
111 if sb[e] == (10 as u8) { go = 0 } else { e = e + 1 }
112 }
113 }
114 var j: i64 = start
115 while j + pl <= e {
116 var k2: i64 = 0
117 var h2: i64 = 1
118 while k2 < pl { if sb[j+k2] != pat[k2] { h2 = 0; k2 = pl } else { k2 = k2 + 1 } }
119 if h2 == 1 { return 1 }
120 j = j + 1
121 }
122 return 0
123}
124
125func g_has_map(serial: *u8) -> i64 {
126 return g_serial_has(serial, "MAP" as *u8, 3)
127}
128
129func main() -> i64 {
130 g_p("=== Sv39 page-table-walk gate (virtual-memory-paging-mmu) ===\n" as *u8)
131 let lfd: i64 = sys_openat_append("knowledge/status/mmu.log" as *u8, 0x1a4)
132
133 // (1) walk works: mapped VA translates (MAP) + unmapped faults (FLT)
134 let walk_ok: i64 = g_emit_run(M_SPEC, M_BIN, "/tmp/_mmu_main.txt" as *u8)
135
136 // (2) tamper device base (byte 7): MMU regs missed -> MAP drops
137 let ib: *u8 = sys_mmap(16384); let ibn: i64 = g_read(M_BIN, ib, 16384)
138 var t1: i64 = 0
139 if ibn > 7 {
140 ib[7] = (ib[7] + 1) as u8
141 let tfd: i64 = sys_openat_wr("/tmp/_mmu_t1.bin" as *u8, 0x1a4)
142 if tfd >= 0 { sys_write(tfd, ib, ibn); sys_close(tfd) }
143 g_run(M_SOV, "/tmp/_mmu_t1.bin" as *u8, "/tmp/_mmu_t1.txt" as *u8)
144 // ANTI-VACUITY 2026-08-06 (see the longer note on tooth 3): a tooth that asserts an ABSENCE
145 // passes loudest when nothing ran. Only credit a disappearance we can prove we CAUSED: the
146 // baseline must have worked, and this tamper run must have produced a serial transcript.
147 let t1b: *u8 = sys_mmap(65536)
148 let t1n: i64 = g_read("/tmp/_mmu_t1.txt" as *u8, t1b, 65536)
149 if walk_ok == 1 { if t1n > 0 { if g_has_map("/tmp/_mmu_t1.txt" as *u8) == 0 { t1 = 1 } } }
150 }
151
152 // (3) tamper bad-PTE variant: leaf PTE V=0 -> mapped VA faults -> MAP drops
153 let bad_emit: i64 = g_run(M_EMIT, M_BADSPEC, "/tmp/_mmu_bad_emit.out" as *u8)
154 g_run(M_SOV, M_BADBIN, "/tmp/_mmu_bad.txt" as *u8)
155 var t2: i64 = 0
156 // ANTI-VACUITY 2026-08-06. This tooth asserts an ABSENCE -- "MAP is gone" -- so it scores PASS
157 // MAXIMALLY when nothing executed at all. MEASURED: knowledge/specs/drv_proto_mmu_badpte.spec and
158 // drv_proto_mmu.spec are BOTH ABSENT, so the emit fails, _drv_proto_mmu_badpte.bin is never built,
159 // /tmp/_mmu_bad.txt is never written -- and the old form read that empty nothing, found no "MAP",
160 // and reported PASS. The gate therefore scored 1/3 while its true state was 0/3-cannot-run, and the
161 // one tooth it credited was the one that had proven the least.
162 // A TOOTH THAT ASSERTS AN ABSENCE PASSES LOUDEST WHEN NOTHING RAN AT ALL. It may only credit a
163 // disappearance it can prove it CAUSED: the baseline worked, the emit succeeded, and this run
164 // actually produced a transcript.
165 var bad_ran: i64 = 0
166 let bb2: *u8 = sys_mmap(65536)
167 let bn2: i64 = g_read("/tmp/_mmu_bad.txt" as *u8, bb2, 65536)
168 if bad_emit == 0 { if bn2 > 0 { bad_ran = 1 } }
169 if walk_ok == 1 { if bad_ran == 1 { if g_has_map("/tmp/_mmu_bad.txt" as *u8) == 0 { t2 = 1 } } }
170
171 g_p(" walk_works=" as *u8); if walk_ok==1 { g_p("GREEN(MAP=mapped-VA->PA, FLT=unmapped-faults)" as *u8) } else { g_p("RED" as *u8) }
172 g_p(" tamper_base=" as *u8); g_fn(1, t1); g_p(" tamper_badpte=" as *u8); g_fn(1, t2); g_p("\n" as *u8)
173
174 // ---- D001 MIGRATION 2026-08-06 -- IDIOM G: BOOLEAN CONJUNCTION, NO COUNTER --------------------
175 // This gate scored a boolean AND-chain into ONE flag and printed its own verdict, so nx_gate_green
176 // could not judge it, it recorded no harness frame, and /api/promote refused it -- which in turn
177 // stranded its registry row on an unpromoted .sov.elf.new (the stagedref class).
178 // nx_gate_dry_apply SKIPS this shape with "counter idiom not recognised", and the reason is
179 // STRUCTURAL: idioms A-F all assume a pass/total COUNTER PAIR to map onto ctr[0]/ctr[1], and this
180 // gate HAS NO COUNTER AT ALL. Measured 2026-08-06: 8 of 8 D001-blocked gates skip -- 6 for exactly
181 // this reason -- so "migrate it" was a remedy with no automated path for this whole family.
182 // THE FAITHFUL MAPPING IS ONE gv_check PER CONJUNCT: that CREATES the counter, and gv_verdict is
183 // GREEN iff pass==total, which is precisely the old `walk_ok && t1 && t2`. The three teeth below are
184 // the SAME three conditions computed above -- NO test logic changed, only who reports the verdict.
185 let ctr: *i64 = gv_ctr()
186 gv_check("T1 Sv39 walk works (mapped VA 0xC0009000 -> PA 0x80009000 [MAP]; unmapped VA FAULTS [FLT])" as *u8, walk_ok, ctr)
187 gv_check("T2 tamper device-base REJECTED (bumped lui imm -> MMU regs missed -> MAP drops)" as *u8, t1, ctr)
188 gv_check("T3 tamper bad-PTE REJECTED (leaf PTE V=0 -> mapped VA faults -> MAP drops)" as *u8, t2, ctr)
189 let rc: i64 = gv_verdict("MMUGATE" as *u8, ctr, "sovereign Sv39 page-table walk: programmed satp + a gigapage page table in guest RAM; the MMU WALKED the 3-level table, translated the mapped VA 0xC0009000 -> PA 0x80009000 [MAP] and FAULTED an unmapped VA [FLT]; device-base and bad-PTE[V=0] tampers both drop MAP, so the walk genuinely reads+validates the page table. probe=virtual-memory-paging" as *u8)
190 // The knowledge/status/mmu.log evidence row is PRESERVED in both branches, byte-for-byte with the
191 // pre-migration text. The rollup reads that file; a migration that quietly stopped writing it would
192 // have traded a D001 refusal for an INVISIBLE gate, which is a strictly worse outcome.
193 if lfd >= 0 {
194 if rc == 0 {
195 g_fp(lfd, "MMUGATE verdict=GREEN keystone=virtual-memory-paging probe=mmu_paging sv39-walk=3-level mapped=0xC0009000->0x80009000 fault=unmapped tamper=rejected(base+badpte) epoch=" as *u8); g_fn(lfd, sys_now_realtime_sec()); g_fp(lfd, "\n" as *u8)
196 }
197 if rc != 0 {
198 g_fp(lfd, "MMUGATE verdict=RED walk=" as *u8); g_fn(lfd, walk_ok); 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)
199 }
200 sys_close(lfd)
201 }
202 sys_exit(rc)
203 return rc
204}