code wiki / _hdl_build / nx_bootcap.nx

nx_bootcap.nx source

↩ module page · 113 lines · 6369 B

1// nx_bootcap.nx -- ONE boot-and-capture primitive for every organ that needs to know what the 2// live kernel actually SAID. 3// 4// WHY: measuring a kernel means booting the ARTIFACT and reading its serial -- not parsing a log 5// ABOUT the artifact, which can be stale, written by a different build, or absent entirely. That 6// boot-and-capture block had already been copy-pasted into nx_nishios_kernel_gate and 7// nx_kernel_adoption and was about to land in nx_kernel_census as a third copy; three copies of a 8// measurement primitive is three chances for the rulers to silently disagree about what booted. 9// 10// Also owns the TWO-ROOTS resolution: the buildroot keeps the image under runtime/_hdl_build/ 11// while the live serving root keeps it at ./ -- one name, two roots. Callers get the resolved 12// path back so they can PRINT which artifact they actually measured; a ruler that will not say 13// which artifact it read is not reporting a measurement. 14// license_tier: ORIGINAL 15import "rv64im_min_sim.nx" 16import "rv64im_min_csr.nx" 17import "rv64im_min_clint.nx" 18import "rv64im_min_uart.nx" 19import "rv64im_min_virtio.nx" 20import "rv64im_min_nvme.nx" 21 22const BOOTCAP_MEM_BASE: i64 = 0x80000000 23const BOOTCAP_MEM_SIZE: i64 = 65536 24const BOOTCAP_MAX_STEPS: i64 = 100000 25// res[] slots the caller reads back 26const BOOTCAP_R_HALTED: i64 = 0 27const BOOTCAP_R_CODE: i64 = 1 28const BOOTCAP_R_STEPS: i64 = 2 29const BOOTCAP_R_TXN: i64 = 3 30const BOOTCAP_R_N: i64 = 4 31 32// Build a FRESH machine (every device re-allocated, so machine N cannot contaminate machine N+1 -- 33// the negative-control runs depend on that isolation), load `img` at BOOTCAP_MEM_BASE, and return 34// the sim STOPPED at reset -- not run. Split out of bootcap_run on 2026-08-23 for the GDB stub 35// (nx_gdbstub), which must hold the machine stopped until a debugger resumes it: the stub needs the 36// SAME device set the boot rulers measure against, and a second hand-rolled copy of this block is 37// exactly the three-rulers-disagree defect the file header describes. bootcap_run composes this. 38// The sim is allocated with NX_RV64IM_SIM_BYTES -- the struct's own size constant; rv64im_min_sim.nx 39// documents why a literal byte count here was the out-of-bounds landmine. 40// bootcap_machine keeps the original 4-arg signature (every boot ruler + nx_gdbstub call it) and 41// delegates to the memory-size-parameterised form. ADDED 2026-08-23 (nishios NO3, nx_rvc_run_suite): 42// the RISC-V architectural branch tests (jal/beq/bne/blt/bge/bltu/bgeu-01) link their signature region 43// up to ~586 KB above mem_base, so a fixed 64 KB RAM cannot hold them. Parameterising the ONE 44// composition -- rather than a second hand-rolled copy in the conformance runner -- is exactly what 45// this file's header demands (a second copy is the three-rulers-disagree defect). mem_size is the 46// caller's derived need (the suite passes round_up(_end - mem_base, page)); existing callers pass 47// BOOTCAP_MEM_SIZE and are byte-for-byte unchanged. 48func bootcap_machine(img: *u8, ilen: i64, tx_buf: *u8, txcap: i64) -> *NxRv64imSim { 49 return bootcap_machine_mem(img, ilen, tx_buf, txcap, BOOTCAP_MEM_SIZE) 50} 51func bootcap_machine_mem(img: *u8, ilen: i64, tx_buf: *u8, txcap: i64, mem_size: i64) -> *NxRv64imSim { 52 let rf_storage: *i64 = (sys_mmap(8 * NX_RV64IM_RF_N_REGS)) as *i64 53 let csr_storage: *i64 = (sys_mmap(8 * NX_CSR_SLOT_N)) as *i64 54 let clint_storage: *i64 = (sys_mmap(8 * NX_CLINT_SLOT_N)) as *i64 55 let uart_storage: *i64 = (sys_mmap(8 * NX_UART_SLOT_N)) as *i64 56 let virtio_storage:*i64 = (sys_mmap(8 * NX_VIRTIO_SLOT_N)) as *i64 57 let vnet_storage: *i64 = (sys_mmap(8 * NX_VIRTIO_SLOT_N)) as *i64 58 let nvme_storage: *i64 = (sys_mmap(8 * NX_NVME_SLOT_N)) as *i64 59 let nndev_storage: *i64 = (sys_mmap(8 * NX_NNDEV_SLOT_N)) as *i64 60 let mmu_storage: *i64 = (sys_mmap(8 * NX_MMU_SLOT_N)) as *i64 61 let mem: *u8 = sys_mmap(mem_size) 62 let rf: *NxRv64imRegfile = (sys_mmap(64)) as *NxRv64imRegfile 63 let csr: *NxRv64imCsrFile = (sys_mmap(64)) as *NxRv64imCsrFile 64 let clint: *NxClint = (sys_mmap(64)) as *NxClint 65 let uart: *NxUart = (sys_mmap(64)) as *NxUart 66 let virtio:*NxVirtioMmio = (sys_mmap(64)) as *NxVirtioMmio 67 let vnet: *NxVirtioMmio = (sys_mmap(64)) as *NxVirtioMmio 68 let nvme: *NxNvmeCtrl = (sys_mmap(64)) as *NxNvmeCtrl 69 let nndev: *NxNnDev = (sys_mmap(64)) as *NxNnDev 70 let mmu: *NxMmu = (sys_mmap(64)) as *NxMmu 71 let sim: *NxRv64imSim = (sys_mmap(NX_RV64IM_SIM_BYTES)) as *NxRv64imSim 72 nx_rv64im_rf_init(rf, rf_storage) 73 nx_rv64im_csr_init(csr, csr_storage, 0) 74 nx_clint_init(clint, clint_storage) 75 nx_uart_init(uart, uart_storage, tx_buf, txcap) 76 nx_virtio_init(virtio, virtio_storage) 77 nx_virtio_init_net(vnet, vnet_storage) 78 nx_nvme_init(nvme, nvme_storage) 79 nx_nndev_init(nndev, nndev_storage) 80 nx_mmu_init(mmu, mmu_storage) 81 nx_rv64im_sim_init(sim, rf, csr, clint, uart, BOOTCAP_MEM_BASE, mem, mem_size, 0) 82 nx_rv64im_sim_attach_virtio(sim, virtio) 83 nx_rv64im_sim_attach_virtio_net(sim, vnet) 84 nx_rv64im_sim_attach_nvme(sim, nvme) 85 nx_rv64im_sim_attach_nndev(sim, nndev) 86 nx_rv64im_sim_attach_mmu(sim, mmu) 87 var i: i64 = 0 88 while i < ilen { mem[i] = img[i]; i = i + 1 } 89 return sim 90} 91 92// Boot `img` on a FRESH machine (bootcap_machine) and capture the UART. Returns tx count. 93func bootcap_run(img: *u8, ilen: i64, tx_buf: *u8, txcap: i64, res: *i64) -> i64 { 94 let sim: *NxRv64imSim = bootcap_machine(img, ilen, tx_buf, txcap) 95 nx_rv64im_sim_run(sim, BOOTCAP_MAX_STEPS) 96 let cnt: i64 = nx_uart_tx_count(sim.uart) 97 res[BOOTCAP_R_HALTED] = sim.halted 98 res[BOOTCAP_R_CODE] = sim.halt_code 99 res[BOOTCAP_R_STEPS] = sim.steps 100 res[BOOTCAP_R_TXN] = cnt 101 return cnt 102} 103 104// Resolve the kernel image across the two roots. Returns the buffer (0 if neither exists) and 105// writes the byte length to lenp[0]; `outpath` receives which path actually answered. 106func bootcap_load(primary: *u8, alt: *u8, lenp: *i64, outpath: *i64) -> *u8 { 107 var img: *u8 = sys_read_file(primary, lenp) 108 if lenp[0] > 0 { outpath[0] = primary as i64; return img } 109 img = sys_read_file(alt, lenp) 110 if lenp[0] > 0 { outpath[0] = alt as i64; return img } 111 outpath[0] = primary as i64 112 return 0 as *u8 113}