code wiki / _hdl_build / nx_nishifs_boot.nx

nx_nishifs_boot.nx source

↩ module page · 284 lines · 16190 B

1// nx_nishifs_boot.nx -- ladder C8 (the arc-closer): BOOT-FROM-NishiFS = power on -> mount rootfs from the FS. 2// 3// ONE disk image fuses the boot chain + the content-addressed FS: sector 0 = a real 16-bit MBR boot stub + 4// the C1 partition table (bootable 0x80 / Nishi 0x9E @ LBA 1); the partition (LBA 1+) = a NishiFS (superblock 5// magic NISHIFS1 + root_CID + object region + Merkle directory) holding the ROOTFS files (init, motd). 6// TWO phases, both off the persisted + re-read disk: 7// (1) BOOT -- the sovereign 16-bit emu EXECUTES the sector-0 boot code at 0x7C00 -> prints "NISHI BOOT" -> HLT. 8// (2) MOUNT ROOTFS -- the kernel's NishiFS driver parses the partition table -> superblock -> recompute dir 9// CID == root (whole-rootfs integrity) -> looks up "init" -> object by CID -> integrity-on-read -> bytes. 10// => the kernel READS ITS ROOTFS FROM the content-addressed NishiFS on the same disk it booted from. 11// KAT 6/6: T1 disk BOOTS (emu executes boot code -> "NISHI BOOT"); T2 partition is NishiFS (0x80/0x9E parsed); 12// T3 kernel mounts rootfs + reads "init" by CID (bytes match); T4 whole-rootfs root-CID integrity holds; 13// T5 liar-kill: tamper init's object -> rootfs mount -> MNT_INTEGRITY (kernel detects corrupt rootfs at boot); 14// T6 runs off the persisted + re-read disk. 15// HONEST SEAM (per the established boot-organ pattern, e.g. nx_nishi_usb_desktop): the emu executes the boot 16// as REAL x86; the rootfs-mount runs as the kernel's NishiFS driver in NishiLang (same sovereign language). 17// A fully NishiFS-AWARE 16-bit asm bootloader (load the kernel object BY CID in real mode) is the deeper rung. 18// composes nx_sha256 + nx_syscalls; reuses the C4 emu + NishiFS format/mount. 19// NEVER-BRICK (Rule 26): writes a FILE (knowledge/status/nishi_boot_fs.img); emu models INT reads only; no /dev. expect_exit: 0 license_tier: ORIGINAL 20import "nx_syscalls.nx" 21import "nx_sha256.nx" 22const DISK_MAGIC_200000: i64 = 200000 23const DISK_MAGIC_32767: i64 = 32767 24const DISK_MAGIC_65536: i64 = 65536 25 26const DISK_SZ: i64 = 4096 27const PBYTE: i64 = 512 28const OBJSTART_REL: i64 = 512 29const PART_TYPE_NISHI: i64 = 0x9E 30const MNT_OK: i64 = 0 31const MNT_BADMAGIC: i64 = 1 32const MNT_ROOT_MISMATCH: i64 = 2 33const MNT_NOTFOUND: i64 = 3 34const MNT_INTEGRITY: i64 = 4 35 36func ui_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 37func ui_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;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{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 38func ui_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 39func ui_contains(hay: *u8, hn: i64, ndl: *u8, nn: i64) -> i64 { 40 if nn==0 { return 1 } 41 var i: i64=0 42 while i+nn <= hn { var j: i64=0; var ok: i64=1; while j<nn { if hay[i+j]!=ndl[j] { ok=0; j=nn } else { j=j+1 } } if ok==1 { return 1 } i=i+1 } 43 return 0 44} 45func cid_eq(a: *u8, b: *u8) -> i64 { var i: i64=0; while i<32 { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } 46func wr_u32_le(d: *u8, off: i64, v: i64) -> i64 { d[off]=(v & 0xFF) as u8; d[off+1]=((v>>8)&0xFF) as u8; d[off+2]=((v>>16)&0xFF) as u8; d[off+3]=((v>>24)&0xFF) as u8; return 0 } 47func rd_u32_le(d: *u8, off: i64) -> i64 { return (d[off] as i64) | ((d[off+1] as i64)<<8) | ((d[off+2] as i64)<<16) | ((d[off+3] as i64)<<24) } 48func sha_slice(d: *u8, off: i64, len: i64, out: *u8) -> i64 { sha256_digest(((d as i64)+off) as *u8, len, out); return 0 } 49 50// ---- 16-bit real-mode + BIOS-INT emu (from C4) ---- 51func emu_x86_real16_disk(mem: *u8, disk: *u8, entry: i64, console: *u8, clen: *i64) -> i64 { 52 var ip: i64 = entry 53 var ax: i64 = 0 54 var bx: i64 = 0 55 var cx: i64 = 0 56 var dx: i64 = 0 57 var si: i64 = 0 58 var zf: i64 = 0 59 var guard: i64 = 0 60 while guard < DISK_MAGIC_200000 { 61 guard = guard + 1 62 let op: i64 = mem[ip] as i64 63 if op == 0xF4 { return 0 } 64 var h: i64 = 0 65 if h==0 { if op==0xBE { si = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 66 if h==0 { if op==0xB8 { ax = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 67 if h==0 { if op==0xBB { bx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 68 if h==0 { if op==0xB9 { cx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 69 if h==0 { if op==0xBA { dx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 70 if h==0 { if op==0xAC { let al: i64 = mem[si] as i64; ax = (ax & 0xFF00) | al; si=si+1; ip=ip+1; h=1 } } 71 if h==0 { if op==0x08 { let al2: i64 = ax & 0xFF; if al2==0 { zf=1 } else { zf=0 } ip=ip+2; h=1 } } 72 if h==0 { if op==0x74 { var r: i64 = mem[ip+1] as i64; if r>127 { r=r-256 } if zf==1 { ip=ip+2+r } else { ip=ip+2 } h=1 } } 73 if h==0 { if op==0xB4 { ax = (ax & 0xFF) | ((mem[ip+1] as i64)<<8); ip=ip+2; h=1 } } 74 if h==0 { if op==0xEB { var r2: i64 = mem[ip+1] as i64; if r2>127 { r2=r2-256 } ip=ip+2+r2; h=1 } } 75 if h==0 { if op==0xE9 { var r3: i64 = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); if r3>DISK_MAGIC_32767 { r3=r3-DISK_MAGIC_65536 } ip=ip+3+r3; h=1 } } 76 if h==0 { if op==0xCD { 77 let vec: i64 = mem[ip+1] as i64 78 let ah: i64 = (ax >> 8) & 0xFF 79 if vec==0x10 { if ah==0x0E { console[clen[0]]=(ax & 0xFF) as u8; clen[0]=clen[0]+1 } } 80 if vec==0x13 { if ah==0x02 { 81 let count: i64 = ax & 0xFF 82 let sector: i64 = cx & 0xFF 83 let lba: i64 = sector - 1 84 var s: i64 = 0 85 while s < count*512 { mem[bx + s] = disk[lba*512 + s]; s=s+1 } 86 ax = ax & 0xFF 87 } } 88 ip=ip+2; h=1 89 } } 90 if h==0 { return 0 - 1 } 91 } 92 return 0 - 2 93} 94 95// ---- NishiFS object/dir helpers (from C4) ---- 96func put_obj(d: *u8, cursor: i64, blob: *u8, n: i64, cidout: *u8) -> i64 { 97 sha256_digest(blob, n, cidout) 98 var i: i64=0; while i<32 { d[cursor+i]=cidout[i]; i=i+1 } 99 wr_u32_le(d, cursor+32, n) 100 i=0; while i<n { d[cursor+36+i]=blob[i]; i=i+1 } 101 return cursor + 36 + n 102} 103func find_obj(d: *u8, start: i64, endb: i64, cid: *u8, outlen: *i64) -> i64 { 104 var c: i64 = start 105 while c + 36 <= endb { 106 var same: i64 = 1; var i: i64 = 0 107 while i < 32 { if d[c+i]!=cid[i] { same=0; i=32 } else { i=i+1 } } 108 let ln: i64 = rd_u32_le(d, c+32) 109 if same==1 { outlen[0]=ln; return c+36 } 110 c = c + 36 + ln 111 } 112 return 0 - 1 113} 114func dir_find(d: *u8, base: i64, len: i64, name: *u8, cidout: *u8) -> i64 { 115 var c: i64 = base 116 let endd: i64 = base + len 117 while c < endd { 118 var k: i64 = 0; var same: i64 = 1 119 while d[c] != (0 as u8) { if name[k] != d[c] { same=0 } c=c+1; k=k+1 } 120 if name[k] != (0 as u8) { same=0 } 121 c = c + 1 122 if same==1 { var i: i64=0; while i<32 { cidout[i]=d[c+i]; i=i+1 } return 1 } 123 c = c + 32 124 } 125 return 0 126} 127 128// FORMAT a BOOTABLE NishiFS disk: sector-0 boot stub + partition table + NishiFS partition holding the rootfs. 129func format_boot_disk(d: *u8, nameA: *u8, A: *u8, nA: i64, nameB: *u8, B: *u8, nB: i64) -> i64 { 130 var z: i64=0; while z<DISK_SZ { d[z]=0 as u8; z=z+1 } 131 // ---- sector 0: 16-bit MBR boot stub -- print "NISHI BOOT" via INT10h, then HLT (loaded at 0x7C00) ---- 132 var q: i64 = 0 133 d[q]=0xBE as u8; let si_q: i64 = q+1; q=q+3 // mov si, imm16 (patched) 134 let loop_q: i64 = q 135 d[q]=0xAC as u8; q=q+1 // lodsb 136 d[q]=0x08 as u8; d[q+1]=0xC0 as u8; q=q+2 // or al,al 137 d[q]=0x74 as u8; let jz_q: i64 = q+1; q=q+2 // jz hang 138 d[q]=0xB4 as u8; d[q+1]=0x0E as u8; q=q+2 // mov ah,0x0E 139 d[q]=0xCD as u8; d[q+1]=0x10 as u8; q=q+2 // int 0x10 140 d[q]=0xEB as u8; d[q+1]=((loop_q-(q+2)) & 0xFF) as u8; q=q+2 // jmp loop 141 let hang_q: i64 = q 142 d[q]=0xF4 as u8; q=q+1 // hlt 143 let msg_q: i64 = q 144 let msg: *u8 = "NISHI BOOT\x0D\x0A\x00" 145 var mi: i64=0; while msg[mi]!=(0 as u8) { d[q]=msg[mi]; q=q+1; mi=mi+1 } d[q]=0 as u8; q=q+1 146 d[jz_q] = ((hang_q-(jz_q+1)) & 0xFF) as u8 // patch jz -> hang 147 let si_abs: i64 = 0x7C00 + msg_q 148 d[si_q] = (si_abs & 0xFF) as u8 149 d[si_q+1] = ((si_abs>>8) & 0xFF) as u8 150 // ---- partition table @446 + signature ---- 151 let p: i64 = 446 152 d[p+0]=0x80 as u8; d[p+2]=0x02 as u8; d[p+4]=PART_TYPE_NISHI as u8; d[p+5]=0xFE as u8; d[p+6]=0xFF as u8; d[p+7]=0xFF as u8 153 wr_u32_le(d, p+8, 1) 154 wr_u32_le(d, p+12, (DISK_SZ/512) - 1) 155 d[510]=0x55 as u8; d[511]=0xAA as u8 156 // ---- NishiFS partition @ LBA 1: superblock + 2 rootfs objects + Merkle dir ---- 157 let cidA: *u8 = sys_mmap(40) 158 let cidB: *u8 = sys_mmap(40) 159 var cur: i64 = PBYTE + OBJSTART_REL 160 cur = put_obj(d, cur, A, nA, cidA) 161 cur = put_obj(d, cur, B, nB, cidB) 162 let dir_abs: i64 = cur 163 var w: i64 = dir_abs 164 var i: i64=0; while nameA[i]!=(0 as u8) { d[w]=nameA[i]; w=w+1; i=i+1 } d[w]=0 as u8; w=w+1 165 i=0; while i<32 { d[w]=cidA[i]; w=w+1; i=i+1 } 166 i=0; while nameB[i]!=(0 as u8) { d[w]=nameB[i]; w=w+1; i=i+1 } d[w]=0 as u8; w=w+1 167 i=0; while i<32 { d[w]=cidB[i]; w=w+1; i=i+1 } 168 let dir_len: i64 = w - dir_abs 169 let root: *u8 = sys_mmap(40) 170 sha_slice(d, dir_abs, dir_len, root) 171 let mg: *u8 = "NISHIFS1\x00" as *u8 172 i=0; while i<8 { d[PBYTE+i]=mg[i]; i=i+1 } 173 i=0; while i<32 { d[PBYTE+8+i]=root[i]; i=i+1 } 174 wr_u32_le(d, PBYTE+40, 2) 175 wr_u32_le(d, PBYTE+44, OBJSTART_REL) 176 wr_u32_le(d, PBYTE+48, dir_abs - PBYTE) 177 wr_u32_le(d, PBYTE+52, dir_len) 178 return 0 179} 180 181// BOOT: execute the on-disk sector-0 boot code on the emu. 182func boot_exec(disk: *u8, console: *u8, clen: *i64) -> i64 { 183 let mem: *u8 = sys_mmap(DISK_MAGIC_65536) 184 var k: i64=0; while k<DISK_MAGIC_65536 { mem[k]=0 as u8; k=k+1 } 185 var j: i64=0; while j<512 { mem[0x7C00+j]=disk[j]; j=j+1 } 186 clen[0]=0 187 return emu_x86_real16_disk(mem, disk, 0x7C00, console, clen) 188} 189 190// MOUNT the NishiFS rootfs and read a file by name (the kernel's FS driver), off the disk. 191func mount_read(d: *u8, name: *u8, out: *u8, cap: i64, lenout: *i64) -> i64 { 192 var lba: i64 = 0 - 1 193 var e: i64 = 0 194 while e < 4 { let off: i64 = 446 + e*16; if (d[off] as i64)==0x80 { if (d[off+4] as i64)==PART_TYPE_NISHI { lba = rd_u32_le(d, off+8); e=4 } else { e=e+1 } } else { e=e+1 } } 195 if lba < 0 { return MNT_NOTFOUND } 196 let pb: i64 = lba * 512 197 let mg: *u8 = "NISHIFS1\x00" as *u8 198 var i: i64=0; while i<8 { if d[pb+i]!=mg[i] { return MNT_BADMAGIC } i=i+1 } 199 let objstart_rel: i64 = rd_u32_le(d, pb+44) 200 let dir_off_rel: i64 = rd_u32_le(d, pb+48) 201 let dir_len: i64 = rd_u32_le(d, pb+52) 202 let dir_abs: i64 = pb + dir_off_rel 203 let root_stored: *u8 = sys_mmap(40) 204 i=0; while i<32 { root_stored[i]=d[pb+8+i]; i=i+1 } 205 let root_calc: *u8 = sys_mmap(40) 206 sha_slice(d, dir_abs, dir_len, root_calc) 207 if cid_eq(root_calc, root_stored)==0 { return MNT_ROOT_MISMATCH } 208 let fcid: *u8 = sys_mmap(40) 209 if dir_find(d, dir_abs, dir_len, name, fcid)==0 { return MNT_NOTFOUND } 210 let lenp: *i64 = sys_mmap(8) as *i64 211 let boff: i64 = find_obj(d, pb + objstart_rel, dir_abs, fcid, lenp) 212 if boff < 0 { return MNT_NOTFOUND } 213 let h: *u8 = sys_mmap(40) 214 sha_slice(d, boff, lenp[0], h) 215 if cid_eq(h, fcid)==0 { return MNT_INTEGRITY } 216 var m: i64 = lenp[0]; if m > cap { m = cap } 217 var j: i64=0; while j<m { out[j]=d[boff+j]; j=j+1 } 218 lenout[0]=lenp[0] 219 return MNT_OK 220} 221 222func ui_read(path: *u8, out: *u8, cap: i64) -> i64 { 223 let fd: i64 = sys_openat_rd(path) 224 if fd < 0 { return 0-1 } 225 var n: i64=0; var go: i64=1 226 while go==1 { let rr: i64 = sys_read(fd, ((out as i64)+n) as *u8, cap-n); if rr<=0 { go=0 } else { n=n+rr } if n>=cap { go=0 } } 227 sys_close(fd) 228 return n 229} 230 231func main() -> i64 { 232 ui_puts("ladder C8: BOOT-FROM-NishiFS -- power on -> kernel mounts its rootfs from the content-addressed FS\n" as *u8) 233 234 let INIT: *u8 = "#!nish init -- mount rootfs, start the userland\x00" as *u8 235 let MOTD: *u8 = "Welcome to NishiOS -- booted from a content-addressed filesystem\x00" as *u8 236 let nI: i64 = ui_slen(INIT) 237 let nM: i64 = ui_slen(MOTD) 238 239 let d: *u8 = sys_mmap(DISK_SZ + 16) 240 format_boot_disk(d, "init\x00" as *u8, INIT, nI, "motd\x00" as *u8, MOTD, nM) 241 242 // persist + re-read (run off the on-disk bytes) 243 let fd: i64 = sys_openat_wr("knowledge/status/nishi_boot_fs.img\x00" as *u8, 0x1a4) 244 if fd<=0 { ui_puts("C8 RED: cannot write disk image\n" as *u8); sys_exit(1); return 1 } 245 sys_write(fd, d, DISK_SZ) 246 sys_close(fd) 247 let rd: *u8 = sys_mmap(DISK_SZ + 16) 248 let rn: i64 = ui_read("knowledge/status/nishi_boot_fs.img\x00" as *u8, rd, DISK_SZ) 249 ui_puts(" formatted + persisted knowledge/status/nishi_boot_fs.img ("); ui_num(rn); ui_puts(" bytes)\n" as *u8) 250 251 // PHASE 1: BOOT (emu executes sector-0 boot code) 252 let con: *u8 = sys_mmap(256) 253 let clen: *i64 = sys_mmap(8) as *i64 254 let brc: i64 = boot_exec(rd, con, clen) 255 ui_puts(" BOOT: emu executed sector-0 -> console: " as *u8); sys_write(1, con, clen[0]); ui_puts(" (rc=" as *u8); ui_num(brc); ui_puts(")\n" as *u8) 256 257 // PHASE 2: kernel mounts the NishiFS rootfs + reads /init by CID 258 let oi: *u8 = sys_mmap(256); let li: *i64 = sys_mmap(8) as *i64 259 let mr: i64 = mount_read(rd, "init\x00" as *u8, oi, 256, li) 260 var initok: i64=0 261 if mr==MNT_OK { if li[0]==nI { initok=1; var i: i64=0; while i<nI { if oi[i]!=INIT[i] { initok=0; i=nI } else { i=i+1 } } } } 262 263 // T5 setup: tamper init's object on a disk copy -> rootfs mount integrity fail 264 let bad: *u8 = sys_mmap(DISK_SZ + 16) 265 var c: i64=0; while c<DISK_SZ { bad[c]=rd[c]; c=c+1 } 266 let initData: i64 = PBYTE + OBJSTART_REL + 36 + 4 // into init's bytes 267 bad[initData] = (((bad[initData] as i64)+1) & 0xFF) as u8 268 let ox: *u8 = sys_mmap(256); let lx: *i64 = sys_mmap(8) as *i64 269 let mr_bad: i64 = mount_read(bad, "init\x00" as *u8, ox, 256, lx) 270 271 let banner: *u8 = "NISHI BOOT" as *u8 272 var pass: i64=0 273 var ttl: i64=0 274 ttl=ttl+1; ui_puts(" T1 disk BOOTS (emu executes sector-0 boot code -> 'NISHI BOOT'): " as *u8); if brc==0 { if ui_contains(con, clen[0], banner, 10)==1 { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } } else { ui_puts("FAIL\n" as *u8) } 275 ttl=ttl+1; ui_puts(" T2 partition is NishiFS (status 0x80 + type 0x9E): " as *u8); if (rd[446] as i64)==0x80 { if (rd[446+4] as i64)==PART_TYPE_NISHI { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } } else { ui_puts("FAIL\n" as *u8) } 276 ttl=ttl+1; ui_puts(" T3 kernel MOUNTS rootfs + reads /init by CID (bytes match): " as *u8); if initok==1 { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL (mr="); ui_num(mr); ui_puts(")\n" as *u8) } 277 ttl=ttl+1; ui_puts(" T4 whole-rootfs root-CID integrity holds (mount didn't ROOT_MISMATCH): " as *u8); if mr != MNT_ROOT_MISMATCH { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } 278 ttl=ttl+1; ui_puts(" T5 liar-kill: tamper /init object -> rootfs mount MNT_INTEGRITY (corrupt rootfs caught): " as *u8); if mr_bad==MNT_INTEGRITY { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL (mr_bad="); ui_num(mr_bad); ui_puts(")\n" as *u8) } 279 ttl=ttl+1; ui_puts(" T6 runs off the PERSISTED + re-read disk (rn==DISK_SZ): " as *u8); if rn==DISK_SZ { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } 280 281 ui_puts("NISHIFS-BOOT-GATE passed " as *u8); ui_num(pass); ui_puts("/" as *u8); ui_num(ttl) 282 if pass==ttl { ui_puts(" verdict=GREEN (BOOT-FROM-NishiFS: disk boots + kernel mounts its rootfs from the content-addressed FS + reads /init by CID with integrity; NishiFS-aware asm bootloader + R10 hardware = next)\n" as *u8); sys_exit(0); return 0 } 283 ui_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 284}