code wiki / _hdl_build / nx_hw_discover.nx

nx_hw_discover.nx source

↩ module page · 159 lines · 10729 B

1// nx_hw_discover.nx -- GATE: SOVEREIGN HARDWARE AUTO-DISCOVERY by parsing a REAL device tree (FDT/DTB). Reads the 2// ACTUAL device tree QEMU's RISC-V virt machine hands the guest (knowledge/hw/virt.dtb, dumped live via 3// `qemu-system-riscv64 -M virt,dumpdtb=`), walks the flattened-device-tree binary (big-endian FDT, magic 0xd00dfeed), 4// and produces a DEVICE MANIFEST: every node's type + base address. This is how a real OS discovers its hardware -- 5// no hard-coded device list; the machine tells us what it has. Feeds nx_driver_gen (generate a driver per device). 6// T1 parse the real DTB: valid FDT magic + find the 8 virtio-mmio transport slots. 7// T2 KAT: the 8 virtio-mmio base addresses == 0x10001000..0x10008000 (the real virt-machine layout). 8// T3 discover the UART (serial@10000000) + PLIC + CLINT + main memory@0x80000000. 9// T4 teeth: a corrupted FDT magic is REFUSED (no false discovery). T5 deterministic (re-parse = same manifest). 10// expect_exit: 0 Sovereign: nx_syscalls. Grounded: knowledge/hw/virt.dtb (a live QEMU artifact). 11import "nx_syscalls.nx" 12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 13import "nx_g_puts_lib.nx" 14 15// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 16// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 17// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 18// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 19func g_pn(v: i64) -> i64 { nxi_out(v); return 0 } 20func g_hex(v: i64) -> i64 { g_puts("0x" as *u8); let b: *u8=sys_mmap(20); var started: i64=0; var k: i64=0; var i: i64=60; while i>=0 { let nib: i64=(v>>i)&15; if nib!=0 { started=1 } if started==1 { if nib<10 { b[k]=(48+nib) as u8 } else { b[k]=(87+nib) as u8 } k=k+1 } i=i-4 } if k==0 { b[0]=48 as u8; k=1 } sys_write(1,b,k); return 0 } 21func ck(name: *u8, c: i64) -> i64 { if c==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } g_puts(name); g_puts("\n" as *u8); return c } 22 23// FDT tokens + big-endian reader 24const FDT_BEGIN_NODE: i64 = 1 25const FDT_END_NODE: i64 = 2 26const FDT_PROP: i64 = 3 27const FDT_NOP: i64 = 4 28const FDT_END: i64 = 9 29const FDT_MAGIC: i64 = 0xd00dfeed 30func be32(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<24)|((b[o+1] as i64)<<16)|((b[o+2] as i64)<<8)|(b[o+3] as i64) } 31func align4(x: i64) -> i64 { return (x+3) & (0-4) } 32func hexval(c: i64) -> i64 { if c>=48 { if c<=57 { return c-48 } } if c>=97 { if c<=102 { return c-87 } } if c>=65 { if c<=70 { return c-55 } } return 0-1 } 33// device types 34const D_VIRTIO: i64 = 1 35const D_UART: i64 = 2 36const D_PLIC: i64 = 3 37const D_CLINT: i64 = 4 38const D_MEMORY: i64 = 5 39const D_CPU: i64 = 6 40const D_OTHER: i64 = 0 41func tname(t: i64) -> *u8 { if t==1 { return "virtio-mmio" as *u8 } if t==2 { return "uart(ns16550)" as *u8 } if t==3 { return "plic" as *u8 } if t==4 { return "clint" as *u8 } if t==5 { return "memory" as *u8 } if t==6 { return "cpu" as *u8 } return "other" as *u8 } 42// name prefix match: does name[0..] start with lit? 43func starts(name: *u8, o: i64, lit: *u8) -> i64 { var i: i64=0; while lit[i]!=(0 as u8) { if name[o+i]!=lit[i] { return 0 } i=i+1 } return 1 } 44// parse the hex address after '@' in a node name at offset o; -1 if no '@' 45func addr_after_at(b: *u8, o: i64) -> i64 { 46 var i: i64=o; while b[i]!=(0 as u8) { if b[i]==(64 as u8) { // '@' 47 var v: i64=0; var j: i64=i+1; var any: i64=0 48 while b[j]!=(0 as u8) { let hv: i64=hexval(b[j] as i64); if hv<0 { j=j+1 } else { v=(v<<4)|hv; any=1; j=j+1 } } 49 if any==1 { return v } return 0-1 50 } i=i+1 } 51 return 0-1 52} 53func classify(b: *u8, o: i64) -> i64 { 54 if starts(b,o,"virtio_mmio@" as *u8)==1 { return D_VIRTIO } 55 if starts(b,o,"serial@" as *u8)==1 { return D_UART } 56 if starts(b,o,"plic@" as *u8)==1 { return D_PLIC } 57 if starts(b,o,"clint@" as *u8)==1 { return D_CLINT } 58 if starts(b,o,"memory@" as *u8)==1 { return D_MEMORY } 59 if starts(b,o,"cpu@" as *u8)==1 { return D_CPU } 60 return D_OTHER 61} 62 63// walk the FDT struct block; fill dtype[]/daddr[]; return device count, or -1 on bad magic. 64func fdt_discover(b: *u8, n: i64, dtype: *i64, daddr: *i64, cap: i64) -> i64 { 65 if be32(b,0)!=FDT_MAGIC { return 0-1 } 66 let off_struct: i64=be32(b,8) 67 var pos: i64=off_struct 68 var count: i64=0 69 var go: i64=1 70 while go==1 { 71 if pos+4>n { go=0 } else { 72 let tok: i64=be32(b,pos); pos=pos+4 73 if tok==FDT_BEGIN_NODE { 74 var nlen: i64=0; while b[pos+nlen]!=(0 as u8) { nlen=nlen+1 } 75 let ty: i64=classify(b,pos) 76 if ty!=D_OTHER { if count<cap { dtype[count]=ty; daddr[count]=addr_after_at(b,pos); count=count+1 } } 77 pos = pos + align4(nlen+1) 78 } else { if tok==FDT_PROP { 79 let plen: i64=be32(b,pos); pos=pos+4; pos=pos+4 // skip len + nameoff 80 pos = pos + align4(plen) // skip value 81 } else { if tok==FDT_END { go=0 } } } // END_NODE / NOP: nothing 82 } 83 } 84 return count 85} 86func count_type(dtype: *i64, n: i64, ty: i64) -> i64 { var c: i64=0; var i: i64=0; while i<n { if dtype[i]==ty { c=c+1 } i=i+1 } return c } 87func find_addr(dtype: *i64, daddr: *i64, n: i64, ty: i64, addr: i64) -> i64 { var i: i64=0; while i<n { if dtype[i]==ty { if daddr[i]==addr { return 1 } } i=i+1 } return 0 } 88 89func main() -> i64 { 90 g_puts("nx_hw_discover (SOVEREIGN hardware auto-discovery: parse the REAL QEMU device tree (FDT/DTB) -> device manifest)\n" as *u8) 91 var pass: i64=0; var total: i64=0 92 let lenbox: *i64 = sys_mmap(16) as *i64 93 let dtb: *u8 = sys_read_file("knowledge/hw/virt.dtb" as *u8, lenbox) 94 let n: i64 = lenbox[0] 95 if (dtb as i64)==0 { g_puts(" FATAL: cannot read knowledge/hw/virt.dtb (dump via qemu-system-riscv64 -M virt,dumpdtb=)\n" as *u8); sys_exit(1); return 1 } 96 g_puts(" read device tree: "); g_pn(n); g_puts(" bytes; FDT magic="); g_hex(be32(dtb,0)); g_puts(" (0xd00dfeed=valid)\n" as *u8) 97 98 let dtype: *i64 = sys_mmap(64*8) as *i64; let daddr: *i64 = sys_mmap(64*8) as *i64 99 let ndev: i64 = fdt_discover(dtb, n, dtype, daddr, 64) 100 g_puts(" DISCOVERED "); g_pn(ndev); g_puts(" devices from the live device tree:\n" as *u8) 101 var i: i64=0; while i<ndev { g_puts(" ["); g_pn(i); g_puts("] "); g_puts(tname(dtype[i])); g_puts(" @ "); g_hex(daddr[i]); g_puts("\n" as *u8); i=i+1 } 102 103 let nvirtio: i64 = count_type(dtype, ndev, D_VIRTIO) 104 var t1: i64=0; if be32(dtb,0)==FDT_MAGIC { if nvirtio==8 { t1=1 } } 105 pass=pass+ck("T1: parse the REAL DTB (valid FDT magic) + discover the 8 virtio-mmio transport slots" as *u8, t1); total=total+1 106 107 // T2 KAT: the 8 virtio-mmio slots are at 0x10001000..0x10008000 108 var allslots: i64=1; var s: i64=0; while s<8 { let want: i64=0x10001000 + s*0x1000; if find_addr(dtype,daddr,ndev,D_VIRTIO,want)==0 { allslots=0 } s=s+1 } 109 var t2: i64=0; if allslots==1 { t2=1 } 110 g_puts(" T2 virtio-mmio slot addresses 0x10001000..0x10008000 all present="); g_pn(allslots); g_puts("\n" as *u8) 111 pass=pass+ck("T2 (KAT): the discovered virtio-mmio base addresses match the real virt-machine layout" as *u8, t2); total=total+1 112 113 // T3: UART + PLIC + CLINT + memory discovered at the real addresses 114 let uart_ok: i64 = find_addr(dtype,daddr,ndev,D_UART,0x10000000) 115 let plic_ok: i64 = count_type(dtype,ndev,D_PLIC) 116 let clint_ok: i64 = count_type(dtype,ndev,D_CLINT) 117 let mem_ok: i64 = find_addr(dtype,daddr,ndev,D_MEMORY,0x80000000) 118 var t3: i64=0; if uart_ok==1 { if plic_ok>=1 { if clint_ok>=1 { if mem_ok==1 { t3=1 } } } } 119 g_puts(" T3 core devices: UART@0x10000000="); g_pn(uart_ok); g_puts(" PLIC="); g_pn(plic_ok); g_puts(" CLINT="); g_pn(clint_ok); g_puts(" memory@0x80000000="); g_pn(mem_ok); g_puts("\n" as *u8) 120 pass=pass+ck("T3: the UART, PLIC, CLINT, and main memory are discovered at their real base addresses" as *u8, t3); total=total+1 121 122 // T4 teeth: corrupt the FDT magic -> discovery refused 123 let save0: i64=dtb[0] as i64; dtb[0]=0xFF as u8 124 let bad: i64 = fdt_discover(dtb, n, dtype, daddr, 64) 125 dtb[0]=save0 as u8 126 let good: i64 = fdt_discover(dtb, n, dtype, daddr, 64) 127 var t4: i64=0; if bad==(0-1) { if good==ndev { t4=1 } } 128 g_puts(" T4 corrupted FDT magic -> discover returns "); g_pn(bad); g_puts(" (-1=REFUSED); restored -> "); g_pn(good); g_puts(" devices\n" as *u8) 129 pass=pass+ck("T4 (teeth): a corrupted FDT magic is REFUSED -- no false hardware discovery" as *u8, t4); total=total+1 130 131 // T5 determinism 132 let d2type: *i64 = sys_mmap(64*8) as *i64; let d2addr: *i64 = sys_mmap(64*8) as *i64 133 let ndev2: i64 = fdt_discover(dtb, n, d2type, d2addr, 64) 134 var same: i64=1; i=0; while i<ndev { if dtype[i]!=d2type[i] { same=0 } if daddr[i]!=d2addr[i] { same=0 } i=i+1 } 135 var t5: i64=0; if ndev2==ndev { if same==1 { t5=1 } } 136 pass=pass+ck("T5: discovery is deterministic -- re-parsing the device tree yields the identical manifest" as *u8, t5); total=total+1 137 138 // write the discovered manifest for nx_driver_gen to consume 139 let mf: i64 = sys_openat_wr("knowledge/hw/discovered.tsv" as *u8, 420) 140 if mf>=0 { i=0; while i<ndev { let line: *u8=sys_mmap(64); var o: i64=0 141 let tn: *u8=tname(dtype[i]); var j: i64=0; while tn[j]!=(0 as u8) { line[o]=tn[j]; o=o+1; j=j+1 } 142 line[o]=9 as u8; o=o+1 143 var a: i64=daddr[i]; if a<0 { a=0 } 144 // hex address 145 line[o]=48 as u8; line[o+1]=120 as u8; o=o+2; var started: i64=0; var sh: i64=60 146 while sh>=0 { let nib: i64=(a>>sh)&15; if nib!=0 { started=1 } if started==1 { if nib<10 { line[o]=(48+nib) as u8 } else { line[o]=(87+nib) as u8 } o=o+1 } sh=sh-4 } 147 if started==0 { line[o]=48 as u8; o=o+1 } 148 line[o]=10 as u8; o=o+1 149 sys_write(mf, line, o); i=i+1 } sys_close(mf) } 150 151 var okall: i64=0; if pass==total { okall=1 } 152 g_puts("---- nx_hw_discover: passed "); g_pn(pass); g_puts(" / "); g_pn(total); g_puts(" ----\n" as *u8) 153 if okall==1 { 154 let logf: i64=sys_openat_append("knowledge/status/hw_discover.log" as *u8, 420) 155 if logf>=0 { let z: i64=sys_write(logf,"NXHWDISCOVER GREEN: sovereign FDT/DTB parser auto-discovers the REAL QEMU virt device tree (8 virtio-mmio + UART/PLIC/CLINT/memory at real addresses); corrupt-magic refused\n" as *u8,162); sys_close(logf) } 156 g_puts("verdict=GREEN (sovereign hardware auto-discovery: parses the REAL QEMU device tree -> device manifest with real base addresses; no hard-coded device list)\n" as *u8); sys_exit(0); return 0 157 } 158 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1 159}