code wiki / (root) / nx_pabi.nx

nx_pabi.nx source

↩ module page · 261 lines · 11090 B

1// nx_pabi.nx -- THE PORTABLE SYSCALL ABI SEAM (operator 2026-07-16: "don't defer, eat our debt, 2// build the tools we need; target the OS on rv64 AND x86 AND all hardware mobile+non-mobile so the 3// forge works on them too, as resources permit locally/forest/cloud"). This is R1 (the FOUNDATIONAL 4// rock from nx_forge_os_readiness) STARTED, not deferred. 5// 6// THE DEBT: every forge organ imports nx_syscalls hard-wired to Linux-x86-64 (raw `syscall` insn). 7// That binds the forge to ONE OS. THE FIX: an ABI INDIRECTION -- the forge's file/mem/etc. surface 8// as a stable interface with PLUGGABLE BACKENDS selected at call time: 9// PABI_LINUX -> the host kernel via sys_* (today's path; any Linux/arch) 10// PABI_NISHIOS -> NishiOS-native via the sovereign block-VFS (nx_vfsblock_lib) -- no Linux kernel 11// It is ARCH-AGNOSTIC by construction (NishiLang source -> whatever nx_cc backend: x86-64 today, 12// RV64/ARM as the compiler gains backends), so the SAME forge code runs on x86 laptops, RV64, and 13// mobile/non-mobile targets. The swarm admission plane (nx_swarm_admit/queue) then PLACES the forge 14// where resources permit (local / forest / cloud). This module ships the FILE subset (the 15// deterministic core's need: the byte-exact judge reads/writes candidates+store+ledger); mem/proc/ 16// clock backends are the next increments on the same seam. 17// license_tier: ORIGINAL 18import "nx_vfsblock_lib.nx" 19import "nx_nxe_lib.nx" 20import "nx_lib_std.nx" 21const PABI_MAGIC_4096: i64 = 4096 22const PABI_MAGIC_65536: i64 = 65536 23 24const PABI_LINUX: i64 = 0 25const PABI_NISHIOS: i64 = 1 26 27// basename of a "/a/b/name" path (after the last '/') into out; returns len. 28func pabi_basename(path: *u8, out: *u8) -> i64 { 29 var last: i64 = 0 - 1 30 var i: i64 = 0 31 while path[i] != (0 as u8) { if path[i] == (47 as u8) { last = i } i = i + 1 } 32 var o: i64 = 0 33 var p: i64 = last + 1 34 while path[p] != (0 as u8) { out[o] = path[p]; o = o + 1; p = p + 1 } 35 out[o] = 0 as u8 36 return o 37} 38 39// write data[0..dlen) to `path`. vimg = the mounted NishiOS VFS image (ignored for LINUX). 40// returns 0 ok / negative on failure. ONE forge-level file write, TWO substrates. 41func pabi_write(be: i64, vimg: *u8, path: *u8, data: *u8, dlen: i64) -> i64 { 42 if be == PABI_LINUX { 43 let fd: i64 = sys_openat_wr(path, 420) 44 if fd < 0 { return 0 - 1 } 45 var off: i64 = 0 46 while off < dlen { 47 let q: *u8 = data + off 48 let w: i64 = sys_write(fd, q, dlen - off) 49 if w <= 0 { sys_close(fd); return 0 - 2 } 50 off = off + w 51 } 52 sys_close(fd) 53 return 0 54 } 55 if be == PABI_NISHIOS { 56 let name: *u8 = sys_mmap(80) as *u8 57 pabi_basename(path, name) 58 let idx: i64 = vb_create(vimg, 0, name, data, dlen) 59 if idx < 0 { return 0 - 1 } 60 return 0 61 } 62 return 0 - 9 63} 64 65// read `path` into out (cap). returns bytes or -1 (absent). ONE forge-level file read, TWO substrates. 66func pabi_read(be: i64, vimg: *u8, path: *u8, out: *u8, cap: i64) -> i64 { 67 if be == PABI_LINUX { 68 let fd: i64 = sys_openat_rd(path) 69 if fd < 0 { return 0 - 1 } 70 var o: i64 = 0 71 var go: i64 = 1 72 while go == 1 { 73 let rem: i64 = cap - o 74 if rem <= 0 { go = 0 } 75 if go == 1 { 76 let q: *u8 = out + o 77 let r: i64 = sys_read(fd, q, rem) 78 if r <= 0 { go = 0 } 79 if r > 0 { o = o + r } 80 } 81 } 82 sys_close(fd) 83 return o 84 } 85 if be == PABI_NISHIOS { 86 let idx: i64 = vb_resolve(vimg, path) 87 if idx < 0 { return 0 - 1 } 88 let n: i64 = vb_read(vimg, idx, out) 89 return n 90 } 91 return 0 - 9 92} 93 94// mkdir `path`. LINUX: host sys_mkdir. NISHIOS: vb_mkdir under root(0). 0 ok / negative fail. 95// (Genuinely cross-substrate: the block-VFS inode/dir model vs the host FS -- not a pass-through.) 96func pabi_mkdir(be: i64, vimg: *u8, path: *u8) -> i64 { 97 if be == PABI_LINUX { 98 let r: i64 = sys_mkdir(path, 493) 99 if r < 0 { return 0 - 1 } 100 return 0 101 } 102 if be == PABI_NISHIOS { 103 let name: *u8 = sys_mmap(80) as *u8 104 pabi_basename(path, name) 105 let idx: i64 = vb_mkdir(vimg, 0, name) 106 if idx < 0 { return 0 - 1 } 107 return 0 108 } 109 return 0 - 9 110} 111 112// does `path` exist? 1 yes / 0 no. LINUX: openat probe. NISHIOS: vb_resolve. 113func pabi_exists(be: i64, vimg: *u8, path: *u8) -> i64 { 114 if be == PABI_LINUX { 115 let fd: i64 = sys_openat_rd(path) 116 if fd < 0 { return 0 } 117 sys_close(fd) 118 return 1 119 } 120 if be == PABI_NISHIOS { 121 let idx: i64 = vb_resolve(vimg, path) 122 if idx >= 0 { return 1 } 123 return 0 124 } 125 return 0 126} 127 128// SUBSTRATE HONESTY (do not overclaim): the block-VFS is the ONE genuinely NishiOS-native substrate 129// today (file/dir ops route to nx_vfsblock_lib, a real inode/block/journal model DISTINCT from the 130// host FS). mem/clock on the current file-model NishiOS are host-backed (the nx_mmu_hw / CLINT models 131// exist but are not yet wired as pabi backends); proc (fork-a-program vs nxe_load_exec-in-process) 132// and lock (flock vs a NishiOS task-lock) are DEEPER concurrency/exec rungs, not shims. So R1 grades 133// PARTIAL honestly -- file+dir proven cross-substrate; the rest are named work, never faked. 134 135// EXEC BACKEND -- the forge JUDGE's core primitive: run a unit of computation, get its verdict, via 136// the OS's NATIVE execution mechanism (genuinely distinct, not a shim): 137// LINUX fork a child that computes f(arg)=arg+K and exits with it; wait4 the exit code 138// (the judge's actual subprocess model -- fg_spawn forks the build lane the same way). 139// NISHIOS nxe_write x86-64 machine code computing f(arg), nxe_load_exec it (verify SHA-256 + EXEC 140// cap -> mmap RWX -> call) -- the SPORE's actual verified-machine-code model. 141// The cross-substrate IDENTITY (same result via subprocess AND verified-machine-code) proves the 142// forge's execute-and-verify primitive runs on both OSes. result 0..255, or negative on failure. 143const PABI_EXEC_K: i64 = 100 144 145func pabi_exec(be: i64, arg: i64) -> i64 { 146 if be == PABI_LINUX { 147 let pid: i64 = sys_fork() 148 if pid == 0 { 149 let r: i64 = (arg + PABI_EXEC_K) & 255 150 sys_exit(r) 151 } 152 let st: *i64 = sys_mmap(64) as *i64 153 sys_wait4(pid, st, 0) 154 let sv: i64 = st[0] 155 return (sv >> 8) & 255 156 } 157 if be == PABI_NISHIOS { 158 // x86-64 SysV: mov rax,rdi (48 89 F8) ; add rax,K (48 83 C0 KK) ; ret (C3) 159 let code: *u8 = sys_mmap(16) as *u8 160 code[0] = 0x48 as u8 161 code[1] = 0x89 as u8 162 code[2] = 0xF8 as u8 163 code[3] = 0x48 as u8 164 code[4] = 0x83 as u8 165 code[5] = 0xC0 as u8 166 code[6] = PABI_EXEC_K as u8 167 code[7] = 0xC3 as u8 168 let img: *u8 = sys_mmap(PABI_MAGIC_4096) as *u8 169 nxe_write(img, 1, 0, 8, 0, code, 8) // arch x86, flags 0, caps=8 (EXEC bit3), entry 0 170 let resbox: *i64 = sys_mmap(8) as *i64 171 let ranbox: *i64 = sys_mmap(8) as *i64 172 let rc: i64 = nxe_load_exec(img, arg, resbox, ranbox) 173 if rc != 0 { return rc - 100 } 174 if ranbox[0] != 1 { return 0 - 50 } 175 return resbox[0] & 255 176 } 177 return 0 - 9 178} 179 180// THE PORTABLE FORGE JUDGE -- the exceed lever (noise-free byte-exact verify), made OS-portable. 181// The judge = EXECUTE a candidate -> CAPTURE its output bytes -> BYTE-COMPARE vs expected. Composes 182// the proven backends: pabi_exec (produce, OS-native) + pabi_write/read (capture, OS-native). Runs 183// identically on the Linux host kernel AND on NishiOS (block-VFS + NXE loader). Returns 1 GREEN / 184// 0 RED / negative on error. (The remaining depth = compiling an ARBITRARY .nx candidate via 185// nx_cc-as-subprocess on NishiOS -- needs nx_cc itself running native; this proves the DECISION LOOP.) 186func pabi_judge(be: i64, vimg: *u8, arg: i64, expected: *u8, elen: i64) -> i64 { 187 let n: i64 = pabi_exec(be, arg) 188 if n < 0 { return 0 - 1 } 189 let outbuf: *u8 = sys_mmap(64) as *u8 190 let nl: i64 = std_itoa(n, outbuf) 191 var opath: *u8 = "/tmp/pabi_judge_out" as *u8 192 if be == PABI_NISHIOS { opath = "/judge_out" as *u8 } 193 let w: i64 = pabi_write(be, vimg, opath, outbuf, nl) 194 if w != 0 { return 0 - 2 } 195 let got: *u8 = sys_mmap(64) as *u8 196 let gn: i64 = pabi_read(be, vimg, opath, got, 64) 197 if gn != elen { return 0 } 198 var i: i64 = 0 199 while i < elen { 200 if got[i] != expected[i] { return 0 } 201 i = i + 1 202 } 203 return 1 204} 205 206// SPAWN BACKEND -- run a REAL external program + capture its output (the judge's ACTUAL mechanism, 207// not the toy in-process pabi_exec). LINUX: fork -> child dup3(outfile,1&2) + execve(argv) -> parent 208// wait4 (this IS fg_spawn -- the forge judge forks nx_sov_build_run exactly this way, then reads the 209// captured output). NISHIOS: a "program" is an NXE in the VFS (NishiOS runs verified NXEs, not 210// arbitrary Linux ELFs -- the honest boundary): load the NXE bytes from the VFS, nxe_load_exec, write 211// its result to the output file. returns the child exit code (LINUX) / 0-ok (NISHIOS) / negative err. 212func pabi_spawn(be: i64, vimg: *u8, argv: *i64, envp: *i64, outpath: *u8) -> i64 { 213 if be == PABI_LINUX { 214 let pid: i64 = sys_fork() 215 if pid == 0 { 216 let ofd: i64 = sys_openat_wr(outpath, 420) 217 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) } 218 let p0: i64 = argv[0] 219 let prog: *u8 = p0 as *u8 220 sys_execve(prog, argv, envp) 221 sys_exit(127) 222 } 223 let st: *i64 = sys_mmap(64) as *i64 224 sys_wait4(pid, st, 0) 225 let sv: i64 = st[0] 226 return (sv >> 8) & 255 227 } 228 if be == PABI_NISHIOS { 229 // load the NXE program bytes from the VFS (argv[0] = the NXE path in the image) 230 let p0: i64 = argv[0] 231 let npath: *u8 = p0 as *u8 232 let nxe: *u8 = sys_mmap(PABI_MAGIC_65536) as *u8 233 let idx: i64 = vb_resolve(vimg, npath) 234 if idx < 0 { return 0 - 1 } 235 vb_read(vimg, idx, nxe) 236 let resbox: *i64 = sys_mmap(8) as *i64 237 let ranbox: *i64 = sys_mmap(8) as *i64 238 let rc: i64 = nxe_load_exec(nxe, 0, resbox, ranbox) 239 if rc != 0 { return rc - 100 } 240 // write the NXE's result as the captured output (fresh path per run; VFS is additive-only) 241 let outbuf: *u8 = sys_mmap(64) as *u8 242 let nl: i64 = std_itoa(resbox[0], outbuf) 243 pabi_write(PABI_NISHIOS, vimg, outpath, outbuf, nl) 244 return 0 245 } 246 return 0 - 9 247} 248 249// mount a fresh NishiOS VFS image (256KB) for the NISHIOS backend; returns the image ptr. 250func pabi_nishios_new() -> *u8 { 251 let img: *u8 = sys_mmap(VB_BS * VB_NB) as *u8 252 vb_format(img) 253 vb_mount(img) 254 return img 255} 256 257func pabi_backend_name(be: i64) -> *u8 { 258 if be == PABI_LINUX { return "linux-host-syscalls" as *u8 } 259 if be == PABI_NISHIOS { return "nishios-block-vfs" as *u8 } 260 return "unknown" as *u8 261}