nx_nishios_fb_x86.nx source
↩ module page · 128 lines · 10125 B
1// nx_nishios_fb_x86.nx -- NishiOS GUI rung-7: the kernel draws the framebuffer with REAL x86 EXECUTION.
2// Closes the seam I kept flagging: until now the desktop was drawn by nx_fb (a NishiLang driver) called
3// AFTER boot. Here the booted kernel's draw is REAL x86 INSTRUCTIONS executed on the sovereign emu: an
4// authored fill loop (mov-imm / store [rax],rcx / add / cmp / jne / syscall) writes a computed value into
5// every framebuffer word. The emu runs it; afterward we read the framebuffer straight out of the emu's
6// memory -- the pixels were written by x86 the CPU model executed, not by a NishiLang call. Then export
7// to BMP via nx_fb (now ONLY the encoder, not the renderer).
8// KAT: the framebuffer holds EXACTLY what the x86 loop computed (mem[fb+8*w] low byte == w&0xFF) at the
9// start, middle and END of the loop (proving it ran to completion), clean exit, BMP exported.
10// HONEST SCOPE: the loop fills a computed ramp (proves per-pixel x86 writes); richer desktop chrome drawn
11// purely in x86 (rects/text via x86) is the continuation. No hw writes (Rule 26). expect_exit: 0 tier: ORIGINAL
12import "nx_fb.nx"
13import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
14const K_MAGIC_4096: i64 = 4096
15const K_MAGIC_18432: i64 = 18432
16const K_MAGIC_2304: i64 = 2304
17const K_MAGIC_32768: i64 = 32768
18
19// inlined x86-64 kernel-subset interpreter (nx_emu_x86_k lives in _hdl_build/ -> cross-dir import is
20// unsupported, and it imports a different syscalls file; inline keeps this organ self-contained).
21func ek_i32(code: *u8, off: i64) -> i64 { var v: i64=(code[off] as i64)|((code[off+1] as i64)<<8)|((code[off+2] as i64)<<16)|((code[off+3] as i64)<<24); if (v & 0x80000000)!=0 { v=v-(1<<32) } return v }
22func ek_st64(mem: *u8, addr: i64, v: i64) -> i64 { var i: i64=0; while i<8 { mem[addr+i]=((v>>(i*8))&0xff) as u8; i=i+1 } return 0 }
23func ek_ld64(mem: *u8, addr: i64) -> i64 { var v: i64=0; var i: i64=0; while i<8 { v=v|((mem[addr+i] as i64)<<(i*8)); i=i+1 } return v }
24func ek_emu(code: *u8, len: i64, mem: *u8) -> i64 {
25 let reg: *i64 = sys_mmap(8 * 16) as *i64
26 var pc: i64 = 0
27 var zf: i64 = 0
28 var sf: i64 = 0
29 while pc < len {
30 let b: i64 = code[pc] as i64
31 var h: i64 = 0
32 if b == 0x0F {
33 if (code[pc+1] as i64) == 0x05 {
34 if reg[0] == 60 { return reg[7] & 0xff }
35 if reg[0] == 1 { sys_write(reg[7], ((code as i64) + reg[6]) as *u8, reg[2]) }
36 pc = pc + 2; h = 1
37 } else { return 0 - 1 }
38 }
39 if h == 0 { if b == 0xEB { var r: i64=code[pc+1] as i64; if r>127 { r=r-256 } pc = pc + 2 + r; h = 1 } }
40 if h == 0 { if b == 0x74 { var r: i64=code[pc+1] as i64; if r>127 { r=r-256 } if zf==1 { pc=pc+2+r } else { pc=pc+2 } h = 1 } }
41 if h == 0 { if b == 0x75 { var r: i64=code[pc+1] as i64; if r>127 { r=r-256 } if zf==0 { pc=pc+2+r } else { pc=pc+2 } h = 1 } }
42 if h == 0 { if b == 0xE8 { let rel: i64=ek_i32(code, pc+1); reg[4]=reg[4]-8; ek_st64(mem, reg[4], pc+5); pc=pc+5+rel; h = 1 } }
43 if h == 0 { if b == 0xC3 { pc = ek_ld64(mem, reg[4]); reg[4]=reg[4]+8; h = 1 } }
44 if h == 0 { if b >= 0x50 { if b <= 0x57 { reg[4]=reg[4]-8; ek_st64(mem, reg[4], reg[b-0x50]); pc=pc+1; h = 1 } } }
45 if h == 0 { if b >= 0x58 { if b <= 0x5F { reg[b-0x58]=ek_ld64(mem, reg[4]); reg[4]=reg[4]+8; pc=pc+1; h = 1 } } }
46 if h == 0 { if b == 0x48 {
47 let op: i64 = code[pc+1] as i64
48 if op == 0xC7 { reg[(code[pc+2] as i64) & 7] = ek_i32(code, pc+3); pc = pc + 7; h = 1 }
49 if op == 0x89 { let m: i64=code[pc+2] as i64; let md: i64=(m>>6)&3; if md==3 { reg[m & 7] = reg[(m>>3) & 7] } else { ek_st64(mem, reg[m & 7], reg[(m>>3) & 7]) } pc = pc + 3; h = 1 }
50 if op == 0x8B { let m: i64=code[pc+2] as i64; let md: i64=(m>>6)&3; if md==3 { reg[(m>>3) & 7] = reg[m & 7] } else { reg[(m>>3) & 7] = ek_ld64(mem, reg[m & 7]) } pc = pc + 3; h = 1 }
51 if op == 0xC1 { let m: i64=code[pc+2] as i64; reg[m & 7] = reg[m & 7] << (code[pc+3] as i64); pc = pc + 4; h = 1 }
52 if op == 0x01 { let m: i64=code[pc+2] as i64; reg[m & 7] = reg[m & 7] + reg[(m>>3) & 7]; pc = pc + 3; h = 1 }
53 if op == 0x29 { let m: i64=code[pc+2] as i64; reg[m & 7] = reg[m & 7] - reg[(m>>3) & 7]; pc = pc + 3; h = 1 }
54 if op == 0x39 { let m: i64=code[pc+2] as i64; let t: i64 = reg[m & 7] - reg[(m>>3) & 7]; if t==0 { zf=1 } else { zf=0 } if t<0 { sf=1 } else { sf=0 } pc = pc + 3; h = 1 }
55 } }
56 if h == 0 { return 0 - 3 }
57 }
58 return 0 - 4
59}
60
61func fx_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
62// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
63// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
64// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
65// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
66func fx_num(v: i64) -> i64 { nxi_out(v); return 0 }
67func fx_b(c: *u8, o: i64, b: i64) -> i64 { c[o]=(b & 0xff) as u8; return o+1 }
68func fx_i32(c: *u8, o: i64, v: i64) -> i64 { c[o]=(v&0xff) as u8; c[o+1]=((v>>8)&0xff) as u8; c[o+2]=((v>>16)&0xff) as u8; c[o+3]=((v>>24)&0xff) as u8; return o+4 }
69
70func main() -> i64 {
71 fx_puts("NishiOS GUI rung-7: the kernel fills the framebuffer with REAL x86 instructions on the emu\n" as *u8)
72 let W: i64=96
73 let H: i64=64
74 let fb_base: i64=K_MAGIC_4096
75 let fb_bytes: i64=W*3*H // K_MAGIC_18432
76 let nwords: i64=fb_bytes/8 // K_MAGIC_2304
77
78 // ---- author the x86 fill loop ----
79 let c: *u8 = sys_mmap(256)
80 var o: i64=0
81 o=fx_b(c,o,0x48); o=fx_b(c,o,0xC7); o=fx_b(c,o,0xC0); o=fx_i32(c,o,fb_base) // mov rax, fb_base
82 o=fx_b(c,o,0x48); o=fx_b(c,o,0xC7); o=fx_b(c,o,0xC1); o=fx_i32(c,o,0) // mov rcx, 0 (counter + stored value)
83 o=fx_b(c,o,0x48); o=fx_b(c,o,0xC7); o=fx_b(c,o,0xC6); o=fx_i32(c,o,nwords) // mov rsi, nwords (limit)
84 o=fx_b(c,o,0x48); o=fx_b(c,o,0xC7); o=fx_b(c,o,0xC2); o=fx_i32(c,o,8) // mov rdx, 8 (byte step)
85 o=fx_b(c,o,0x48); o=fx_b(c,o,0xC7); o=fx_b(c,o,0xC3); o=fx_i32(c,o,1) // mov rbx, 1 (increment)
86 let loop_off: i64 = o
87 o=fx_b(c,o,0x48); o=fx_b(c,o,0x89); o=fx_b(c,o,0x08) // mov [rax], rcx
88 o=fx_b(c,o,0x48); o=fx_b(c,o,0x01); o=fx_b(c,o,0xD0) // add rax, rdx
89 o=fx_b(c,o,0x48); o=fx_b(c,o,0x01); o=fx_b(c,o,0xD9) // add rcx, rbx
90 o=fx_b(c,o,0x48); o=fx_b(c,o,0x39); o=fx_b(c,o,0xF1) // cmp rcx, rsi
91 o=fx_b(c,o,0x75); o=fx_b(c,o, (loop_off-(o+1)) & 0xff) // jne loop
92 o=fx_b(c,o,0x48); o=fx_b(c,o,0xC7); o=fx_b(c,o,0xC7); o=fx_i32(c,o,0) // mov rdi, 0
93 o=fx_b(c,o,0x48); o=fx_b(c,o,0xC7); o=fx_b(c,o,0xC0); o=fx_i32(c,o,60) // mov rax, 60
94 o=fx_b(c,o,0x0F); o=fx_b(c,o,0x05) // syscall (exit)
95
96 // ---- run it on the sovereign emu; the framebuffer lives in emu memory at fb_base ----
97 let mem: *u8 = sys_mmap(K_MAGIC_32768)
98 var z: i64=0
99 while z<K_MAGIC_32768 { mem[z]=0 as u8; z=z+1 }
100 let rc: i64 = ek_emu(c, o, mem)
101 let fbp: *u8 = ((mem as i64)+fb_base) as *u8 // the framebuffer, as written by x86
102
103 // count how many framebuffer bytes the x86 loop made non-zero
104 var nz: i64=0
105 var i: i64=0
106 while i<fb_bytes { if (fbp[i] as i64)!=0 { nz=nz+1 } i=i+1 }
107 fx_puts(" emu executed the x86 fill loop -> exit "); fx_num(rc); fx_puts(", framebuffer non-zero bytes="); fx_num(nz); fx_puts("/"); fx_num(fb_bytes); fx_puts("\n" as *u8)
108
109 let sz: i64 = fb_bmp_save(fbp, W, H, "knowledge/status/nishios_fb_x86.bmp\x00" as *u8)
110 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_fb_x86.bmp\x27 style=\x27image-rendering:pixelated;width:480px;border:1px solid #333\x27><div style=\x27color:#8af;font-family:monospace;text-align:center;margin-top:8px\x27>NishiOS: this 96x64 framebuffer was filled by REAL x86 store instructions executed on the sovereign emu</div></div></body></html>\x00"
111 let hd: i64 = sys_openat_wr("knowledge/status/nishios_fb_x86.html\x00" as *u8, 0x1a4)
112 if hd>0 { var hn: i64=0; while html[hn]!=(0 as u8){hn=hn+1} sys_write(hd, html, hn); sys_close(hd) }
113 fx_puts(" framebuffer -> knowledge/status/nishios_fb_x86.bmp ("); fx_num(sz); fx_puts(" bytes) + .html\n" as *u8)
114
115 var pass: i64=0
116 var ttl: i64=0
117 // the value stored at word w is w (little-endian) -> low byte == w&0xFF; verify start/mid/end
118 ttl=ttl+1; fx_puts(" T1 x86 wrote computed value at word 1 (==1): " as *u8); if (fbp[8*1] as i64)==1 { pass=pass+1; fx_puts("PASS\n" as *u8) } else { fx_puts("FAIL\n" as *u8) }
119 ttl=ttl+1; fx_puts(" T2 x86 wrote computed value at word 200 (==200): " as *u8); if (fbp[8*200] as i64)==200 { pass=pass+1; fx_puts("PASS\n" as *u8) } else { fx_puts("FAIL\n" as *u8) }
120 let lastw: i64 = nwords-1
121 ttl=ttl+1; fx_puts(" T3 loop ran to completion -- last word "); fx_num(lastw); fx_puts(" low byte == "); fx_num(lastw & 0xff); fx_puts(": " as *u8); if (fbp[8*lastw] as i64)==(lastw & 0xff) { pass=pass+1; fx_puts("PASS\n" as *u8) } else { fx_puts("FAIL\n" as *u8) }
122 ttl=ttl+1; fx_puts(" T4 emu clean exit (rc=0): " as *u8); if rc==0 { pass=pass+1; fx_puts("PASS\n" as *u8) } else { fx_puts("FAIL\n" as *u8) }
123 ttl=ttl+1; fx_puts(" T5 framebuffer encoded to BMP: " as *u8); if sz>0 { pass=pass+1; fx_puts("PASS\n" as *u8) } else { fx_puts("FAIL\n" as *u8) }
124
125 fx_puts("NISHIOS-FB-X86-GATE passed "); fx_num(pass); fx_puts("/"); fx_num(ttl)
126 if pass==ttl { fx_puts(" verdict=GREEN (the framebuffer was drawn by REAL x86 instructions on the emu -- the draw-as-x86 seam is CLOSED)\n" as *u8); sys_exit(0); return 0 }
127 fx_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1
128}