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}