code wiki / _hdl_build / nx_nishi_usb_kernel.nx

nx_nishi_usb_kernel.nx source

↩ module page · 318 lines · 20144 B

1// nx_nishi_usb_kernel.nx -- x86 ladder R-KERN-1: the long-mode kernel sets up real GDT + IDT and takes 2// a VECTORED interrupt through the IDT. This is the first OS-internals rung at the long-mode entry the 3// operator chose: lgdt -> a real GDT, lidt -> a real IDT, int -> the CPU vectors through the IDT gate to 4// a handler that runs ONLY because the interrupt was delivered (not a direct call). 5// 6// The kernel is LOADED OFF the persisted image (nishi_os_kernel.img) and booted to LONG mode, then: 7// * builds a spec-shaped GDT (null + 64-bit code [L-bit] + data) as static data, lgdt [pseudo] 8// * builds a spec-shaped IDT whose entry 3 is a real interrupt gate (offset split across the 9// offset_low/offset_mid/offset_high fields, selector 0x08, type 0x8E), lidt [pseudo] 10// * mov rsp + int 3 -> the emu reads IDT[3], reconstructs the handler offset, pushes the return 11// address, and vectors to the handler; the handler writes a marker and IRETs back; HLT. 12// 13// The unified emu now fuses FOUR proven mechanisms: the 16-bit + INT 13h loader, the CR0/EFER mode 14// transition, the 64-bit store/arith engine, and IDT interrupt delivery + iret (from nx_nishios_irq). 15// 16// KAT: (T1) booted off disk; (T2) LONG mode; (T3) GDTR loaded (base+limit); (T4) the GDT holds a 64-bit 17// code descriptor (L-bit set); (T5) IDTR loaded; (T6) int 3 vectored through the IDT -> the handler ran 18// (marker written). NEG/liar-kill (T7): a sibling image whose IDT[3] offset is ZEROED never vectors, so 19// the handler never runs and the marker stays unwritten -- the handler runs ONLY via a real IDT gate. 20// 21// HONEST SCOPE: long mode is flat so the emu loads/validates the GDT but does not enforce segmentation; 22// the IDT delivery (gate read -> reconstruct offset -> push -> vector -> iret) is real. Paging 23// (CR3 + PML4 walk) and PIC/IRQ0 timer preemption are the next two rungs. NEVER-BRICK (Rule 26): 24// writes a FILE; models INT 13h *reads* only; no /dev. expect_exit: 0 license_tier: ORIGINAL 25import "nx_syscalls.nx" 26import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 27const IMG_MAGIC_2000000: i64 = 2000000 28const IMG_MAGIC_32767: i64 = 32767 29const IMG_MAGIC_65536: i64 = 65536 30 31func k_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 32// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 33// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 34// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 35// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 36func k_num(v: i64) -> i64 { nxi_out(v); return 0 } 37func k_contains(hay: *u8, hn: i64, ndl: *u8, nn: i64) -> i64 { if nn==0 { return 1 } var i: i64=0; 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 } return 0 } 38func k_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 } 39func k_st64(mem: *u8, a: i64, v: i64) -> i64 { var i: i64=0; while i<8 { mem[a+i]=((v>>(i*8))&0xff) as u8; i=i+1 } return 0 } 40func k_ld64(mem: *u8, a: i64) -> i64 { var v: i64=0; var i: i64=0; while i<8 { v=v|((mem[a+i] as i64)<<(i*8)); i=i+1 } return v } 41func k_ld16(mem: *u8, a: i64) -> i64 { return (mem[a] as i64) | ((mem[a+1] as i64)<<8) } 42func k_ld32(mem: *u8, a: i64) -> i64 { return (mem[a] as i64) | ((mem[a+1] as i64)<<8) | ((mem[a+2] as i64)<<16) | ((mem[a+3] as i64)<<24) } 43 44// UNIFIED boot emu: 16-bit loader + CR0/EFER mode transition + 64-bit store/arith + GDT/IDT + int/iret. 45// st[]: 0=cr0 1=mode 2=gdtr_base 3=gdtr_limit 4=idtr_base 5=idtr_limit 6=marker(mem[0xC000]). 46func emu_x86_boot_kern(mem: *u8, disk: *u8, entry: i64, console: *u8, clen: *i64, st: *i64) -> i64 { 47 let reg: *i64 = sys_mmap(8 * 16) as *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 cr0: i64=0 56 var efer: i64=0 57 var gdtr_base: i64=0 58 var gdtr_limit: i64=0 59 var idtr_base: i64=0 60 var idtr_limit: i64=0 61 var guard: i64=0 62 st[0]=0; st[1]=0; st[2]=0; st[3]=0; st[4]=0; st[5]=0; st[6]=0 63 while guard < IMG_MAGIC_2000000 { 64 guard = guard + 1 65 let op: i64 = mem[ip] as i64 66 if op == 0xF4 { st[0]=cr0; st[1]=k_mode(cr0,efer); st[2]=gdtr_base; st[3]=gdtr_limit; st[4]=idtr_base; st[5]=idtr_limit; st[6]=k_ld64(mem,0xC000); return 0 } 67 var h: i64 = 0 68 // ---- iret ---- 69 if h==0 { if op==0xCF { ip = k_ld64(mem, reg[4]); reg[4]=reg[4]+8; h=1 } } 70 // ---- 64-bit ops ---- 71 if h==0 { if op==0x48 { 72 let o2: i64 = mem[ip+1] as i64 73 if o2==0xC7 { let m: i64=mem[ip+2] as i64; 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); reg[m & 7]=imm; ip=ip+7; h=1 } 74 if h==0 { if o2==0x89 { let m: i64=mem[ip+2] as i64; if ((m>>6)&3)==3 { reg[m & 7]=reg[(m>>3) & 7] } else { k_st64(mem, reg[m & 7], reg[(m>>3) & 7]) } ip=ip+3; h=1 } } 75 if h==0 { if o2==0x8B { let m: i64=mem[ip+2] as i64; if ((m>>6)&3)==3 { reg[(m>>3) & 7]=reg[m & 7] } else { reg[(m>>3) & 7]=k_ld64(mem, reg[m & 7]) } ip=ip+3; h=1 } } 76 if h==0 { if o2==0x01 { let m: i64=mem[ip+2] as i64; reg[m & 7]=reg[m & 7]+reg[(m>>3) & 7]; ip=ip+3; h=1 } } 77 if h==0 { if o2==0x39 { let m: i64=mem[ip+2] as i64; let t: i64=reg[m & 7]-reg[(m>>3) & 7]; if t==0 { zf=1 } else { zf=0 } ip=ip+3; h=1 } } 78 if h==0 { return 0 - 1 } 79 } } 80 // ---- two-byte 0F ops ---- 81 if h==0 { if op==0x0F { 82 let b1: i64 = mem[ip+1] as i64 83 if b1==0x01 { // lgdt/lidt [rm] 84 let m: i64=mem[ip+2] as i64; let addr: i64=reg[m & 7] 85 if ((m>>3)&7)==2 { gdtr_limit=k_ld16(mem,addr); gdtr_base=k_ld64(mem,addr+2) } // lgdt 86 if ((m>>3)&7)==3 { idtr_limit=k_ld16(mem,addr); idtr_base=k_ld64(mem,addr+2) } // lidt 87 ip=ip+3; h=1 88 } 89 if h==0 { if b1==0x22 { let m: i64=mem[ip+2] as i64; if ((m>>3)&7)==0 { cr0=reg[0] }; ip=ip+3; h=1 } } 90 if h==0 { if b1==0x30 { efer=reg[0]; ip=ip+2; h=1 } } 91 if h==0 { if b1==0x05 { st[0]=cr0; st[1]=k_mode(cr0,efer); return reg[7] & 0xff } } 92 if h==0 { return 0 - 1 } 93 } } 94 if h==0 { if op==0x75 { var r: i64=mem[ip+1] as i64; if r>127 { r=r-256 } if zf==0 { ip=ip+2+r } else { ip=ip+2 } h=1 } } 95 // ---- 16-bit real-mode + BIOS INT services (IDTR==0) / software int vectoring (IDTR!=0) ---- 96 if h==0 { if op==0xBE { si = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 97 if h==0 { if op==0xB8 { ax = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 98 if h==0 { if op==0xBB { bx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 99 if h==0 { if op==0xB9 { cx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 100 if h==0 { if op==0xBA { dx = (mem[ip+1] as i64) | ((mem[ip+2] as i64)<<8); ip=ip+3; h=1 } } 101 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 } } 102 if h==0 { if op==0x08 { let al2: i64 = ax & 0xFF; if al2==0 { zf=1 } else { zf=0 } ip=ip+2; h=1 } } 103 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 } } 104 if h==0 { if op==0xB4 { ax = (ax & 0xFF) | ((mem[ip+1] as i64)<<8); ip=ip+2; h=1 } } 105 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 } } 106 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 } } 107 if h==0 { if op==0xCD { 108 let vec: i64 = mem[ip+1] as i64 109 if idtr_base != 0 { 110 // software interrupt: vector through the real IDT gate (offset split across fields) 111 let e: i64 = idtr_base + vec*16 112 let off: i64 = k_ld16(mem, e) | (k_ld16(mem, e+6)<<16) | (k_ld32(mem, e+8)<<32) 113 if off != 0 { reg[4]=reg[4]-8; k_st64(mem, reg[4], ip+2); ip=off } else { ip=ip+2 } 114 } else { 115 let ah: i64 = (ax >> 8) & 0xFF 116 if vec==0x10 { if ah==0x0E { console[clen[0]]=(ax & 0xFF) as u8; clen[0]=clen[0]+1 } } 117 if vec==0x13 { if ah==0x02 { 118 let count: i64 = ax & 0xFF 119 let sector: i64 = cx & 0xFF 120 let lba: i64 = sector - 1 121 var s: i64 = 0 122 while s < count*512 { mem[bx + s] = disk[lba*512 + s]; s=s+1 } 123 ax = ax & 0xFF 124 } } 125 ip=ip+2 126 } 127 h=1 128 } } 129 if h==0 { return 0 - 1 } 130 } 131 return 0 - 2 132} 133 134const IMG_SZ: i64 = 1024 135 136func uf_movr(img: *u8, base: i64, o: i64, modrm: i64, imm: i64) -> i64 { 137 img[base+o]=0x48 as u8; img[base+o+1]=0xC7 as u8; img[base+o+2]=(modrm&0xff) as u8 138 img[base+o+3]=(imm&0xff) as u8; img[base+o+4]=((imm>>8)&0xff) as u8; img[base+o+5]=((imm>>16)&0xff) as u8; img[base+o+6]=((imm>>24)&0xff) as u8 139 return o+7 140} 141func wr16(img: *u8, a: i64, v: i64) -> i64 { img[a]=(v&0xff) as u8; img[a+1]=((v>>8)&0xff) as u8; return 0 } 142func wr64(img: *u8, a: i64, v: i64) -> i64 { var i: i64=0; while i<8 { img[a+i]=((v>>(i*8))&0xff) as u8; i=i+1 } return 0 } 143 144// info[]: 0=gdt_off(in-sector) 1=idt_off 2=handler_off 3=GDT_ABS 4=IDT_ABS 5=handler_ABS 145func build_image(img: *u8, info: *i64) -> i64 { 146 var z: i64=0 147 while z<IMG_SZ { img[z]=0 as u8; z=z+1 } 148 // ---- MBR: load kernel (sector 1) to 0x8000, jmp to it ---- 149 img[0]=0xB8 as u8; img[1]=0x01 as u8; img[2]=0x02 as u8 150 img[3]=0xBB as u8; img[4]=0x00 as u8; img[5]=0x80 as u8 151 img[6]=0xB9 as u8; img[7]=0x02 as u8; img[8]=0x00 as u8 152 img[9]=0xBA as u8; img[10]=0x80 as u8; img[11]=0x00 as u8 153 img[12]=0xCD as u8; img[13]=0x13 as u8 154 let rel16: i64 = 0x8000 - (0x7C00 + 14 + 3) 155 img[14]=0xE9 as u8; img[15]=(rel16 & 0xFF) as u8; img[16]=((rel16>>8) & 0xFF) as u8 156 img[510]=0x55 as u8; img[511]=0xAA as u8 157 158 // ---- kernel (loads at 0x8000) ---- 159 var r: i64 = 0 160 // banner 161 img[512+r]=0xBE as u8; let si_r: i64 = r+1; r=r+3 162 let loop_r: i64 = r 163 img[512+r]=0xAC as u8; r=r+1 164 img[512+r]=0x08 as u8; img[512+r+1]=0xC0 as u8; r=r+2 165 img[512+r]=0x74 as u8; let jz_r: i64 = r+1; r=r+2 166 img[512+r]=0xB4 as u8; img[512+r+1]=0x0E as u8; r=r+2 167 img[512+r]=0xCD as u8; img[512+r+1]=0x10 as u8; r=r+2 168 img[512+r]=0xEB as u8; img[512+r+1]=((loop_r-(r+2)) & 0xFF) as u8; r=r+2 169 let after_r: i64 = r 170 // mode transition -> long 171 r = uf_movr(img, 512, r, 0xC0, 1) 172 img[512+r]=0x0F as u8; img[512+r+1]=0x22 as u8; img[512+r+2]=0xC0 as u8; r=r+3 173 r = uf_movr(img, 512, r, 0xC0, 0x100) 174 img[512+r]=0x0F as u8; img[512+r+1]=0x30 as u8; r=r+2 175 r = uf_movr(img, 512, r, 0xC0, 0x80000001) 176 img[512+r]=0x0F as u8; img[512+r+1]=0x22 as u8; img[512+r+2]=0xC0 as u8; r=r+3 177 // set up a stack for the interrupt push 178 r = uf_movr(img, 512, r, 0xC4, 0x7000) // mov rsp, 0x7000 179 // lgdt [rax] : rax = gdt_pseudo_abs (patched) 180 r = uf_movr(img, 512, r, 0xC0, 0); let gp_imm: i64 = r-4 // mov rax, GDTPSEUDO (patch imm bytes at r-4..r-1) 181 img[512+r]=0x0F as u8; img[512+r+1]=0x01 as u8; img[512+r+2]=0x10 as u8; r=r+3 // lgdt [rax] 182 // lidt [rax] : rax = idt_pseudo_abs (patched) 183 r = uf_movr(img, 512, r, 0xC0, 0); let ip_imm: i64 = r-4 // mov rax, IDTPSEUDO 184 img[512+r]=0x0F as u8; img[512+r+1]=0x01 as u8; img[512+r+2]=0x18 as u8; r=r+3 // lidt [rax] 185 // int 3 186 img[512+r]=0xCD as u8; img[512+r+1]=0x03 as u8; r=r+2 187 // hlt 188 img[512+r]=0xF4 as u8; r=r+1 189 // ---- handler ---- 190 let handler_r: i64 = r 191 r = uf_movr(img, 512, r, 0xC3, 0xC000) // mov rbx, 0xC000 (marker addr) 192 r = uf_movr(img, 512, r, 0xC0, 0xABCD) // mov rax, 0xABCD 193 img[512+r]=0x48 as u8; img[512+r+1]=0x89 as u8; img[512+r+2]=0x03 as u8; r=r+3 // mov [rbx], rax 194 img[512+r]=0xCF as u8; r=r+1 // iret 195 // ---- data: GDT (24B) ---- 196 let gdt_r: i64 = r 197 // null (8 zero already), code (8), data (8) 198 img[512+gdt_r+8]=0xFF as u8; img[512+gdt_r+9]=0xFF as u8; img[512+gdt_r+13]=0x9A as u8; img[512+gdt_r+14]=0xAF as u8 // code: L-bit (0xAF) + access 0x9A 199 img[512+gdt_r+16]=0xFF as u8; img[512+gdt_r+17]=0xFF as u8; img[512+gdt_r+21]=0x92 as u8; img[512+gdt_r+22]=0xCF as u8 // data 200 r = gdt_r + 24 201 // ---- data: IDT (4 entries * 16 = 64B); entry 3 = interrupt gate to handler ---- 202 let idt_r: i64 = r 203 let e3: i64 = idt_r + 48 204 img[512+e3+2]=0x08 as u8; img[512+e3+3]=0x00 as u8 // selector 0x0008 205 img[512+e3+5]=0x8E as u8 // type_attr: present, interrupt gate 206 // offset_low(+0), offset_mid(+6), offset_high(+8) patched below 207 r = idt_r + 64 208 // ---- data: pseudo-descriptors ---- 209 let gdt_ps_r: i64 = r; wr16(img, 512+gdt_ps_r, 23); r=r+10 // limit=23, base patched 210 let idt_ps_r: i64 = r; wr16(img, 512+idt_ps_r, 63); r=r+10 // limit=63, base patched 211 // ---- banner message ---- 212 let msg_r: i64 = r 213 let msg: *u8 = "NishiOS\x0D\x0A\x00" 214 var mi: i64=0 215 while msg[mi]!=(0 as u8) { img[512+r]=msg[mi]; r=r+1; mi=mi+1 } 216 img[512+r]=0 as u8; r=r+1 217 218 // ---- absolute addresses (loaded at 0x8000) ---- 219 let GDT_ABS: i64 = 0x8000 + gdt_r 220 let IDT_ABS: i64 = 0x8000 + idt_r 221 let H_ABS: i64 = 0x8000 + handler_r 222 let GDTPS_ABS: i64 = 0x8000 + gdt_ps_r 223 let IDTPS_ABS: i64 = 0x8000 + idt_ps_r 224 // patch mov-rax immediates for lgdt/lidt pseudo-descriptor pointers 225 img[512+gp_imm]=(GDTPS_ABS&0xff) as u8; img[512+gp_imm+1]=((GDTPS_ABS>>8)&0xff) as u8; img[512+gp_imm+2]=((GDTPS_ABS>>16)&0xff) as u8; img[512+gp_imm+3]=((GDTPS_ABS>>24)&0xff) as u8 226 img[512+ip_imm]=(IDTPS_ABS&0xff) as u8; img[512+ip_imm+1]=((IDTPS_ABS>>8)&0xff) as u8; img[512+ip_imm+2]=((IDTPS_ABS>>16)&0xff) as u8; img[512+ip_imm+3]=((IDTPS_ABS>>24)&0xff) as u8 227 // patch pseudo-descriptor bases 228 wr64(img, 512+gdt_ps_r+2, GDT_ABS) 229 wr64(img, 512+idt_ps_r+2, IDT_ABS) 230 // patch IDT[3] gate offset fields with the handler absolute address 231 wr16(img, 512+e3+0, H_ABS & 0xFFFF) 232 wr16(img, 512+e3+6, (H_ABS>>16) & 0xFFFF) 233 img[512+e3+8]=((H_ABS>>32)&0xff) as u8; img[512+e3+9]=((H_ABS>>40)&0xff) as u8; img[512+e3+10]=((H_ABS>>48)&0xff) as u8; img[512+e3+11]=((H_ABS>>56)&0xff) as u8 234 // patch banner si + jz 235 img[512+jz_r] = ((after_r - (jz_r+1)) & 0xFF) as u8 236 let si_abs: i64 = 0x8000 + msg_r 237 img[512+si_r] = (si_abs & 0xFF) as u8 238 img[512+si_r+1] = ((si_abs>>8) & 0xFF) as u8 239 240 info[0]=gdt_r; info[1]=idt_r; info[2]=handler_r; info[3]=GDT_ABS; info[4]=IDT_ABS; info[5]=H_ABS 241 return 0 242} 243 244func boot_image(img: *u8, console: *u8, clen: *i64, st: *i64, loaded: *i64) -> i64 { 245 let mem: *u8 = sys_mmap(IMG_MAGIC_65536) 246 var k: i64=0 247 while k<IMG_MAGIC_65536 { mem[k]=0 as u8; k=k+1 } 248 var j: i64=0 249 while j<512 { mem[0x7C00+j]=img[j]; j=j+1 } 250 loaded[0] = mem[0x8000] as i64 251 clen[0]=0 252 let rc: i64 = emu_x86_boot_kern(mem, img, 0x7C00, console, clen, st) 253 loaded[1] = mem[0x8000] as i64 254 return rc 255} 256 257func k_read(path: *u8, out: *u8, cap: i64) -> i64 { 258 let fd: i64 = sys_openat_rd(path) 259 if fd < 0 { return 0 - 1 } 260 var n: i64 = 0; var go: i64 = 1 261 while go==1 { let rr: i64 = sys_read(fd, ((out as i64)+n) as *u8, cap-n); if rr<=0 { go=0 } else { n=n+rr } if n>=cap { go=0 } } 262 sys_close(fd) 263 return n 264} 265 266func main() -> i64 { 267 k_puts("x86 ladder R-KERN-1: the long-mode kernel sets up a real GDT + IDT and takes a vectored interrupt\n" as *u8) 268 269 let img: *u8 = sys_mmap(IMG_SZ + 16) 270 let info: *i64 = sys_mmap(64) as *i64 271 build_image(img, info) 272 let fd: i64 = sys_openat_wr("knowledge/status/nishi_os_kernel.img\x00" as *u8, 0x1a4) 273 if fd<=0 { k_puts("R-KERN-1 RED: cannot write image\n" as *u8); sys_exit(1); return 1 } 274 sys_write(fd, img, IMG_SZ) 275 sys_close(fd) 276 let rd: *u8 = sys_mmap(IMG_SZ + 16) 277 k_read("knowledge/status/nishi_os_kernel.img\x00" as *u8, rd, IMG_SZ) 278 279 // GOOD boot. 280 let con: *u8 = sys_mmap(256) 281 let clen: *i64 = sys_mmap(8) as *i64 282 let st: *i64 = sys_mmap(64) as *i64 283 let ld: *i64 = sys_mmap(64) as *i64 284 let rc: i64 = boot_image(rd, con, clen, st, ld) 285 k_puts(" boot: 0x8000 " as *u8); k_num(ld[0]); k_puts("->" as *u8); k_num(ld[1]); k_puts(" mode=" as *u8); k_num(st[1]); k_puts(" rc=" as *u8); k_num(rc); k_puts("\n" as *u8) 286 k_puts(" GDTR base=" as *u8); k_num(st[2]); k_puts(" limit=" as *u8); k_num(st[3]); k_puts(" IDTR base=" as *u8); k_num(st[4]); k_puts(" limit=" as *u8); k_num(st[5]); k_puts("\n" as *u8) 287 k_puts(" int 3 -> handler marker (expect 43981=0xABCD): " as *u8); k_num(st[6]); k_puts("\n" as *u8) 288 289 // NEG CONTROL: zero the IDT[3] gate offset -> int 3 finds no handler -> marker never written. 290 let bad: *u8 = sys_mmap(IMG_SZ + 16) 291 var c: i64=0 292 while c<IMG_SZ { bad[c]=rd[c]; c=c+1 } 293 let e3: i64 = 512 + info[1] + 48 294 bad[e3+0]=0 as u8; bad[e3+1]=0 as u8; bad[e3+6]=0 as u8; bad[e3+7]=0 as u8; bad[e3+8]=0 as u8; bad[e3+9]=0 as u8; bad[e3+10]=0 as u8; bad[e3+11]=0 as u8 295 let con2: *u8 = sys_mmap(256) 296 let clen2: *i64 = sys_mmap(8) as *i64 297 let st2: *i64 = sys_mmap(64) as *i64 298 let ld2: *i64 = sys_mmap(64) as *i64 299 boot_image(bad, con2, clen2, st2, ld2) 300 k_puts(" NEG (IDT[3] offset zeroed): marker=" as *u8); k_num(st2[6]); k_puts(" (stays 0)\n" as *u8) 301 302 let GDT_ABS: i64 = info[3] 303 let IDT_ABS: i64 = info[4] 304 let lbyte: i64 = rd[512 + info[0] + 8 + 6] as i64 // GDT code descriptor flags byte (static image data) 305 var pass: i64=0 306 var ttl: i64=0 307 ttl=ttl+1; k_puts(" T1 booted off the persisted image (0x8000: 0->0xBE): " as *u8); if ld[0]==0 { if ld[1]==0xBE { pass=pass+1; k_puts("PASS\n" as *u8) } else { k_puts("FAIL\n" as *u8) } } else { k_puts("FAIL\n" as *u8) } 308 ttl=ttl+1; k_puts(" T2 disk-loaded kernel reached LONG mode (mode==2): " as *u8); if st[1]==2 { pass=pass+1; k_puts("PASS\n" as *u8) } else { k_puts("FAIL\n" as *u8) } 309 ttl=ttl+1; k_puts(" T3 lgdt loaded GDTR (base==" as *u8); k_num(GDT_ABS); k_puts(", limit==23): " as *u8); if st[2]==GDT_ABS { if st[3]==23 { pass=pass+1; k_puts("PASS\n" as *u8) } else { k_puts("FAIL\n" as *u8) } } else { k_puts("FAIL\n" as *u8) } 310 ttl=ttl+1; k_puts(" T4 GDT holds a 64-bit code descriptor (L-bit 0x20 set in flags=" as *u8); k_num(lbyte); k_puts("): " as *u8); if (lbyte & 0x20)==0x20 { pass=pass+1; k_puts("PASS\n" as *u8) } else { k_puts("FAIL\n" as *u8) } 311 ttl=ttl+1; k_puts(" T5 lidt loaded IDTR (base==" as *u8); k_num(IDT_ABS); k_puts(", limit==63): " as *u8); if st[4]==IDT_ABS { if st[5]==63 { pass=pass+1; k_puts("PASS\n" as *u8) } else { k_puts("FAIL\n" as *u8) } } else { k_puts("FAIL\n" as *u8) } 312 ttl=ttl+1; k_puts(" T6 int 3 vectored through the IDT -> handler ran (marker==0xABCD): " as *u8); if st[6]==0xABCD { pass=pass+1; k_puts("PASS\n" as *u8) } else { k_puts("FAIL\n" as *u8) } 313 ttl=ttl+1; k_puts(" T7 NEG: zeroed IDT[3] offset -> no vector -> marker stays 0 (liar-kill): " as *u8); if st2[6]==0 { pass=pass+1; k_puts("PASS\n" as *u8) } else { k_puts("FAIL\n" as *u8) } 314 315 k_puts("X86-USB-KERNEL-GATE passed " as *u8); k_num(pass); k_puts("/" as *u8); k_num(ttl) 316 if pass==ttl { k_puts(" verdict=GREEN (the disk-loaded long-mode kernel installs a real GDT+IDT and takes a vectored interrupt; paging + IRQ0 preemption = next rungs)\n" as *u8); sys_exit(0); return 0 } 317 k_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 318}