code wiki / _hdl_build / nx_nishios_net.nx

nx_nishios_net.nx source

↩ module page · 448 lines · 26830 B

1// nx_nishios_net.nx -- BROWSER-ON-ALL-OS arc, rung N3: the Nishi browser FETCHES over a NishiOS NIC. 2// 3// N1 rendered a disk page on NishiOS; N2 navigated by click; N4 wrote the window with executed x86. The 4// remaining NishiOS gap is the network. This rung builds the hardware-up NIC path: a MODELED network 5// interface (TX/RX descriptor registers + a doorbell) lives in the x86 RAM; the kernel driver programs 6// the TX descriptor and RINGS THE DOORBELL via EXECUTED x86 STORE instructions on the sovereign mini-emu; 7// the emu intercepts the doorbell store and runs the device, which reads the request out of the TX buffer 8// and delivers an HTTP 200 into the RX buffer. Crucially the response body is DERIVED FROM the request 9// (it echoes the requested path), so a hardcoded constant response cannot pass -- the liar-kill. The 10// browser then parses the HTTP headers and lays out the fetched body into the NishiOS desktop. 11// 12// KAT: T1 booted off the persisted image; T2 LONG mode + banner; T3 the executed x86 rang the doorbell 13// (device fired exactly once); T4 the device delivered (RX_STATUS==1) AND the x86 read that status back 14// (scratch==1); T5 the response is a real HTTP 200; T6 the body is CONTENT-DERIVED (contains the exact 15// requested path, and a decoy path is absent -- not a constant); T7 the browser laid out the fetched 16// body (ok, boxes); T8 the browser rendered it into the desktop (h1 bar pixels); T9 BMP exported at the 17// exact expected size. NEG/liar-kill: T10 a driver that programs the descriptor but NEVER rings the 18// doorbell gets NO delivery (RX_STATUS stays 0 -- delivery is caused by the executed doorbell store, not 19// a constant); T11 a 0-sector-load sibling image never reaches long mode. 20// 21// HONEST SEAM (stated, not hidden): the boot chain + the doorbell store execute as real x86 on the 22// sovereign emu; the device's peer is a HERMETIC loopback (it answers from the request) so the gate is 23// deterministic -- bridging the NIC's TX to the live sovereign TLS/HTTP stack for the REAL internet is 24// the named next rung (nx_nishios_net_wire). What this rung proves: the NIC descriptor/doorbell driver 25// path is real + executed, and the browser renders whatever the device delivers. 26// NEVER-BRICK (Rule 26): writes FILE artifacts only; models INT 13h *reads* + a loopback NIC; no /dev. 27// expect_exit: 0 license_tier: ORIGINAL 28import "nx_browser_render.nx" 29import "nx_fb.nx" 30const NB_MAGIC_200000: i64 = 200000 31const NB_MAGIC_32767: i64 = 32767 32const NB_MAGIC_65536: i64 = 65536 33const NB_MAGIC_100000: i64 = 100000 34 35func nb_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 nb_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 nb_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 38func nb_contains(hay: *u8, hn: i64, ndl: *u8, nn: i64) -> i64 { 39 if nn==0 { return 1 } 40 var i: i64 = 0 41 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 } 42 return 0 43} 44func nb_mode(cr0: i64, efer: i64) -> i64 { let pe: i64=cr0&1; let pg: i64=(cr0>>31)&1; let lme: i64=(efer>>8)&1; if pe==0 { return 0 } if pg==1 { if lme==1 { return 2 } } return 1 } 45 46// UNIFIED boot-disk emu (proven in nx_nishi_usb_longmode/_desktop and rungs N1/N2/N4). 47func nb_emu_boot_disk(mem: *u8, disk: *u8, entry: i64, console: *u8, clen: *i64, st: *i64) -> i64 { 48 var ip: i64=entry 49 var ax: i64=0 50 var bx: i64=0 51 var cx: i64=0 52 var dx: i64=0 53 var si: i64=0 54 var zf: i64=0 55 var rax: i64=0 56 var cr0: i64=0 57 var efer: i64=0 58 var guard: i64=0 59 st[0]=0; st[1]=0 60 while guard < NB_MAGIC_200000 { 61 guard = guard + 1 62 let op: i64 = mem[ip] as i64 63 if op == 0xF4 { st[0]=cr0; st[1]=nb_mode(cr0,efer); return 0 } 64 var h: i64 = 0 65 if h==0 { if op==0x48 { 66 if mem[ip+1]==(0xC7 as u8) { 67 let modrm: i64 = mem[ip+2] as i64 68 let imm: i64 = (mem[ip+3] as i64) | ((mem[ip+4] as i64)<<8) | ((mem[ip+5] as i64)<<16) | ((mem[ip+6] as i64)<<24) 69 if modrm==0xC0 { rax = imm } 70 ip=ip+7; h=1 71 } 72 } } 73 if h==0 { if op==0x0F { 74 let b1: i64 = mem[ip+1] as i64 75 if b1==0x22 { let m: i64=mem[ip+2] as i64; if ((m>>3)&7)==0 { cr0=rax }; ip=ip+3; h=1 } 76 if h==0 { if b1==0x30 { efer=rax; ip=ip+2; h=1 } } 77 if h==0 { if b1==0x05 { st[0]=cr0; st[1]=nb_mode(cr0,efer); return rax & 0xff } } 78 if h==0 { return 0 - 1 } 79 } } 80 if h==0 { if op==0xBE { si = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 81 if h==0 { if op==0xB8 { ax = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 82 if h==0 { if op==0xBB { bx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 83 if h==0 { if op==0xB9 { cx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 84 if h==0 { if op==0xBA { dx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 85 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 } } 86 if h==0 { if op==0x08 { let al2: i64 = ax & 0xFF; if al2==0 { zf=1 } else { zf=0 } ip=ip+2; h=1 } } 87 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 } } 88 if h==0 { if op==0xB4 { ax = (ax & 0xFF) | ((mem[ip+1] as i64)<<8); ip=ip+2; h=1 } } 89 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 } } 90 if h==0 { if op==0xE9 { var r3: i64 = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); if r3>NB_MAGIC_32767 { r3=r3-NB_MAGIC_65536 } ip=ip+3+r3; h=1 } } 91 if h==0 { if op==0xCD { 92 let vec: i64 = mem[ip+1] as i64 93 let ah: i64 = (ax >> 8) & 0xFF 94 if vec==0x10 { if ah==0x0E { console[clen[0]]=(ax & 0xFF) as u8; clen[0]=clen[0]+1 } } 95 if vec==0x13 { if ah==0x02 { 96 let count: i64 = ax & 0xFF 97 let sector: i64 = cx & 0xFF 98 let lba: i64 = sector - 1 99 var s: i64 = 0 100 while s < count*512 { mem[bx + s] = disk[lba*512 + s]; s=s+1 } 101 ax = ax & 0xFF 102 } } 103 ip=ip+2; h=1 104 } } 105 if h==0 { return 0 - 1 } 106 } 107 return 0 - 2 108} 109 110const NB_IMG_SZ: i64 = 1024 111func nb_movrax(img: *u8, base: i64, o: i64, b0: i64, b1: i64, b2: i64, b3: i64) -> i64 { 112 img[base+o]=0x48 as u8; img[base+o+1]=0xC7 as u8; img[base+o+2]=0xC0 as u8 113 img[base+o+3]=(b0&0xff) as u8; img[base+o+4]=(b1&0xff) as u8; img[base+o+5]=(b2&0xff) as u8; img[base+o+6]=(b3&0xff) as u8 114 return o+7 115} 116func nb_build_image(img: *u8) -> i64 { 117 var z: i64=0 118 while z<NB_IMG_SZ { img[z]=0 as u8; z=z+1 } 119 img[0]=0xB8 as u8; img[1]=0x01 as u8; img[2]=0x02 as u8 120 img[3]=0xBB as u8; img[4]=0x00 as u8; img[5]=0x80 as u8 121 img[6]=0xB9 as u8; img[7]=0x02 as u8; img[8]=0x00 as u8 122 img[9]=0xBA as u8; img[10]=0x80 as u8; img[11]=0x00 as u8 123 img[12]=0xCD as u8; img[13]=0x13 as u8 124 let rel16: i64 = 0x8000 - (0x7C00 + 14 + 3) 125 img[14]=0xE9 as u8; img[15]=(rel16 & 0xFF) as u8; img[16]=((rel16>>8) & 0xFF) as u8 126 img[510]=0x55 as u8; img[511]=0xAA as u8 127 var r: i64 = 0 128 img[512+r]=0xBE as u8; let si_r: i64 = r+1; r=r+3 129 let loop_r: i64 = r 130 img[512+r]=0xAC as u8; r=r+1 131 img[512+r]=0x08 as u8; img[512+r+1]=0xC0 as u8; r=r+2 132 img[512+r]=0x74 as u8; let jz_r: i64 = r+1; r=r+2 133 img[512+r]=0xB4 as u8; img[512+r+1]=0x0E as u8; r=r+2 134 img[512+r]=0xCD as u8; img[512+r+1]=0x10 as u8; r=r+2 135 img[512+r]=0xEB as u8; img[512+r+1]=((loop_r-(r+2)) & 0xFF) as u8; r=r+2 136 let after_r: i64 = r 137 r = nb_movrax(img, 512, r, 1, 0, 0, 0) 138 img[512+r]=0x0F as u8; img[512+r+1]=0x22 as u8; img[512+r+2]=0xC0 as u8; r=r+3 139 r = nb_movrax(img, 512, r, 0x00, 0x01, 0, 0) 140 img[512+r]=0x0F as u8; img[512+r+1]=0x30 as u8; r=r+2 141 r = nb_movrax(img, 512, r, 0x01, 0x00, 0x00, 0x80) 142 img[512+r]=0x0F as u8; img[512+r+1]=0x22 as u8; img[512+r+2]=0xC0 as u8; r=r+3 143 img[512+r]=0xF4 as u8; r=r+1 144 let msg_r: i64 = r 145 let msg: *u8 = "NishiOS\x0D\x0A\x00" 146 var mi: i64=0 147 while msg[mi]!=(0 as u8) { img[512+r]=msg[mi]; r=r+1; mi=mi+1 } 148 img[512+r]=0 as u8; r=r+1 149 img[512+jz_r] = ((after_r - (jz_r+1)) & 0xFF) as u8 150 let si_abs: i64 = 0x8000 + msg_r 151 img[512+si_r] = (si_abs & 0xFF) as u8 152 img[512+si_r+1] = ((si_abs>>8) & 0xFF) as u8 153 return 0 154} 155func nb_boot_image(img: *u8, console: *u8, clen: *i64, st: *i64, loaded: *i64) -> i64 { 156 let mem: *u8 = sys_mmap(NB_MAGIC_65536) 157 var k: i64=0 158 while k<NB_MAGIC_65536 { mem[k]=0 as u8; k=k+1 } 159 var j: i64=0 160 while j<512 { mem[0x7C00+j]=img[j]; j=j+1 } 161 loaded[0] = mem[0x8000] as i64 162 clen[0]=0 163 let rc: i64 = nb_emu_boot_disk(mem, img, 0x7C00, console, clen, st) 164 loaded[1] = mem[0x8000] as i64 165 return rc 166} 167func nb_str(fb: *u8, W: i64, H: i64, x: i64, y: i64, s: *u8, r: i64, g: i64, b: i64) -> i64 { 168 let table: *u8 = font8x8_table() 169 var i: i64=0 170 while s[i]!=(0 as u8) { 171 let cc: i64 = s[i] as i64 172 if cc>=0x20 { if cc<=0x7E { 173 let gi: i64=(cc-0x20)*8 174 var rr: i64=0 175 while rr<8 { let bits: i64=table[gi+rr] as i64; var co: i64=0; while co<8 { if ((bits>>co)&1)==1 { fb_setpx(fb,W,H, x+i*8+co, y+rr, r,g,b) } co=co+1 } rr=rr+1 } 176 } } 177 i=i+1 178 } 179 return 0 180} 181func nb_write_file(path: *u8, data: *u8, n: i64) -> i64 { 182 let fd: i64 = sys_openat_wr(path, 0x1a4) 183 if fd<=0 { return 0 - 1 } 184 sys_write(fd, data, n) 185 sys_close(fd) 186 return n 187} 188 189const NB_W: i64 = 640 190const NB_H: i64 = 480 191const NB_BW: i64 = 620 192const NB_BH: i64 = 426 193const NB_OX: i64 = 10 194const NB_OY: i64 = 38 195 196// --- the modeled NIC in the x86 RAM --- 197// register block (dwords): +0 TX_ADDR +4 TX_LEN +8 DOORBELL +12 RX_ADDR +16 RX_LEN +20 RX_STATUS +24 SCRATCH 198const NN_NICREG: i64 = 0x2000 199const NN_TXOFF: i64 = 0x3000 200const NN_RXOFF: i64 = 0x5000 201const NN_MEMSZ: i64 = 0x10000 202const NN_DOORBELL: i64 = 0x2008 // NN_NICREG + 8 203 204func nn_rd32(mem: *u8, off: i64) -> i64 { return (mem[off] as i64)|((mem[off+1] as i64)<<8)|((mem[off+2] as i64)<<16)|((mem[off+3] as i64)<<24) } 205func nn_wr32(mem: *u8, off: i64, v: i64) -> i64 { mem[off]=(v&0xFF) as u8; mem[off+1]=((v>>8)&0xFF) as u8; mem[off+2]=((v>>16)&0xFF) as u8; mem[off+3]=((v>>24)&0xFF) as u8; return 0 } 206func nn_appz(mem: *u8, p: i64, s: *u8) -> i64 { var q: i64=p; var i: i64=0; while s[i]!=(0 as u8) { mem[q]=s[i]; q=q+1; i=i+1 } return q } 207 208// the device: fires on the doorbell store. Reads the request from the TX buffer, delivers an HTTP 200 209// into the RX buffer whose body ECHOES the requested path (content-derived -- a constant cannot pass). 210func nn_device(mem: *u8) -> i64 { 211 let txaddr: i64 = nn_rd32(mem, NN_NICREG+0) 212 let txlen: i64 = nn_rd32(mem, NN_NICREG+4) 213 let rxaddr: i64 = nn_rd32(mem, NN_NICREG+12) 214 // parse the path: request begins "GET " then path up to the next space 215 var ps: i64 = txaddr + 4 216 var pe: i64 = ps 217 while pe < txaddr + txlen { if (mem[pe] as i64)==32 { pe = txaddr + txlen } else { pe = pe + 1 } } 218 // real end (loop above jumps pe to end on space; recompute cleanly) 219 pe = ps 220 var go: i64 = 1 221 while go==1 { if pe >= txaddr + txlen { go=0 } else { if (mem[pe] as i64)==32 { go=0 } else { pe=pe+1 } } } 222 // build the response 223 var p: i64 = rxaddr 224 p = nn_appz(mem, p, "HTTP/1.0 200 OK\x0D\x0AContent-Type: text/html\x0D\x0A\x0D\x0A\x00" as *u8) 225 p = nn_appz(mem, p, "<html><head><title>Fetched over the NishiOS NIC</title></head><body><h1>Fetched over NIC</h1><p>Path requested: \x00" as *u8) 226 var i: i64 = ps 227 while i < pe { mem[p]=mem[i]; p=p+1; i=i+1 } 228 p = nn_appz(mem, p, "</p><p>The kernel wrote this request into the TX buffer, programmed the NIC TX descriptor and rang the doorbell with an executed x86 store; the device delivered this HTTP 200 into the RX buffer; the browser laid out the response body.</p><p>Try the <a href='/next'>next page</a>.</p></body></html>\x00" as *u8) 229 let rxlen: i64 = p - rxaddr 230 nn_wr32(mem, NN_NICREG+16, rxlen) 231 nn_wr32(mem, NN_NICREG+20, 1) 232 return rxlen 233} 234 235// the sovereign mini-emu for the NIC driver program. Implements exactly: movabs rax,imm64 (48 B8); 236// mov rdx,imm32 (48 C7 C2); mov [rax],edx (89 10, with doorbell interception); mov edx,[rax] (8B 10); 237// hlt (F4). Anything else refuses (-1). On a store to the doorbell MMIO with a nonzero value it runs 238// the device. fired[0] counts device firings. 239func nn_run(mem: *u8, memsz: i64, entry: i64, fired: *i64) -> i64 { 240 var ip: i64 = entry 241 var rax: i64=0 242 var rdx: i64=0 243 var guard: i64=0 244 fired[0]=0 245 while guard < NB_MAGIC_100000 { 246 guard = guard + 1 247 let op: i64 = mem[ip] as i64 248 if op==0xF4 { return 0 } 249 var h: i64 = 0 250 if h==0 { if op==0x48 { 251 let b1: i64 = mem[ip+1] as i64 252 if b1==0xB8 { rax = (mem[ip+2] as i64)|((mem[ip+3] as i64)<<8)|((mem[ip+4] as i64)<<16)|((mem[ip+5] as i64)<<24)|((mem[ip+6] as i64)<<32)|((mem[ip+7] as i64)<<40)|((mem[ip+8] as i64)<<48)|((mem[ip+9] as i64)<<56); ip=ip+10; h=1 } 253 if h==0 { if b1==0xC7 { if (mem[ip+2] as i64)==0xC2 { rdx = (mem[ip+3] as i64)|((mem[ip+4] as i64)<<8)|((mem[ip+5] as i64)<<16)|((mem[ip+6] as i64)<<24); ip=ip+7; h=1 } } } 254 } } 255 if h==0 { if op==0x89 { if (mem[ip+1] as i64)==0x10 { 256 if rax<0 { return 0 - 3 } 257 if rax+4>memsz { return 0 - 3 } 258 nn_wr32(mem, rax, rdx & 0xFFFFFFFF) 259 if rax==NN_DOORBELL { if (rdx & 0xFFFFFFFF)!=0 { nn_device(mem); fired[0]=fired[0]+1 } } 260 ip=ip+2; h=1 261 } } } 262 if h==0 { if op==0x8B { if (mem[ip+1] as i64)==0x10 { 263 if rax<0 { return 0 - 3 } 264 if rax+4>memsz { return 0 - 3 } 265 rdx = nn_rd32(mem, rax) 266 ip=ip+2; h=1 267 } } } 268 if h==0 { return 0 - 1 } 269 } 270 return 0 - 2 271} 272 273func nn_movabs(code: *u8, p: i64, v: i64) -> i64 { 274 code[p]=0x48 as u8; code[p+1]=0xB8 as u8 275 code[p+2]=(v&0xFF) as u8; code[p+3]=((v>>8)&0xFF) as u8; code[p+4]=((v>>16)&0xFF) as u8; code[p+5]=((v>>24)&0xFF) as u8 276 code[p+6]=((v>>32)&0xFF) as u8; code[p+7]=((v>>40)&0xFF) as u8; code[p+8]=((v>>48)&0xFF) as u8; code[p+9]=((v>>56)&0xFF) as u8 277 return p+10 278} 279func nn_movrdx(code: *u8, p: i64, v: i64) -> i64 { 280 code[p]=0x48 as u8; code[p+1]=0xC7 as u8; code[p+2]=0xC2 as u8 281 code[p+3]=(v&0xFF) as u8; code[p+4]=((v>>8)&0xFF) as u8; code[p+5]=((v>>16)&0xFF) as u8; code[p+6]=((v>>24)&0xFF) as u8 282 return p+7 283} 284func nn_store(code: *u8, p: i64) -> i64 { code[p]=0x89 as u8; code[p+1]=0x10 as u8; return p+2 } 285func nn_load(code: *u8, p: i64) -> i64 { code[p]=0x8B as u8; code[p+1]=0x10 as u8; return p+2 } 286 287// author the NIC driver program: program TX descriptor + RX_ADDR, ring the doorbell (if ring==1), then 288// read RX_STATUS back into a scratch register. Returns program length. 289func nn_author(code: *u8, txlen: i64, ring: i64) -> i64 { 290 var p: i64 = 0 291 p = nn_movabs(code, p, NN_NICREG+0); p = nn_movrdx(code, p, NN_TXOFF); p = nn_store(code, p) // TX_ADDR = TX buffer 292 p = nn_movabs(code, p, NN_NICREG+4); p = nn_movrdx(code, p, txlen); p = nn_store(code, p) // TX_LEN 293 p = nn_movabs(code, p, NN_NICREG+12); p = nn_movrdx(code, p, NN_RXOFF); p = nn_store(code, p) // RX_ADDR = RX buffer 294 if ring==1 { p = nn_movabs(code, p, NN_DOORBELL); p = nn_movrdx(code, p, 1); p = nn_store(code, p) } // DOORBELL=1 -> device fires 295 p = nn_movabs(code, p, NN_NICREG+20); p = nn_load(code, p) // edx = RX_STATUS 296 p = nn_movabs(code, p, NN_NICREG+24); p = nn_store(code, p) // SCRATCH = status the driver saw 297 code[p]=0xF4 as u8; p=p+1 298 return p 299} 300 301func nn_draw_desktop(desk: *u8, page: *Page, url: *u8, ulen: i64) -> i64 { 302 let font: *u8 = sys_mmap(64) 303 let idx: *u8 = sys_mmap(8) 304 fb_nishi_font(font, idx) 305 var wy: i64=0 306 while wy<NB_H { let wr: i64=10-(8*wy)/NB_H; let wg: i64=30+(40*wy)/NB_H; let wb: i64=50+(30*wy)/NB_H; fb_rect(desk,NB_W,NB_H, 0,wy, NB_W,1, wr,wg,wb); wy=wy+1 } 307 fb_rect(desk,NB_W,NB_H, 0,0, NB_W,16, 28,28,110) 308 fb_text(desk,NB_W,NB_H, font, idx, 7, 6,4, 1, 255,255,255) 309 fb_window(desk,NB_W,NB_H, font,idx, 8,22, 624,444, 50,80,180, 210,210,225) 310 nb_str(desk,NB_W,NB_H, 8+3+66, 22+3, "- NISHI BROWSER (over NIC)\x00" as *u8, 240,240,250) 311 let bfb: *Framebuffer = sys_mmap(NX_FRAMEBUFFER_BYTES) as *Framebuffer 312 let bpx: *u8 = sys_mmap(NB_BW*NB_BH*4 + 64) 313 nx_framebuffer_init(bfb, bpx, NB_BW, NB_BH) 314 br_draw_fb(bfb, page, NB_BW, url, ulen, 1) 315 var by: i64 = 0 316 while by < NB_BH { 317 var bx: i64 = 0 318 while bx < NB_BW { 319 let so: i64 = (by*NB_BW + bx)*4 320 let dof: i64 = ((NB_OY+by)*NB_W + (NB_OX+bx))*3 321 desk[dof]=bpx[so]; desk[dof+1]=bpx[so+1]; desk[dof+2]=bpx[so+2] 322 bx = bx + 1 323 } 324 by = by + 1 325 } 326 fb_rect(desk,NB_W,NB_H, 0,466, NB_W,14, 20,20,40) 327 fb_rect(desk,NB_W,NB_H, 4,469, 36,8, 80,200,80) 328 nb_str(desk,NB_W,NB_H, 46,469, "browser\x00" as *u8, 200,210,230) 329 fb_cursor(desk,NB_W,NB_H, 330,240) 330 return 0 331} 332 333func main() -> i64 { 334 nb_puts("BROWSER-ON-ALL-OS N3: the Nishi browser FETCHES over a NishiOS NIC (doorbell rung by executed x86)\n" as *u8) 335 336 // ---- 1. persist + boot the NishiOS image 337 let img: *u8 = sys_mmap(NB_IMG_SZ + 16) 338 nb_build_image(img) 339 if nb_write_file("knowledge/status/nishios_browser.img\x00" as *u8, img, NB_IMG_SZ) <= 0 { nb_puts("N3 RED: cannot write image\n" as *u8); sys_exit(1); return 1 } 340 let ilp: *i64 = sys_mmap(16) as *i64 341 let rd: *u8 = sys_read_file("knowledge/status/nishios_browser.img\x00" as *u8, ilp) 342 let con: *u8 = sys_mmap(256) 343 let clen: *i64 = sys_mmap(8) as *i64 344 let st: *i64 = sys_mmap(64) as *i64 345 let ld: *i64 = sys_mmap(64) as *i64 346 nb_boot_image(rd, con, clen, st, ld) 347 nb_puts(" boot: 0x8000 " as *u8); nb_num(ld[0]); nb_puts("->" as *u8); nb_num(ld[1]); nb_puts(" mode=" as *u8); nb_num(st[1]); nb_puts("\n" as *u8) 348 349 // ---- 2. the driver builds the request into the TX buffer + programs/ring the NIC via executed x86 350 let path: *u8 = "/nishi-net-probe\x00" as *u8 351 let mem: *u8 = sys_mmap(NN_MEMSZ) 352 var mz: i64=0 353 while mz<NN_MEMSZ { mem[mz]=0 as u8; mz=mz+1 } 354 // request = "GET <path> HTTP/1.0\r\n\r\n" assembled into the TX buffer (driver packet assembly) 355 var tq: i64 = NN_TXOFF 356 tq = nn_appz(mem, tq, "GET \x00" as *u8) 357 tq = nn_appz(mem, tq, path) 358 tq = nn_appz(mem, tq, " HTTP/1.0\x0D\x0A\x0D\x0A\x00" as *u8) 359 let txlen: i64 = tq - NN_TXOFF 360 let fired: *i64 = sys_mmap(16) as *i64 361 var rc86: i64 = 0 - 9 362 if st[1]==2 { 363 let clen86: i64 = nn_author(mem, txlen, 1) 364 nb_puts(" driver program: " as *u8); nb_num(clen86); nb_puts(" bytes; request txlen=" as *u8); nb_num(txlen); nb_puts("\n" as *u8) 365 rc86 = nn_run(mem, NN_MEMSZ, 0, fired) 366 } 367 let rx_status: i64 = nn_rd32(mem, NN_NICREG+20) 368 let scratch: i64 = nn_rd32(mem, NN_NICREG+24) 369 let rxlen: i64 = nn_rd32(mem, NN_NICREG+16) 370 nb_puts(" NIC: x86 rc=" as *u8); nb_num(rc86); nb_puts(" doorbell_fired=" as *u8); nb_num(fired[0]); nb_puts(" rx_status=" as *u8); nb_num(rx_status); nb_puts(" driver_saw=" as *u8); nb_num(scratch); nb_puts(" rxlen=" as *u8); nb_num(rxlen); nb_puts("\n" as *u8) 371 372 // ---- 3. parse the HTTP response, hand the body to the browser 373 let resp: *u8 = ((mem as i64) + NN_RXOFF) as *u8 374 var http200: i64 = 0 375 if rxlen >= 12 { if nb_contains(resp, 12, "HTTP/1.0 200\x00" as *u8, 12)==1 { http200 = 1 } } 376 // find the header/body split "\r\n\r\n" 377 var bodyoff: i64 = 0 - 1 378 var bi: i64 = 0 379 while bi + 3 < rxlen { if (resp[bi] as i64)==0x0D { if (resp[bi+1] as i64)==0x0A { if (resp[bi+2] as i64)==0x0D { if (resp[bi+3] as i64)==0x0A { bodyoff = bi+4; bi = rxlen } } } } bi=bi+1 } 380 var content_ok: i64 = 0 // liar-kill: body echoes the requested path, decoy absent 381 if bodyoff >= 0 { let blen: i64 = rxlen - bodyoff 382 let bptr: *u8 = ((resp as i64) + bodyoff) as *u8 383 if nb_contains(bptr, blen, "/nishi-net-probe\x00" as *u8, 16)==1 { if nb_contains(bptr, blen, "/zzz-not-here\x00" as *u8, 13)==0 { content_ok = 1 } } 384 } 385 nb_puts(" response: http200=" as *u8); nb_num(http200); nb_puts(" bodyoff=" as *u8); nb_num(bodyoff); nb_puts(" content_derived=" as *u8); nb_num(content_ok); nb_puts("\n" as *u8) 386 387 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page 388 var a_ok: i64 = 0 389 if bodyoff >= 0 { page.raw = ((resp as i64) + bodyoff) as *u8; page.raw_len = rxlen - bodyoff; br_layout(page, NB_BW); a_ok = page.ok } 390 nb_puts(" layout: ok=" as *u8); nb_num(a_ok); nb_puts(" boxes=" as *u8); if a_ok==1 { nb_num(page.tree.count) } else { nb_num(0) } nb_puts("\n" as *u8) 391 392 // ---- 4. render the FETCHED page into the NishiOS desktop 393 let desk: *u8 = sys_mmap(NB_W*NB_H*3 + 16) 394 var bmpsz: i64 = 0 395 var cnt_h1: i64 = 0 396 if a_ok==1 { 397 nn_draw_desktop(desk, page, "nishios://nic/nishi-net-probe\x00" as *u8, 29) 398 var y: i64=0 399 while y<NB_BH { var x: i64=0; while x<NB_BW { let d: i64=((NB_OY+y)*NB_W+(NB_OX+x))*3; if (desk[d] as i64)==168 { if (desk[d+1] as i64)==200 { if (desk[d+2] as i64)==255 { cnt_h1=cnt_h1+1 } } } x=x+1 } y=y+1 } 400 bmpsz = fb_bmp_save(desk, NB_W, NB_H, "knowledge/status/nishios_net.bmp\x00" as *u8) 401 let html: *u8 = "<!doctype html><html><body style=\x27margin:0;background:#0a0a12;display:flex;align-items:center;justify-content:center;height:100vh\x27><div><img src=\x27nishios_net.bmp\x27 style=\x27image-rendering:pixelated;width:960px;border:1px solid #333\x27><div style=\x27color:#8af;font-family:monospace;text-align:center;margin-top:8px\x27>NishiOS boots to LONG mode; the NIC driver programs the TX descriptor and rings the doorbell with an executed x86 store; the device delivers an HTTP 200 (body echoes the requested path); the Nishi browser renders the fetched body into the desktop</div></div></body></html>\x00" 402 nb_write_file("knowledge/status/nishios_net.html\x00" as *u8, html, nb_slen(html)) 403 nb_puts(" fetched page rendered -> knowledge/status/nishios_net.bmp (" as *u8); nb_num(bmpsz); nb_puts(" bytes) + .html\n" as *u8) 404 } 405 406 // ---- 5. NEG 1: a driver that programs the descriptor but NEVER rings the doorbell gets no delivery 407 let mem2: *u8 = sys_mmap(NN_MEMSZ) 408 var mz2: i64=0 409 while mz2<NN_MEMSZ { mem2[mz2]=0 as u8; mz2=mz2+1 } 410 var tq2: i64 = NN_TXOFF 411 tq2 = nn_appz(mem2, tq2, "GET \x00" as *u8); tq2 = nn_appz(mem2, tq2, path); tq2 = nn_appz(mem2, tq2, " HTTP/1.0\x0D\x0A\x0D\x0A\x00" as *u8) 412 let fired2: *i64 = sys_mmap(16) as *i64 413 nn_author(mem2, tq2 - NN_TXOFF, 0) // ring=0 -> no doorbell 414 let rc2: i64 = nn_run(mem2, NN_MEMSZ, 0, fired2) 415 let neg_status: i64 = nn_rd32(mem2, NN_NICREG+20) 416 nb_puts(" NEG no-doorbell: rc=" as *u8); nb_num(rc2); nb_puts(" fired=" as *u8); nb_num(fired2[0]); nb_puts(" rx_status=" as *u8); nb_num(neg_status); nb_puts("\n" as *u8) 417 418 // ---- 6. NEG 2: 0-sector boot never reaches long mode 419 let bad: *u8 = sys_mmap(NB_IMG_SZ + 16) 420 var c: i64=0 421 while c<NB_IMG_SZ { bad[c]=rd[c]; c=c+1 } 422 bad[1]=0x00 as u8 423 let con2: *u8 = sys_mmap(256) 424 let clen2: *i64 = sys_mmap(8) as *i64 425 let st2: *i64 = sys_mmap(64) as *i64 426 let ld2: *i64 = sys_mmap(64) as *i64 427 nb_boot_image(bad, con2, clen2, st2, ld2) 428 429 // ---- KATs 430 let banner: *u8 = "NishiOS" as *u8 431 var pass: i64=0 432 var ttl: i64=0 433 ttl=ttl+1; nb_puts(" T1 booted off the persisted image (0x8000: 0->0xBE): " as *u8); if ld[0]==0 { if ld[1]==0xBE { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } } else { nb_puts("FAIL\n" as *u8) } 434 ttl=ttl+1; nb_puts(" T2 LONG mode + banner: " as *u8); if st[1]==2 { if nb_contains(con, clen[0], banner, 7)==1 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } } else { nb_puts("FAIL\n" as *u8) } 435 ttl=ttl+1; nb_puts(" T3 the executed x86 rang the doorbell exactly once: " as *u8); if fired[0]==1 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } 436 ttl=ttl+1; nb_puts(" T4 device delivered (RX_STATUS==1) AND driver read it back (scratch==1): " as *u8); if rx_status==1 { if scratch==1 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } } else { nb_puts("FAIL\n" as *u8) } 437 ttl=ttl+1; nb_puts(" T5 the response is a real HTTP 200: " as *u8); if http200==1 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } 438 ttl=ttl+1; nb_puts(" T6 body is CONTENT-DERIVED (echoes the path, decoy absent): " as *u8); if content_ok==1 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } 439 ttl=ttl+1; nb_puts(" T7 browser laid out the fetched body (ok, boxes>=8): " as *u8); if a_ok==1 { if page.tree.count>=8 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } } else { nb_puts("FAIL\n" as *u8) } 440 ttl=ttl+1; nb_puts(" T8 fetched page rendered into the desktop (h1 bar >200 px): " as *u8); if cnt_h1>200 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } 441 ttl=ttl+1; nb_puts(" T9 BMP exported at the exact expected size: " as *u8); if bmpsz==(54 + NB_W*NB_H*3) { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } 442 ttl=ttl+1; nb_puts(" T10 NEG: no doorbell -> no delivery (rx_status==0, fired==0): " as *u8); if fired2[0]==0 { if neg_status==0 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } } else { nb_puts("FAIL\n" as *u8) } 443 ttl=ttl+1; nb_puts(" T11 NEG: 0-sector load never reaches long mode: " as *u8); if st2[1]!=2 { pass=pass+1; nb_puts("PASS\n" as *u8) } else { nb_puts("FAIL\n" as *u8) } 444 445 nb_puts("NISHIOS-NET-GATE passed " as *u8); nb_num(pass); nb_puts("/" as *u8); nb_num(ttl) 446 if pass==ttl { nb_puts(" verdict=GREEN (the browser fetched + rendered over the NishiOS NIC; open knowledge/status/nishios_net.html)\n" as *u8); sys_exit(0); return 0 } 447 nb_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 448}