code wiki / _hdl_build / _sched_gate.nx

_sched_gate.nx source

↩ module page · 114 lines · 6514 B

1// _sched_gate.nx -- gate for the 2-task PREEMPTIVE SCHEDULER slice. 2// NO mocks: runs the REAL nx_sched_emit, RUNS the image on the SOVEREIGN rv64 emu, and asserts a 3// STRUCTURAL property honest for a preemptive phenomenon: the serial has boot 'S' + BOTH task 4// markers 'A' and 'B' in MANY alternating runs (>=8 A<->B transitions = the scheduler preempted + 5// context-switched repeatedly) + a clean finisher halt. Then TAMPER: zero the mie.MTIE-enable byte 6// -> no timer -> no preemption -> task A loops alone -> 'B' never appears, transitions collapse -> 7// the gate MUST go RED (proves the SWITCHING is really timer-preemption, not a rubber stamp). 8// Evidence -> knowledge/status/sched.log (SCHEDGATE row). license_tier: ORIGINAL 9import "nx_syscalls.nx" 10 11func 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 } 12func 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 } 13func 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 } 14 15func g_run1(prog: *u8, arg1: *u8, outpath: *u8) -> i64 { 16 let pid: i64 = sys_fork() 17 if pid == 0 { 18 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) } } 19 else { let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4); if dn >= 0 { sys_dup3(dn, 1, 0) } } 20 let argv: *i64 = sys_mmap(32) as *i64 21 argv[0] = prog as i64 22 if arg1 != (0 as *u8) { argv[1] = arg1 as i64; argv[2] = 0 } else { argv[1] = 0 } 23 let envp: *i64 = sys_mmap(16) as *i64 24 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 25 sys_execve(prog, argv, envp) 26 sys_exit(127) 27 } 28 let st: *i64 = sys_mmap(16) as *i64 29 sys_wait4(pid, st, 0) 30 return st[0] 31} 32 33func g_read(path: *u8, buf: *u8, cap: i64) -> i64 { 34 let fd: i64 = sys_openat_rd(path) 35 if fd < 0 { return 0 } 36 var n: i64 = 0 37 var go: i64 = 1 38 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 } } 39 sys_close(fd) 40 return n 41} 42 43func g_has(buf: *u8, n: i64, ch: i64) -> i64 { var i: i64=0; while i<n { if buf[i]==(ch as u8) { return 1 } i=i+1 } return 0 } 44 45// count A<->B transitions (adjacent chars both in {A,B} and differing). 46func g_transitions(buf: *u8, n: i64) -> i64 { 47 var c: i64 = 0 48 var i: i64 = 0 49 while i + 1 < n { 50 let a: i64 = buf[i] as i64 51 let b: i64 = buf[i+1] as i64 52 var aok: i64 = 0; if a == 65 { aok = 1 } if a == 66 { aok = 1 } 53 var bok: i64 = 0; if b == 65 { bok = 1 } if b == 66 { bok = 1 } 54 if aok == 1 { if bok == 1 { if a != b { c = c + 1 } } } 55 i = i + 1 56 } 57 return c 58} 59 60func main() -> i64 { 61 let binpath: *u8 = "runtime/_hdl_build/_sched_virt.bin" as *u8 62 let tamper_bin: *u8 = "/tmp/_schedgate_tamper.bin" as *u8 63 let sov_serial: *u8 = "/tmp/_schedgate_sov.txt" as *u8 64 let sov_tamper: *u8 = "/tmp/_schedgate_tamper.txt" as *u8 65 g_p("=== preemptive-scheduler gate (2-task round-robin: SOVEREIGN rv64 emu + tamper) ===\n" as *u8) 66 let lfd: i64 = sys_openat_append("knowledge/status/sched.log" as *u8, 0x1a4) 67 68 let est: i64 = g_run1("/tmp/nx_sched_emit.sov.elf" as *u8, 0 as *u8, 0 as *u8) 69 if est != 0 { g_p("SCHEDGATE verdict=RED reason=emit-failed\n" as *u8); if lfd>=0 { g_fp(lfd,"SCHEDGATE verdict=RED reason=emit-failed\n" as *u8); sys_close(lfd) } sys_exit(1); return 1 } 70 71 // PRIMARY: sovereign emu runs the scheduler. 72 let sst: i64 = g_run1("_offc/nx_boot_run_sov.elf" as *u8, binpath, sov_serial) 73 let sbuf: *u8 = sys_mmap(131072) 74 let sbn: i64 = g_read(sov_serial, sbuf, 131072) 75 let has_s: i64 = g_has(sbuf, sbn, 83) 76 let has_a: i64 = g_has(sbuf, sbn, 65) 77 let has_b: i64 = g_has(sbuf, sbn, 66) 78 let trans: i64 = g_transitions(sbuf, sbn) 79 var halt_ok: i64 = 0 80 var p2: i64 = 0 81 while p2 + 21 <= sbn { var k: i64=0; var hit: i64=1; let pat: *u8="BOOTSOV verdict=GREEN" as *u8; while k<21 { if sbuf[p2+k]!=pat[k] { hit=0; k=21 } else { k=k+1 } } if hit==1 { halt_ok=1; p2=sbn } else { p2=p2+1 } } 82 var sov_ok: i64 = 0 83 if sst == 0 { if has_s == 1 { if has_a == 1 { if has_b == 1 { if trans >= 8 { if halt_ok == 1 { sov_ok = 1 } } } } } } 84 85 // TAMPER: zero mie.MTIE-enable imm (addi t1,x0,0x80 at byte 48 -> imm byte 51). 86 let ibuf: *u8 = sys_mmap(8192) 87 let ibn: i64 = g_read(binpath, ibuf, 8192) 88 ibuf[48 + 3] = 0 as u8 89 let tfd: i64 = sys_openat_wr(tamper_bin, 0x1a4) 90 if tfd >= 0 { sys_write(tfd, ibuf, ibn); sys_close(tfd) } 91 let tst: i64 = g_run1("_offc/nx_boot_run_sov.elf" as *u8, tamper_bin, sov_tamper) 92 let tbuf: *u8 = sys_mmap(131072) 93 let tbn: i64 = g_read(sov_tamper, tbuf, 131072) 94 let t_trans: i64 = g_transitions(tbuf, tbn) 95 var tamper_bites: i64 = 0 96 if t_trans < 4 { tamper_bites = 1 } // no preemption -> task B never scheduled -> A<->B switching collapses (real run >=8; note 'B' alone is unreliable -- it appears in the runner's "BOOTSOV" line) 97 98 g_p(" sovereign_emu=" as *u8) 99 if sov_ok == 1 { g_p("GREEN" as *u8) } else { g_p("RED" as *u8) } 100 g_p("(switches=" as *u8); g_fn(1, trans); g_p(") tamper_bites=" as *u8) 101 if tamper_bites == 1 { g_p("yes\n" as *u8) } else { g_p("no\n" as *u8) } 102 103 var pass: i64 = 0 104 if sov_ok == 1 { if tamper_bites == 1 { pass = 1 } } 105 if pass == 1 { 106 g_p("SCHEDGATE verdict=GREEN (sovereign rv64 emu: 2-task preemptive round-robin; repeated context switches; tamper REJECTED)\n" as *u8) 107 if lfd >= 0 { g_fp(lfd, "SCHEDGATE verdict=GREEN runtime=sovereign-emu sched=preemptive-round-robin tasks=2 switches=" as *u8); g_fn(lfd, trans); g_fp(lfd, " mechanism=timer-preempt-csrrw-mepc-swap tamper=rejected epoch=" as *u8); g_fn(lfd, sys_now_realtime_sec()); g_fp(lfd, "\n" as *u8); sys_close(lfd) } 108 sys_exit(0); return 0 109 } 110 g_p("SCHEDGATE verdict=RED (sov_ok/tamper not both green)\n" as *u8) 111 if lfd >= 0 { g_fp(lfd, "SCHEDGATE verdict=RED sov_ok=" as *u8); g_fn(lfd, sov_ok); g_fp(lfd, " switches=" as *u8); g_fn(lfd, trans); g_fp(lfd, " tamper_bites=" as *u8); g_fn(lfd, tamper_bites); g_fp(lfd, "\n" as *u8); sys_close(lfd) } 112 sys_exit(1) 113 return 1 114}