code wiki / _hdl_build / _timer_irq_gate.nx
_timer_irq_gate.nx source
↩ module page · 137 lines · 7507 B
1// _timer_irq_gate.nx -- gate for the TIMER-INTERRUPT (preemption mechanism) slice.
2// NO mocks: runs the REAL nx_timer_irq_emit (team AUTHORS the rv64 image + TABLE-COMPUTED
3// golden "BT"), RUNS it on the SOVEREIGN rv64 emu (PRIMARY: Nishi owns the runtime), asserts
4// the serial CONTAINS the golden (B=boot, T=timer-interrupt handler ran) AND a clean finisher
5// halt (BOOTSOV verdict=GREEN). Then a TAMPER: zero the mie.MTIE-enable immediate -> the CPU
6// never takes the timer trap -> the handler never runs -> 'T' disappears -> the gate MUST go RED
7// (proves the gate bites, not a rubber stamp -- the timer interrupt is REALLY what produces T).
8// Evidence -> knowledge/status/timer_irq.log (TIMERIRQGATE row). Sovereign orchestration.
9// license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_gate_verdict.nx"
12
13func 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 }
14func 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 }
15func 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 }
16
17func g_run1(prog: *u8, arg1: *u8, outpath: *u8) -> i64 {
18 let pid: i64 = sys_fork()
19 if pid == 0 {
20 if outpath != (0 as *u8) {
21 let ofd: i64 = sys_openat_wr(outpath, 0x1a4)
22 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) }
23 } else {
24 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
25 if dn >= 0 { sys_dup3(dn, 1, 0) }
26 }
27 let argv: *i64 = sys_mmap(32) as *i64
28 argv[0] = prog as i64
29 if arg1 != (0 as *u8) { argv[1] = arg1 as i64; argv[2] = 0 } else { argv[1] = 0 }
30 let envp: *i64 = sys_mmap(16) as *i64
31 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
32 sys_execve(prog, argv, envp)
33 sys_exit(127)
34 }
35 let st: *i64 = sys_mmap(16) as *i64
36 sys_wait4(pid, st, 0)
37 return st[0]
38}
39
40func g_read(path: *u8, buf: *u8, cap: i64) -> i64 {
41 let fd: i64 = sys_openat_rd(path)
42 if fd < 0 { return 0 }
43 var n: i64 = 0
44 var go: i64 = 1
45 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 } }
46 sys_close(fd)
47 return n
48}
49
50func g_buf_has(buf: *u8, n: i64, pat: *u8, pl: i64) -> i64 {
51 if pl <= 0 { return 0 }
52 var i: i64 = 0
53 while i + pl <= n {
54 var k: i64 = 0
55 var hit: i64 = 1
56 while k < pl { if buf[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } }
57 if hit == 1 { return 1 }
58 i = i + 1
59 }
60 return 0
61}
62
63func main() -> i64 {
64 let binpath: *u8 = "runtime/_hdl_build/_timer_irq_virt.bin" as *u8
65 let goldpath: *u8 = "runtime/_hdl_build/_timer_irq_virt.bin.gold" as *u8
66 let tamper_bin: *u8 = "/tmp/_timergate_tamper.bin" as *u8
67 let sov_serial: *u8 = "/tmp/_timergate_sov.txt" as *u8
68 let sov_tamper: *u8 = "/tmp/_timergate_sov_tamper.txt" as *u8
69 g_p("=== timer-interrupt gate (preemption mechanism: SOVEREIGN rv64 emu + tamper) ===\n" as *u8)
70 let lfd: i64 = sys_openat_append("knowledge/status/timer_irq.log" as *u8, 0x1a4)
71
72 // 1. AUTHOR the image + golden (the team's emitter, no mocks).
73 // 2026-08-06 LM-026: this fork named /tmp/nx_timer_irq_emit.sov.elf -- the VOLATILE build-time twin,
74 // cleared on idle -- while every other fork in this same file already used _offc/. So the moment /tmp
75 // was cleaned the gate could never emit again and reported reason=emit-failed forever, indicting the
76 // kernel for a missing temp file. The emitter itself was never broken: run directly it still writes
77 // _timer_irq_virt.bin (84 B, golden=BT). A GATE THAT FORKS A BUILD-TIME TEMP PATH STOPS TESTING THE
78 // MOMENT THE TEMP IS CLEARED, AND BLAMES ITS SUBJECT.
79 let est: i64 = g_run1("_offc/nx_timer_irq_emit.elf" as *u8, 0 as *u8, 0 as *u8)
80 if est != 0 {
81 g_p("TIMERIRQGATE verdict=RED reason=emit-failed\n" as *u8)
82 if lfd >= 0 { g_fp(lfd, "TIMERIRQGATE verdict=RED reason=emit-failed\n" as *u8); sys_close(lfd) }
83 sys_exit(1); return 1
84 }
85 let gold: *u8 = sys_mmap(64)
86 let gn: i64 = g_read(goldpath, gold, 64)
87 gold[gn] = 0 as u8
88
89 // 2. PRIMARY: sovereign emu runs the image; serial CONTAINS golden + clean finisher halt.
90 let sst: i64 = g_run1("_offc/nx_boot_run_sov.elf" as *u8, binpath, sov_serial)
91 let sbuf: *u8 = sys_mmap(65536)
92 let sbn: i64 = g_read(sov_serial, sbuf, 65536)
93 let trans_ok: i64 = g_buf_has(sbuf, sbn, gold, gn)
94 let halt_ok: i64 = g_buf_has(sbuf, sbn, "BOOTSOV verdict=GREEN" as *u8, 21)
95 var sov_ok: i64 = 0
96 if sst == 0 { if trans_ok == 1 { if halt_ok == 1 { sov_ok = 1 } } }
97
98 // 3. TAMPER: zero the mie.MTIE-enable immediate (addi t1,x0,0x80 at byte 36; imm byte=39).
99 // Without MTIE the CPU never takes the timer trap -> handler never runs -> 'T' vanishes.
100 let ibuf: *u8 = sys_mmap(8192)
101 let ibn: i64 = g_read(binpath, ibuf, 8192)
102 ibuf[36 + 3] = 0 as u8
103 let tfd: i64 = sys_openat_wr(tamper_bin, 0x1a4)
104 if tfd >= 0 { sys_write(tfd, ibuf, ibn); sys_close(tfd) }
105 let tst: i64 = g_run1("_offc/nx_boot_run_sov.elf" as *u8, tamper_bin, sov_tamper)
106 let tbuf: *u8 = sys_mmap(65536)
107 let tbn: i64 = g_read(sov_tamper, tbuf, 65536)
108 let tamper_trans: i64 = g_buf_has(tbuf, tbn, gold, gn)
109 var tamper_bites: i64 = 0
110 if tamper_trans == 0 { tamper_bites = 1 }
111
112 g_p(" sovereign_emu=" as *u8)
113 if sov_ok == 1 { g_p("GREEN(serial-contains-BT+clean-halt)" as *u8) } else { g_p("RED" as *u8) }
114 g_p(" tamper_bites=" as *u8)
115 if tamper_bites == 1 { g_p("yes\n" as *u8) } else { g_p("no\n" as *u8) }
116
117 // ---- D001 MIGRATION 2026-08-06 -- IDIOM G (boolean conjunction, no counter) -------------------
118 // Fifth of the family; see _mmu_gate for the full reasoning. ONE gv_check PER CONJUNCT creates the
119 // counter that idioms A-F assume exists, and gv_verdict is GREEN iff pass==total -- exactly the old
120 // `sov_ok && tamper_bites`. Teeth unchanged; only the verdict reporter moves to the base class.
121 let ctr: *i64 = gv_ctr()
122 gv_check("T1 sovereign rv64 emu delivers+handles the timer interrupt (serial contains the table-computed golden BT, clean halt)" as *u8, sov_ok, ctr)
123 gv_check("T2 tamper BITES (the mutated image no longer produces the golden) -- proves the serial match is load-bearing, not incidental" as *u8, tamper_bites, ctr)
124 let rc: i64 = gv_verdict("TIMERIRQGATE" as *u8, ctr, "sovereign rv64 emu: timer interrupt delivered and handled, serial == golden BT, clean halt; tamper REJECTED. mechanism=clint-mtip-trap" as *u8)
125 // knowledge/status evidence row PRESERVED in both branches -- the rollup reads it.
126 if lfd >= 0 {
127 if rc == 0 {
128 g_fp(lfd, "TIMERIRQGATE verdict=GREEN runtime=sovereign-emu serial==golden=BT mechanism=clint-mtip-trap tamper=rejected epoch=" as *u8); g_fn(lfd, sys_now_realtime_sec()); g_fp(lfd, "\n" as *u8)
129 }
130 if rc != 0 {
131 g_fp(lfd, "TIMERIRQGATE verdict=RED sov_ok=" as *u8); g_fn(lfd, sov_ok); g_fp(lfd, " tamper_bites=" as *u8); g_fn(lfd, tamper_bites); g_fp(lfd, "\n" as *u8)
132 }
133 sys_close(lfd)
134 }
135 sys_exit(rc)
136 return rc
137}