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}