code wiki / (root) / nx_nxc_native_wrap.nx

nx_nxc_native_wrap.nx source

↩ module page · 180 lines · 5392 B

1// nxc_native_wrap.nx -- sovereign bootstrap-verification driver. 2// 3// One-shot main() that proves the off-C runtime path works: 4// 5// 1. Read an RV64 ELF from disk (built via stage 1's gcc-anchor 6// OR via the in-NishiLang nxc.elf compiler). 7// 2. Validate the ELF via nx_elf_read. 8// 3. Allocate a 16 MB flat memory region. 9// 4. Load segments into memory via nx_loader. 10// 5. Set sp to the top of memory minus 64 bytes. 11// 6. Run via nx_rv64_sim with a 100M-instruction budget. 12// 7. Report exit code + instruction count to stderr. 13// 14// Usage: 15// nxc_native_wrap path/to/program.elf 16// 17// Returns: 18// 0 = program executed cleanly via simulator 19// 1 = invalid ELF 20// 2 = load failed (e.g. segment OOB) 21// 3 = simulator hit illegal instruction 22// 4 = budget expired 23// N = the simulated program exited with code N (passed through) 24// 25// Pairs with bootstrap_native.sh. Once this lands + works, we have 26// the full off-C verification: produce ELF in NishiLang, run ELF in 27// NishiLang, compare exit code with stage 1. Sovereign stage 2 is 28// achieved. 29 30// nx_safety_envelope: 31// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 32// sil_target: SIL1 33// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 34// verdict: NOT_YET_EVALUATED 35 36import "nx_syscalls.nx" 37import "nx_elf_read.nx" 38import "nx_loader.nx" 39import "nx_rv64_sim.nx" 40const NX_MAGIC_4194304: i64 = 4194304 41 42const NX_WRAP_MEM_SIZE: i64 = 16777216 // 16 MB sim memory 43const NX_WRAP_BUDGET: i64 = 100000000 // 100M instructions 44 45// Read the entire file at `path` into a fresh mmap'd buffer. 46// Returns null + zero len on error. 47func nx_wrap_read_file(path: *u8, out_len: *i64) -> *u8 { 48 let fd: i64 = sys_openat_rd(path) 49 if fd < 0 { 50 *out_len = 0 51 return 0 as *u8 52 } 53 let cap: i64 = NX_MAGIC_4194304 // 4 MB cap (covers nxc.elf + room) 54 let buf: *u8 = sys_mmap(cap) 55 var total: i64 = 0 56 var go: i64 = 1 57 while go == 1 { 58 let base: i64 = buf as i64 59 let tail: *u8 = (base + total) as *u8 60 let n: i64 = sys_read(fd, tail, cap - total) 61 if n <= 0 { go = 0 } 62 if n > 0 { total = total + n } 63 if total >= cap { go = 0 } 64 } 65 sys_close(fd) 66 *out_len = total 67 return buf 68} 69 70// Print "wrap: " + a NUL-terminated string + "\n" to stderr. 71func nx_wrap_log(s: *u8) -> i64 { 72 sys_write(2, "wrap: " as *u8, 6) 73 var n: i64 = 0 74 while s[n] != 0 { n = n + 1 } 75 sys_write(2, s, n) 76 sys_write(2, "\n" as *u8, 1) 77 return 0 78} 79 80// Print "wrap: " + label + " = " + decimal value + "\n". 81func nx_wrap_logn(label: *u8, v: i64) -> i64 { 82 sys_write(2, "wrap: " as *u8, 6) 83 var nl: i64 = 0 84 while label[nl] != 0 { nl = nl + 1 } 85 sys_write(2, label, nl) 86 sys_write(2, " = " as *u8, 3) 87 88 let buf: *u8 = sys_mmap(32) 89 var n: i64 = v 90 if n < 0 { 91 sys_write(2, "-" as *u8, 1) 92 n = 0 - n 93 } 94 if n == 0 { 95 buf[0] = 0x30 96 sys_write(2, buf, 1) 97 } else { 98 var k: i64 = 0 99 while n > 0 { 100 buf[k] = 0x30 + (n - (n / 10) * 10) 101 n = n / 10 102 k = k + 1 103 } 104 var j: i64 = 0 105 var r: i64 = k - 1 106 while j < r { 107 let t: i64 = buf[j] 108 buf[j] = buf[r] 109 buf[r] = t 110 j = j + 1 111 r = r - 1 112 } 113 sys_write(2, buf, k) 114 } 115 sys_write(2, "\n" as *u8, 1) 116 return 0 117} 118 119func main(argc: i64, argv: *i64) -> i64 { 120 if argc < 2 { 121 nx_wrap_log("usage: nxc_native_wrap <path.elf>" as *u8) 122 return 1 123 } 124 let path: *u8 = (argv[1]) as *u8 125 126 // Stage 1: read the ELF. 127 let elf_len_raw: *u8 = sys_mmap(16) 128 let elf_len: *i64 = elf_len_raw as *i64 129 *elf_len = 0 130 let elf_buf: *u8 = nx_wrap_read_file(path, elf_len) 131 if elf_buf == (0 as *u8) { 132 nx_wrap_log("read failed" as *u8) 133 return 1 134 } 135 nx_wrap_logn("elf bytes" as *u8, *elf_len) 136 137 // Stage 2: validate header. 138 let h: *NxElfHeader = nx_elf_parse_header(elf_buf, *elf_len) 139 if h.valid != 1 { 140 nx_wrap_log("invalid ELF" as *u8) 141 return 1 142 } 143 if h.is_64bit != 1 { 144 nx_wrap_log("not ELF64" as *u8) 145 return 1 146 } 147 if h.e_machine != 0xF3 { 148 nx_wrap_log("not RISC-V" as *u8) 149 return 1 150 } 151 nx_wrap_logn("entry vaddr (hex)" as *u8, h.e_entry) 152 nx_wrap_logn("phnum" as *u8, h.e_phnum) 153 154 // Stage 3: allocate sim memory + load segments. 155 let mem: *u8 = sys_mmap(NX_WRAP_MEM_SIZE) 156 let entry: i64 = nx_loader_load(elf_buf, *elf_len, mem, NX_WRAP_MEM_SIZE) 157 if entry < 0 { 158 nx_wrap_log("load failed" as *u8) 159 return 2 160 } 161 nx_wrap_logn("loaded; entry" as *u8, entry) 162 163 // Stage 4: spin up the CPU + run. 164 let cpu: *NxRv64Cpu = nx_rv64_cpu_new(mem, NX_WRAP_MEM_SIZE, entry) 165 nx_rv64_cpu_set_sp(cpu, NX_WRAP_MEM_SIZE - 64) 166 nx_wrap_log("starting simulator" as *u8) 167 let r: i64 = nx_rv64_run(cpu, NX_WRAP_BUDGET) 168 nx_wrap_logn("instructions executed" as *u8, cpu.insn_count) 169 170 if r == 0 { 171 nx_wrap_logn("program exit code" as *u8, cpu.exit_code) 172 return cpu.exit_code 173 } 174 if r > 0 { 175 nx_wrap_log("BUDGET EXPIRED" as *u8) 176 return 4 177 } 178 nx_wrap_log("ILLEGAL INSTRUCTION" as *u8) 179 return 3 180}