code wiki / _hdl_build / nx_mmu_hw.nx

nx_mmu_hw.nx source

↩ module page · 189 lines · 12758 B

1// nx_mmu_hw.nx -- GATE: a FAITHFUL x86-64 4-LEVEL PAGE-TABLE WALK MODEL (deepens MEMORY-MGMT toward the real-hw-MMU 2// gap). Where nx_paging is a flat vpn->pfn model, THIS models the ACTUAL x86-64 hardware structures the CPU's MMU 3// walks: a 48-bit VA split 9/9/9/9/12 -> PML4 -> PDPT -> PD -> PT -> frame, CR3-rooted, with present/writable/user/ 4// NX protection bits accumulated down the levels, page faults, and a TLB with invalidation + CR3-flush. This is the 5// rung BEFORE loading a real CR3 -- the exact table layout the hardware expects. 6// ★ NEVER-BRICK (cardinal 26) BY CONSTRUCTION: 100% in-memory integer model over an mmap'd 'simulated physical RAM'. 7// It issues NO real CR3 write, NO privileged instruction, NO MMU/firmware write. The real-hardware activation path 8// (mmu_activate_real) is a STUB that REFUSES by construction -- a real CR3 load requires a SEPARATELY-proven 9// never-brick hardware capability that does not exist here. Proven mechanically in T5, not asserted. 10// T1 4-level walk: map + translate a VA -> exact PA (frame<<12 | offset). T2 unmapped VA -> page fault. 11// T3 protection: a read-only page faults on WRITE (ok on READ); an NX page faults on EXECUTE. 12// T4 TLB: miss->fill->hit; invlpg evicts (miss again); CR3 reload flushes all. 13// T5 NEVER-BRICK teeth: mmu_activate_real is REFUSED by construction (no real CR3 write path exists) + determinism. 14// expect_exit: 0 Sovereign: nx_syscalls. 15import "nx_syscalls.nx" 16import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 17const F_MAGIC_4095: i64 = 4095 18 19func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 20// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 21// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 22// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 23// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 24func g_pn(v: i64) -> i64 { nxi_out(v); return 0 } 25func ck(name: *u8, c: i64) -> i64 { if c==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } g_puts(name); g_puts("\n" as *u8); return c } 26 27const ENTRIES: i64 = 512 // 512 8-byte entries per 4KB table (2^9) 28const OFFB: i64 = 12 // page offset bits (4KB pages) 29const NFRAMES: i64 = 64 30// PTE flags (same SEMANTICS as x86-64 P/RW/US/XD; the model keeps them in low bits for clean integer range). 31const F_P: i64 = 1 // present 32const F_RW: i64 = 2 // writable 33const F_US: i64 = 4 // user-accessible 34const F_NX: i64 = 8 // no-execute (x86-64 XD) 35// fault codes 36const FLT_NP: i64 = 0-1 // not present 37const FLT_W: i64 = 0-2 // write-protection 38const FLT_X: i64 = 0-3 // NX / execute violation 39 40// simulated physical RAM: NFRAMES frames x ENTRIES words. A table entry OR a data word lives at pmem[frame*512+i]. 41struct Mmu { pmem: *i64, next: i64, cr3: i64, tvpn: *i64, tpa: *i64, tfl: *i64, tvalid: *i64, tn: i64, tclk: i64 } 42 43func mmu_new() -> *Mmu { 44 let m: *Mmu = sys_mmap(128) as *Mmu 45 m.pmem = sys_mmap(NFRAMES*ENTRIES*8) as *i64 46 var i: i64=0; while i<NFRAMES*ENTRIES { m.pmem[i]=0; i=i+1 } 47 m.next = 2 // frame 0 reserved (null), frame 1 = PML4 (cr3) 48 m.cr3 = 1 49 let T: i64 = 8 50 m.tvpn = sys_mmap(T*8) as *i64; m.tpa = sys_mmap(T*8) as *i64; m.tfl = sys_mmap(T*8) as *i64; m.tvalid = sys_mmap(T*8) as *i64 51 i=0; while i<T { m.tvalid[i]=0; i=i+1 } 52 m.tn = T; m.tclk = 0 53 return m 54} 55func alloc_frame(m: *Mmu) -> i64 { let f: i64=m.next; m.next=m.next+1; var i: i64=0; while i<ENTRIES { m.pmem[f*ENTRIES+i]=0; i=i+1 } return f } 56func pte_make(frame: i64, flags: i64) -> i64 { return (frame<<OFFB) | flags } 57func pte_frame(pte: i64) -> i64 { return (pte>>OFFB) } 58func idxL(va: i64, shift: i64) -> i64 { return (va>>shift)&511 } 59 60// map VA -> data_frame with leaf protection flags; create intermediate tables on demand. 61func mmu_map(m: *Mmu, va: i64, data_frame: i64, leaf_flags: i64) -> i64 { 62 let pmem: *i64 = m.pmem 63 var cur: i64 = m.cr3 64 var lvl: i64 = 0 65 let shifts: *i64 = sys_mmap(4*8) as *i64; shifts[0]=39; shifts[1]=30; shifts[2]=21; shifts[3]=12 66 while lvl < 3 { // walk/create PML4,PDPT,PD 67 let ei: i64 = cur*ENTRIES + idxL(va, shifts[lvl]) 68 var e: i64 = pmem[ei] 69 if (e & F_P)==0 { let nf: i64 = alloc_frame(m); e = pte_make(nf, F_P|F_RW|F_US); pmem[ei]=e } 70 cur = pte_frame(e) 71 lvl = lvl + 1 72 } 73 let leaf: i64 = cur*ENTRIES + idxL(va, 12) // PT leaf 74 pmem[leaf] = pte_make(data_frame, leaf_flags | F_P) 75 return 0 76} 77// TLB helpers 78func tlb_lookup(m: *Mmu, vpn: i64) -> i64 { var i: i64=0; while i<m.tn { if m.tvalid[i]==1 { if m.tvpn[i]==vpn { return i } } i=i+1 } return 0-1 } 79func tlb_fill(m: *Mmu, vpn: i64, paframe: i64, flags: i64) -> i64 { 80 var slot: i64=0-1; var i: i64=0; while i<m.tn { if m.tvalid[i]==0 { slot=i; i=m.tn } else { i=i+1 } } 81 if slot<0 { slot=0 } // simple: reuse slot 0 if full 82 m.tvpn[slot]=vpn; m.tpa[slot]=paframe; m.tfl[slot]=flags; m.tvalid[slot]=1 83 return 0 84} 85func mmu_invlpg(m: *Mmu, va: i64) -> i64 { let vpn: i64=va>>OFFB; var i: i64=0; while i<m.tn { if m.tvalid[i]==1 { if m.tvpn[i]==vpn { m.tvalid[i]=0 } } i=i+1 } return 0 } 86func mmu_set_cr3(m: *Mmu, cr3: i64) -> i64 { m.cr3=cr3; var i: i64=0; while i<m.tn { m.tvalid[i]=0; i=i+1 } return 0 } // CR3 load flushes TLB 87 88// translate; want_w=1 write, want_x=1 instruction fetch. out[0]=PA on success, out[1]=1 iff TLB hit. returns 0 or a fault code. 89func mmu_translate(m: *Mmu, va: i64, want_w: i64, want_x: i64, out: *i64) -> i64 { 90 let pmem: *i64 = m.pmem 91 let vpn: i64 = va>>OFFB; let off: i64 = va & F_MAGIC_4095 92 out[1]=0 93 let hit: i64 = tlb_lookup(m, vpn) 94 if hit>=0 { 95 let fl: i64 = m.tfl[hit] 96 if want_w==1 { if (fl & F_RW)==0 { return FLT_W } } 97 if want_x==1 { if (fl & F_NX)!=0 { return FLT_X } } 98 out[0] = (m.tpa[hit]<<OFFB) | off; out[1]=1; return 0 99 } 100 var cur: i64 = m.cr3 101 var eff_rw: i64 = 1; var eff_nx: i64 = 0 102 let shifts: *i64 = sys_mmap(4*8) as *i64; shifts[0]=39; shifts[1]=30; shifts[2]=21; shifts[3]=12 103 var lvl: i64 = 0 104 while lvl < 4 { 105 let e: i64 = pmem[cur*ENTRIES + idxL(va, shifts[lvl])] 106 if (e & F_P)==0 { return FLT_NP } 107 if (e & F_RW)==0 { eff_rw=0 } 108 if (e & F_NX)!=0 { eff_nx=1 } 109 cur = pte_frame(e) 110 lvl = lvl + 1 111 } 112 // cur now = the data frame; protection is the accumulated effective permission 113 if want_w==1 { if eff_rw==0 { return FLT_W } } 114 if want_x==1 { if eff_nx==1 { return FLT_X } } 115 var leaffl: i64 = F_P; if eff_rw==1 { leaffl=leaffl|F_RW } if eff_nx==1 { leaffl=leaffl|F_NX } 116 tlb_fill(m, vpn, cur, leaffl) 117 out[0] = (cur<<OFFB) | off 118 return 0 119} 120 121// ★ the real-hardware CR3 activation path -- REFUSED BY CONSTRUCTION (no real MMU write exists here). 122// A real activation requires a separately-proven never-brick hardware capability (absent) -> always -1 (refused). 123func mmu_activate_real(neverbrick_hw_proof: i64) -> i64 { if neverbrick_hw_proof==0 { return 0-1 } return 0-1 } 124 125func main() -> i64 { 126 g_puts("nx_mmu_hw (x86-64 4-LEVEL page-table walk MODEL: PML4->PDPT->PD->PT, CR3, protection, TLB; MODEL only, never touches the real MMU)\n" as *u8) 127 var pass: i64=0; var total: i64=0 128 let m: *Mmu = mmu_new() 129 let out: *i64 = sys_mmap(4*8) as *i64 130 131 // T1: map VA 0x1234000-ish -> a data frame, translate a VA with offset -> exact PA 132 let dframe: i64 = alloc_frame(m) 133 let va1: i64 = (1<<39) | (2<<30) | (3<<21) | (4<<12) | 0x111 // distinct index at every level + offset 134 mmu_map(m, va1, dframe, F_RW|F_US) 135 let r1: i64 = mmu_translate(m, va1, 0, 0, out) 136 let expect_pa: i64 = (dframe<<OFFB) | 0x111 137 var t1: i64=0; if r1==0 { if out[0]==expect_pa { t1=1 } } 138 g_puts(" T1 4-level walk: VA(l4=1,l3=2,l2=3,l1=4,off=0x111) -> PA="); g_pn(out[0]); g_puts(" (expect frame "); g_pn(dframe); g_puts(" -> "); g_pn(expect_pa); g_puts(")\n" as *u8) 139 pass=pass+ck("T1: the 4-level page-table walk translates VA -> the exact PA (frame<<12 | offset)" as *u8, t1); total=total+1 140 141 // T2: an unmapped VA -> page fault (not present) 142 let va2: i64 = (5<<39) | (6<<30) | (7<<21) | (8<<12) 143 let r2: i64 = mmu_translate(m, va2, 0, 0, out) 144 var t2: i64=0; if r2==FLT_NP { t2=1 } 145 g_puts(" T2 unmapped VA -> fault code "); g_pn(r2); g_puts(" ("); g_pn(FLT_NP); g_puts("=not-present)\n" as *u8) 146 pass=pass+ck("T2: an unmapped VA raises a PAGE FAULT (not-present) -- no false translation" as *u8, t2); total=total+1 147 148 // T3: protection -- a read-only page (no F_RW) faults on WRITE but not READ; an NX page faults on EXECUTE 149 let rof: i64 = alloc_frame(m); let vaR: i64 = (2<<39)|(2<<30)|(2<<21)|(2<<12) 150 mmu_map(m, vaR, rof, F_US) // leaf: present+user, NO write bit -> read-only 151 let rd: i64 = mmu_translate(m, vaR, 0, 0, out) // read ok 152 let wr: i64 = mmu_translate(m, vaR, 1, 0, out) // write -> fault 153 let nxf: i64 = alloc_frame(m); let vaX: i64 = (3<<39)|(3<<30)|(3<<21)|(3<<12) 154 mmu_map(m, vaX, nxf, F_RW|F_US|F_NX) // leaf: NX set 155 let ex: i64 = mmu_translate(m, vaX, 0, 1, out) // execute -> NX fault 156 var t3: i64=0; if rd==0 { if wr==FLT_W { if ex==FLT_X { t3=1 } } } 157 g_puts(" T3 protection: read-only page read="); g_pn(rd); g_puts(" write="); g_pn(wr); g_puts(" ("); g_pn(FLT_W); g_puts("=W-fault); NX page execute="); g_pn(ex); g_puts(" ("); g_pn(FLT_X); g_puts("=NX-fault)\n" as *u8) 158 pass=pass+ck("T3: protection bits enforced -- RO page faults on write, NX page faults on execute (down-level accumulation)" as *u8, t3); total=total+1 159 160 // T4: TLB -- first translate is a miss (fills), second is a HIT; invlpg evicts (miss again); CR3 reload flushes 161 mmu_invlpg(m, va1) // clear any prior TLB entry for va1 162 let m1: i64 = mmu_translate(m, va1, 0, 0, out); let hit1: i64 = out[1] // miss (fill) 163 let m2: i64 = mmu_translate(m, va1, 0, 0, out); let hit2: i64 = out[1] // hit 164 mmu_invlpg(m, va1) 165 let m3: i64 = mmu_translate(m, va1, 0, 0, out); let hit3: i64 = out[1] // miss again 166 let m4: i64 = mmu_translate(m, va1, 0, 0, out); let hit4: i64 = out[1] // hit 167 mmu_set_cr3(m, m.cr3) // CR3 reload -> flush TLB 168 let m5: i64 = mmu_translate(m, va1, 0, 0, out); let hit5: i64 = out[1] // miss after flush 169 var t4: i64=0; if hit1==0 { if hit2==1 { if hit3==0 { if hit4==1 { if hit5==0 { t4=1 } } } } } 170 g_puts(" T4 TLB: miss="); g_pn(hit1); g_puts(" hit="); g_pn(hit2); g_puts(" invlpg->miss="); g_pn(hit3); g_puts(" hit="); g_pn(hit4); g_puts(" CR3flush->miss="); g_pn(hit5); g_puts("\n" as *u8) 171 pass=pass+ck("T4: TLB caches translations -- miss fills, second is a HIT; invlpg + CR3 reload invalidate correctly" as *u8, t4); total=total+1 172 173 // T5 NEVER-BRICK: the real-CR3 activation is REFUSED by construction; + determinism (translate twice = same PA) 174 let act: i64 = mmu_activate_real(0) 175 let d1: i64 = mmu_translate(m, va1, 0, 0, out); let pa_a: i64 = out[0] 176 let d2: i64 = mmu_translate(m, va1, 0, 0, out); let pa_b: i64 = out[0] 177 var t5: i64=0; if act==(0-1) { if pa_a==pa_b { t5=1 } } 178 g_puts(" T5 never-brick: mmu_activate_real(no-proof)="); g_pn(act); g_puts(" (-1=REFUSED by construction, no real CR3 write); determinism PA1="); g_pn(pa_a); g_puts(" PA2="); g_pn(pa_b); g_puts("\n" as *u8) 179 pass=pass+ck("T5 (NEVER-BRICK, cardinal 26): real-CR3 activation REFUSED by construction (no MMU write path) + deterministic" as *u8, t5); total=total+1 180 181 var okall: i64=0; if pass==total { okall=1 } 182 g_puts("---- nx_mmu_hw: passed "); g_pn(pass); g_puts(" / "); g_pn(total); g_puts(" ----\n" as *u8) 183 if okall==1 { 184 let logf: i64=sys_openat_append("knowledge/status/mmu_hw.log" as *u8, 420) 185 if logf>=0 { let z: i64=sys_write(logf,"NXMMUHW GREEN: x86-64 4-level page-table walk MODEL (PML4/PDPT/PD/PT, CR3, protection accumulation, TLB+flush); NEVER-BRICK -- real CR3 activation refused by construction\n" as *u8,162); sys_close(logf) } 186 g_puts("verdict=GREEN (x86-64 4-level MMU model: faithful hardware page-table structures, protection, TLB; MODEL only -- never touches the real MMU, activation refused by construction; deepens MEMORY-MGMT)\n" as *u8); sys_exit(0); return 0 187 } 188 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1 189}