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}