code wiki / (root) / nx_nishios_fb_x86.nx

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}