code wiki / _hdl_build / nx_nishi_usb_install.nx

nx_nishi_usb_install.nx source

↩ module page · 293 lines · 16819 B

1// nx_nishi_usb_install.nx -- x86 ladder C3 (installer/disk side): the NISHI INSTALLER PROGRAM. 2// 3// The capstone proved "a kernel that runs a userland"; C1 gave the bootable image a real MBR partition 4// table. This rung is the PUBLISHER'S actual tool: a program that installs the partitioned OS onto a 5// target disk WITHOUT EVER BRICKING IT. It composes two proven never-brick primitives: 6// * nx_flash (runtime/nx_flash_test.nx): REFUSE the system disk (/dev/sda) BY CONSTRUCTION, then 7// WRITE + READ-BACK + sha256 HASH-VERIFY byte-for-byte (never write blind, unlike dd/Rufus). 8// * nx_fw_safeflash (golden recovery): keep a known-good GOLDEN anchor; if the write goes bad, 9// AUTO-RESTORE from golden so the target is left BOOTABLE, never bricked. 10// and adds the OS-install specifics: the source IS the C1 partitioned image, and the installed target 11// is PROVEN bootable (executed on the sovereign 16-bit/INT13h emu -> 'NISHIOS KERNEL') and still 12// carries its partition table. 13// 14// KAT: (T1) install to a safe target -> OK + sha256 byte-perfect; (T2) never-brick: refuse /dev/sda; 15// (T3) the refusal is DISCRIMINATING (allows /dev/sdb + files, so T2 is a real check not refuse-all); 16// (T4) the installed target BOOTS to 'NISHIOS KERNEL'; (T5) it keeps the C1 partition table (0x80/0x9E); 17// (T6) golden recovery: a corrupt write -> RECOVERED + the target STILL boots (never bricked); 18// (T7, liar-kill) verifying a TAMPERED target returns mismatch (<0), so "verified" is a real sha256 19// match, not a hardcoded PASS. 20// 21// NEVER-BRICK (Rule 26): refuses the system disk by construction; all writes go to /tmp/ FILES (never a 22// real device); golden recovery guarantees a bootable target. A real install targets /dev/sdX -- the 23// operator runs it with the device + this safety guard (R10). No real-device writes here. 24// nx_sha256 + nx_syscalls are imported (the proven combo from nx_flash_test / nx_fw_safeflash); the 25// emu + image author + boot harness are inlined from the proven nx_nishi_usb_image / _parttable (the 26// standalone-main import exception the codebase already uses). 27// expect_exit: 0 license_tier: ORIGINAL 28import "nx_syscalls.nx" 29import "nx_sha256.nx" 30const IMG_MAGIC_200000: i64 = 200000 31const IMG_MAGIC_32767: i64 = 32767 32const IMG_MAGIC_65536: i64 = 65536 33const IMG_MAGIC_1024: i64 = 1024 34 35func 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 } 36func 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 } 37func ui_contains(hay: *u8, hn: i64, ndl: *u8, nn: i64) -> i64 { 38 if nn==0 { return 1 } 39 var i: i64 = 0 40 while i + nn <= hn { 41 var j: i64 = 0 42 var ok: i64 = 1 43 while j < nn { if hay[i+j]!=ndl[j] { ok=0; j=nn } else { j=j+1 } } 44 if ok==1 { return 1 } 45 i=i+1 46 } 47 return 0 48} 49func fl_h32eq(a: *u8, b: *u8) -> i64 { var i: i64=0; while i<32 { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } 50func fl_hexb(v: i64) -> i64 { let hi: i64=(v>>4)&15; let lo: i64=v&15; var c1: i64=48+hi; if hi>9 { c1=87+hi } var c2: i64=48+lo; if lo>9 { c2=87+lo } let o: *u8=sys_mmap(4); o[0]=c1 as u8; o[1]=c2 as u8; sys_write(1,o,2); return 0 } 51 52// little-endian u32 helpers + bootable-partition scan (from nx_nishi_usb_parttable). 53func wr_u32_le(img: *u8, off: i64, v: i64) -> i64 { 54 img[off]=(v & 0xFF) as u8; img[off+1]=((v>>8) & 0xFF) as u8; img[off+2]=((v>>16) & 0xFF) as u8; img[off+3]=((v>>24) & 0xFF) as u8; return 0 55} 56 57// ---- nx_flash never-brick primitives (verbatim from runtime/nx_flash_test.nx) ---- 58// SAFETY: refuse the system disk (/dev/sda...). files + removable /dev/sdb+ allowed. 59func fl_safe(target: *u8) -> i64 { 60 if target[0]==(47 as u8) { if target[1]==(100 as u8) { if target[2]==(101 as u8) { if target[3]==(118 as u8) { if target[4]==(47 as u8) { if target[5]==(115 as u8) { if target[6]==(100 as u8) { if target[7]==(97 as u8) { return 0 } } } } } } } } 61 return 1 62} 63func fl_write(path: *u8, buf: *u8, n: i64) -> i64 { let fd: i64=sys_openat_wr(path, 0x1a4); if fd<=0 { return 0-1 } sys_write(fd, buf, n); sys_close(fd); return 0 } 64// VERIFY: read the target back, compare its sha256 to the source hash. 0=match, -1=mismatch, -3=read-fail. 65func fl_verify(img: *u8, n: i64, target: *u8) -> i64 { 66 let lenp: *i64 = sys_mmap(8) as *i64 67 let rb: *u8 = sys_read_file(target, lenp) 68 if (rb as i64)==0 { return 0-3 } 69 if lenp[0] != n { return 0-1 } 70 let h1: *u8 = sys_mmap(40) 71 let h2: *u8 = sys_mmap(40) 72 sha256_digest(img, n, h1) 73 sha256_digest(rb, lenp[0], h2) 74 if fl_h32eq(h1, h2)==1 { return 0 } 75 return 0-1 76} 77 78// ---- 16-bit real-mode + BIOS-INT emu (verbatim from nx_nishi_usb_image / _parttable) ---- 79func emu_x86_real16_disk(mem: *u8, disk: *u8, entry: i64, console: *u8, clen: *i64) -> i64 { 80 var ip: i64 = entry 81 var ax: i64 = 0 82 var bx: i64 = 0 83 var cx: i64 = 0 84 var dx: i64 = 0 85 var si: i64 = 0 86 var zf: i64 = 0 87 var guard: i64 = 0 88 while guard < IMG_MAGIC_200000 { 89 guard = guard + 1 90 let op: i64 = mem[ip] as i64 91 if op == 0xF4 { return 0 } 92 var h: i64 = 0 93 if h==0 { if op==0xBE { si = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 94 if h==0 { if op==0xB8 { ax = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 95 if h==0 { if op==0xBB { bx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 96 if h==0 { if op==0xB9 { cx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 97 if h==0 { if op==0xBA { dx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 98 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 } } 99 if h==0 { if op==0x08 { let al2: i64 = ax & 0xFF; if al2==0 { zf=1 } else { zf=0 } ip=ip+2; h=1 } } 100 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 } } 101 if h==0 { if op==0xB4 { ax = (ax & 0xFF) | ((mem[ip+1] as i64)<<8); ip=ip+2; h=1 } } 102 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 } } 103 if h==0 { if op==0xE9 { var r3: i64 = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); if r3>IMG_MAGIC_32767 { r3=r3-IMG_MAGIC_65536 } ip=ip+3+r3; h=1 } } 104 if h==0 { if op==0xCD { 105 let vec: i64 = mem[ip+1] as i64 106 let ah: i64 = (ax >> 8) & 0xFF 107 if vec==0x10 { if ah==0x0E { console[clen[0]]=(ax & 0xFF) as u8; clen[0]=clen[0]+1 } } 108 if vec==0x13 { if ah==0x02 { 109 let count: i64 = ax & 0xFF 110 let sector: i64 = cx & 0xFF 111 let lba: i64 = sector - 1 112 var s: i64 = 0 113 while s < count*512 { mem[bx + s] = disk[lba*512 + s]; s=s+1 } 114 ax = ax & 0xFF 115 } } 116 ip=ip+2; h=1 117 } } 118 if h==0 { return 0 - 1 } 119 } 120 return 0 - 2 121} 122 123const IMG_SZ: i64 = 1536 124const PART_TYPE_NISHI: i64 = 0x9E 125const INST_OK: i64 = 0 126const INST_RECOVERED: i64 = 2 127const INST_UNSAFE: i64 = 7 128const INST_FATAL: i64 = 5 129 130// author the C1 partitioned OS image (MBR boot chain + stage2 + kernel + MBR partition table). 131func build_image(img: *u8) -> i64 { 132 var z: i64=0 133 while z<IMG_SZ { img[z]=0 as u8; z=z+1 } 134 img[0]=0xB8 as u8; img[1]=0x02 as u8; img[2]=0x02 as u8 135 img[3]=0xBB as u8; img[4]=0x00 as u8; img[5]=0x80 as u8 136 img[6]=0xB9 as u8; img[7]=0x02 as u8; img[8]=0x00 as u8 137 img[9]=0xBA as u8; img[10]=0x80 as u8; img[11]=0x00 as u8 138 img[12]=0xCD as u8; img[13]=0x13 as u8 139 let e9off: i64 = 14 140 let rel16: i64 = 0x8000 - (0x7C00 + e9off + 3) 141 img[14]=0xE9 as u8; img[15]=(rel16 & 0xFF) as u8; img[16]=((rel16>>8) & 0xFF) as u8 142 img[510]=0x55 as u8; img[511]=0xAA as u8 143 144 var q: i64 = 0 145 img[512+q]=0xBE as u8; let si_q: i64 = q+1; q=q+3 146 let loop_q: i64 = q 147 img[512+q]=0xAC as u8; q=q+1 148 img[512+q]=0x08 as u8; img[512+q+1]=0xC0 as u8; q=q+2 149 img[512+q]=0x74 as u8; let jz_q: i64 = q+1; q=q+2 150 img[512+q]=0xB4 as u8; img[512+q+1]=0x0E as u8; q=q+2 151 img[512+q]=0xCD as u8; img[512+q+1]=0x10 as u8; q=q+2 152 img[512+q]=0xEB as u8; img[512+q+1]=((loop_q-(q+2)) & 0xFF) as u8; q=q+2 153 let tok_q: i64 = q 154 let relK: i64 = 0x8200 - (0x8000 + tok_q + 3) 155 img[512+q]=0xE9 as u8; img[512+q+1]=(relK & 0xFF) as u8; img[512+q+2]=((relK>>8) & 0xFF) as u8; q=q+3 156 let msg2_q: i64 = q 157 let msg2: *u8 = "NishiOS booting...\x0D\x0A\x00" 158 var mi: i64=0 159 while msg2[mi]!=(0 as u8) { img[512+q]=msg2[mi]; q=q+1; mi=mi+1 } 160 img[512+q]=0 as u8; q=q+1 161 img[512+jz_q] = ((tok_q - (jz_q+1)) & 0xFF) as u8 162 let si2_abs: i64 = 0x8000 + msg2_q 163 img[512+si_q] = (si2_abs & 0xFF) as u8 164 img[512+si_q+1] = ((si2_abs>>8) & 0xFF) as u8 165 166 var r0: i64 = 0 167 img[IMG_MAGIC_1024+r0]=0xBE as u8; let si_r: i64 = r0+1; r0=r0+3 168 let loop_r: i64 = r0 169 img[IMG_MAGIC_1024+r0]=0xAC as u8; r0=r0+1 170 img[IMG_MAGIC_1024+r0]=0x08 as u8; img[IMG_MAGIC_1024+r0+1]=0xC0 as u8; r0=r0+2 171 img[IMG_MAGIC_1024+r0]=0x74 as u8; let jz_r: i64 = r0+1; r0=r0+2 172 img[IMG_MAGIC_1024+r0]=0xB4 as u8; img[IMG_MAGIC_1024+r0+1]=0x0E as u8; r0=r0+2 173 img[IMG_MAGIC_1024+r0]=0xCD as u8; img[IMG_MAGIC_1024+r0+1]=0x10 as u8; r0=r0+2 174 img[IMG_MAGIC_1024+r0]=0xEB as u8; img[IMG_MAGIC_1024+r0+1]=((loop_r-(r0+2)) & 0xFF) as u8; r0=r0+2 175 let hang_r: i64 = r0 176 img[IMG_MAGIC_1024+r0]=0xF4 as u8; r0=r0+1 177 let msgK_r: i64 = r0 178 let msgK: *u8 = "NISHIOS KERNEL\x0D\x0A\x00" 179 var ki: i64=0 180 while msgK[ki]!=(0 as u8) { img[IMG_MAGIC_1024+r0]=msgK[ki]; r0=r0+1; ki=ki+1 } 181 img[IMG_MAGIC_1024+r0]=0 as u8; r0=r0+1 182 img[IMG_MAGIC_1024+jz_r] = ((hang_r - (jz_r+1)) & 0xFF) as u8 183 let siK_abs: i64 = 0x8200 + msgK_r 184 img[IMG_MAGIC_1024+si_r] = (siK_abs & 0xFF) as u8 185 img[IMG_MAGIC_1024+si_r+1] = ((siK_abs>>8) & 0xFF) as u8 186 187 // MBR partition table at offset 446: one bootable Nishi partition (C1). 188 let p: i64 = 446 189 img[p+0]=0x80 as u8; img[p+1]=0x00 as u8; img[p+2]=0x02 as u8; img[p+3]=0x00 as u8 190 img[p+4]=PART_TYPE_NISHI as u8; img[p+5]=0xFE as u8; img[p+6]=0xFF as u8; img[p+7]=0xFF as u8 191 wr_u32_le(img, p+8, 1) 192 wr_u32_le(img, p+12, 2) 193 return 0 194} 195 196func boot_image(img: *u8, console: *u8, clen: *i64, loaded: *i64) -> i64 { 197 let mem: *u8 = sys_mmap(IMG_MAGIC_65536) 198 var k: i64=0 199 while k<IMG_MAGIC_65536 { mem[k]=0 as u8; k=k+1 } 200 var j: i64=0 201 while j<512 { mem[0x7C00+j]=img[j]; j=j+1 } 202 loaded[0] = mem[0x8000] as i64 203 clen[0]=0 204 let rc: i64 = emu_x86_real16_disk(mem, img, 0x7C00, console, clen) 205 loaded[1] = mem[0x8200] as i64 206 return rc 207} 208 209// THE INSTALLER: composes nx_flash (refuse-system-disk + sha256 read-back verify) + nx_fw_safeflash 210// (golden recovery). install src[0,n) onto target with golden as the recovery anchor. 211// corrupt=1 simulates a torn/bad write. returns INST_OK / INST_RECOVERED / INST_UNSAFE / INST_FATAL. 212func nx_install(src: *u8, n: i64, target: *u8, golden: *u8, corrupt: i64) -> i64 { 213 if fl_safe(target)==0 { return INST_UNSAFE } // never-brick: refuse the system disk (no blind write) 214 fl_write(golden, src, n) // keep a known-good golden recovery anchor 215 if corrupt==1 { 216 let bad: *u8 = sys_mmap(n+16) 217 var i: i64=0; while i<n { bad[i]=src[i]; i=i+1 } 218 bad[600] = (((bad[600] as i64) + 1) & 0xFF) as u8 // flip a byte -> simulate a bad write 219 fl_write(target, bad, n) 220 } else { 221 fl_write(target, src, n) 222 } 223 var v: i64 = fl_verify(src, n, target) // read-back sha256 verify 224 if v==0 { return INST_OK } 225 let lenp: *i64 = sys_mmap(8) as *i64 // bad write -> AUTO-RESTORE from golden 226 let g: *u8 = sys_read_file(golden, lenp) 227 if (g as i64)==0 { return INST_FATAL } 228 fl_write(target, g, lenp[0]) 229 v = fl_verify(src, n, target) 230 if v==0 { return INST_RECOVERED } // restored -> target bootable, never bricked 231 return INST_FATAL 232} 233 234func main() -> i64 { 235 ui_puts("x86 ladder C3: the NISHI INSTALLER PROGRAM (never-brick: refuse-system-disk + sha256 read-back-verify + golden recovery)\n" as *u8) 236 237 // SOURCE = the C1 partitioned OS image, built inline. 238 let src: *u8 = sys_mmap(IMG_SZ + 16) 239 build_image(src) 240 let cid: *u8 = sys_mmap(40) 241 sha256_digest(src, IMG_SZ, cid) 242 ui_puts(" OS image bytes=" as *u8); ui_num(IMG_SZ); ui_puts(" CID=sha256:" as *u8) 243 var ci: i64=0; while ci<8 { fl_hexb(cid[ci] as i64); ci=ci+1 } ui_puts("...\n" as *u8) 244 245 let target: *u8 = "/tmp/nishi_install_target.img\x00" as *u8 246 let golden: *u8 = "/tmp/nishi_install_golden.img\x00" as *u8 247 248 // T1: install to a safe target. 249 let r1: i64 = nx_install(src, IMG_SZ, target, golden, 0) 250 let v1: i64 = fl_verify(src, IMG_SZ, target) 251 252 // read the installed target back for the boot + partition checks (snapshot before later writes). 253 let lenp: *i64 = sys_mmap(8) as *i64 254 let tgt: *u8 = sys_read_file(target, lenp) 255 let con: *u8 = sys_mmap(256) 256 let clen: *i64 = sys_mmap(8) as *i64 257 let ld: *i64 = sys_mmap(64) as *i64 258 let rcb: i64 = boot_image(tgt, con, clen, ld) 259 260 // T6: corrupt install -> golden recovery. 261 let r6: i64 = nx_install(src, IMG_SZ, target, golden, 1) 262 let lenp2: *i64 = sys_mmap(8) as *i64 263 let tgt2: *u8 = sys_read_file(target, lenp2) 264 let con2: *u8 = sys_mmap(256) 265 let clen2: *i64 = sys_mmap(8) as *i64 266 let ld2: *i64 = sys_mmap(64) as *i64 267 let rcb2: i64 = boot_image(tgt2, con2, clen2, ld2) 268 269 // T7: tamper the target -> verify must fail. 270 fl_write(target, "TAMPERED-NOT-THE-OS\x00" as *u8, 19) 271 let v7: i64 = fl_verify(src, IMG_SZ, target) 272 273 let kbanner: *u8 = "NISHIOS KERNEL" as *u8 274 var pass: i64=0 275 var ttl: i64=0 276 ttl=ttl+1; ui_puts(" T1 install to safe target -> OK + sha256 byte-perfect: " as *u8); if r1==INST_OK { if v1==0 { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } } else { ui_puts("FAIL\n" as *u8) } 277 ttl=ttl+1; ui_puts(" T2 never-brick: refuse install to /dev/sda (system disk): " as *u8); if nx_install(src, IMG_SZ, "/dev/sda\x00" as *u8, golden, 0)==INST_UNSAFE { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } 278 ttl=ttl+1; ui_puts(" T3 refusal is DISCRIMINATING (allows /dev/sdb + files): " as *u8); if fl_safe("/dev/sdb\x00" as *u8)==1 { if fl_safe("/tmp/usb.img\x00" as *u8)==1 { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } } else { ui_puts("FAIL\n" as *u8) } 279 ttl=ttl+1; ui_puts(" T4 installed target BOOTS (emu -> 'NISHIOS KERNEL'): " as *u8); if rcb==0 { if ui_contains(con, clen[0], kbanner, 14)==1 { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } } else { ui_puts("FAIL\n" as *u8) } 280 ttl=ttl+1; ui_puts(" T5 installed target keeps the C1 partition table (0x80 boot / 0x9E Nishi): " as *u8); if (tgt[446] as i64)==0x80 { if (tgt[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) } 281 ttl=ttl+1; ui_puts(" T6 golden recovery: corrupt write -> RECOVERED + STILL boots (never bricked): " as *u8); if r6==INST_RECOVERED { if rcb2==0 { if ui_contains(con2, clen2[0], kbanner, 14)==1 { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } } else { ui_puts("FAIL\n" as *u8) } } else { ui_puts("FAIL\n" as *u8) } 282 ttl=ttl+1; ui_puts(" T7 liar-kill: verify a TAMPERED target -> mismatch (<0) so 'verified' is a real sha256 match: " as *u8); if v7 < 0 { pass=pass+1; ui_puts("PASS\n" as *u8) } else { ui_puts("FAIL\n" as *u8) } 283 284 ui_puts(" --- INSTALLER EXCEED (vs blind dd/Rufus, by-design) ---\n" as *u8) 285 ui_puts(" refuse-system-disk yes NO (writes blind)\n" as *u8) 286 ui_puts(" content-hash verify yes NO\n" as *u8) 287 ui_puts(" golden-recovery yes NO\n" as *u8) 288 ui_puts(" => EXCEEDS on never-brick + verify + recovery; BEHIND on real-device breadth (file-modeled; real /dev/sdX = operator, R10)\n" as *u8) 289 290 ui_puts("X86-USB-INSTALL-GATE passed " as *u8); ui_num(pass); ui_puts("/" as *u8); ui_num(ttl) 291 if pass==ttl { ui_puts(" verdict=GREEN (a never-brick Nishi installer: refuse-system-disk + sha256 read-back-verify + golden recovery; installs a bootable partitioned OS; real /dev/sdX = operator R10)\n" as *u8); sys_exit(0); return 0 } 292 ui_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 293}