code wiki / _hdl_build / nx_emu_uefi.nx
nx_emu_uefi.nx source
↩ module page · 1368 lines · 76880 B
1// nx_emu_uefi.nx -- the sovereign UEFI EXECUTION-PROOF harness (NOS execution gate).
2//
3// A purpose-built minimal x86-64 interpreter WITH a flat memory model + stack + a hooked
4// UEFI SystemTable, just enough to EXECUTE the entry of an emitted nx_boot_uefi*.efi and
5// PROVE it does what it claims -- the in-house analog of running the RV64 boot stub on
6// rv64im_min_sim (no qemu, no real laptop). It sets up a mock SystemTable/ConOut whose
7// OutputString is a sentinel HOOK; when the executed code calls it, we CAPTURE the UTF-16
8// string it asked to print. A correct nx_boot_uefi prints "NISHI"; the buggy off-by-one
9// variant would capture garbage -- so this is a real gate, not a structural rubber-stamp.
10//
11// Memory is the flat image space with ImageBase=0: .text loaded at its RVA (0x1000), so
12// RIP-relative leas resolve to the real string RVAs. Mock UEFI placed elsewhere in MEM.
13//
14// Decoded forms (exactly what the nx_boot_uefi* / nx_gop_efi emitters produce):
15// 50+r push r64 | 58+r pop r64 | C3 ret | 31 /r xor r/m,r (reg-direct)
16// 48 83 grp1 (add/sub/and/cmp imm8) | 48 C7 mov r64,imm32 | 48 C1/D3 shr | 48 01/29/39 add/sub/cmp
17// 48 31 /r xor r64,r64 (reg-direct) | 48 89 /r mov store | 48 8B /r mov load (disp8/SIB+disp8/disp32/reg)
18// 48 8D lea [rip+disp32] (mod00) or [SIB-base+disp8] (mod01) | B8+rd mov r32,imm32 (zero-extended)
19// FC cld | F3 AB rep stosd (one interpreter step, bounds-refused -34)
20// FF /2 call [base+disp8] (mod01) or call r64 (mod11) -- HOOK-aware
21// EB FE jmp $ -> distinct HOLD return: a painting app KEEPS the screen; the verdict is then
22// decided by MEASURING the modeled framebuffer (color read from the artifact, never assumed):
23// nonzero color AND 100% fill -> PAINTED-AND-HOLDING, anything less -> RED.
24// Mock UEFI hooks: ConOut->OutputString (capture) | BootServices->GetMemoryMap (writes 0x1800) |
25// BootServices->LocateProtocol (GUID-CHECKED: only the GOP GUID is served, wrong GUID -> -33)
26// -> modeled GOP: gop->Mode->FrameBufferBase/Size = a real 1280x800x32 in-MEM framebuffer
27// (mirrors the OVMF oracle mode, so sovereign + foreign engines judge the same geometry).
28// Usage: nx_emu_uefi <path.efi> [expect-prefix] | nx_emu_uefi selftest (4 teeth incl. negative controls)
29// Gate: captured console output begins "NISHI" -> GREEN. Log -> knowledge/status/nishi_os.log
30// Sovereign: syscalls only, no gcc/qemu/.sh. license_tier: ORIGINAL
31import "nx_syscalls.nx"
32const RET_MAGIC_200000: i64 = 200000
33
34const MEMSZ: i64 = 0x800000 // raised for AI2: the served AI blob sits above the kernel window
35const HOOK: i64 = 0x9000
36const RET_SENTINEL: i64 = 0xC0DE
37const ST_ADDR: i64 = 0x4000
38const CO_ADDR: i64 = 0x4800
39const FV_ADDR: i64 = 0x4900
40const STACK_TOP: i64 = 0x20000 // RAISED: the loader's virtual image (code + reserves) now ends
41 // near 0x8DC0, and a stack growing down from 0x8000 would have
42 // grown straight into the assistant reserve. A stack that shares
43 // an address with the data it is loading is the modelled-
44 // peripheral bug wearing different clothes -- moved, not shrunk.
45const BS_ADDR: i64 = 0x4C00
46const HOOK2: i64 = 0x9100
47const HOOK3: i64 = 0x9200
48const HOOK4: i64 = 0x9300
49const HOOK5: i64 = 0x9400
50const CI_ADDR: i64 = 0x4A00
51const KEYQ_ADDR: i64 = 0x4B00
52const EFI_NOT_READY: i64 = 6
53const EFI_NOT_FOUND: i64 = 14 // what real firmware returns for a file that is not there --
54 // the ABSENT assistant file must look exactly like this
55const EFI_INVALID_PARAM: i64 = 2
56const EFI_BUFFER_TOO_SMALL: i64 = 5
57// N4: the firmware handoff is modeled with REAL protocol teeth, not a rubber stamp --
58// GetMemoryMap is a genuine two-call sequence and ExitBootServices REFUSES a stale MapKey,
59// which is the classic UEFI mistake. EBS_STATE tracks whether firmware has been surrendered;
60// after that, every firmware service must FAIL, because that is what real hardware does.
61const MM_REQ_BYTES: i64 = 0x1800 // DEFAULT modeled map size (see MM_SIZE_SLOT -- this is a
62 // MODEL, not a measurement: real EDK2 returned 0x18F0 on the
63 // same payload, debt 1786237098. A rung that asserts an exact
64 // ram-map size against this organ is asserting THIS CONSTANT.)
65const MM_SIZE_SLOT: i64 = 0x4D10 // caller-settable via --mmsize; 0 = unset -> MM_REQ_BYTES.
66 // Lives in MEM (not a global) so the selftest fixtures, which
67 // mmap fresh zeroed memory, keep the default BY CONSTRUCTION.
68const MM_DESC_SIZE: i64 = 0x30 // EFI_MEMORY_DESCRIPTOR stride
69const MM_MAPKEY: i64 = 0x5AFEC0DE // the key a SUCCESSFUL GetMemoryMap issues
70const EBS_STATE: i64 = 0x4D00 // [0]=exited? [8]=issued map key
71// N1-full: model the UEFI file-read chain the shim must use to load its OWN kernel off the ESP.
72// Every step is GUID- or handle-checked so a wrong protocol is REFUSED rather than served.
73const HOOK6: i64 = 0x9500 // BootServices->HandleProtocol
74const HOOK7: i64 = 0x9600 // SimpleFileSystem->OpenVolume
75const HOOK8: i64 = 0x9700 // File->Open
76const HOOK9: i64 = 0x9800 // File->Read
77// FS-2: BootServices->LocateHandleBuffer. The loader must stop ASSUMING the optional file is on the
78// volume it booted from and start SEARCHING every filesystem the firmware knows about. The model
79// therefore serves TWO volumes and puts the assistant file ONLY on the second one -- a loader that
80// checks just its own volume fails this harness by construction, which is the whole point.
81const HOOK10: i64 = 0x9900 // BootServices->LocateHandleBuffer (BS + 0x138)
82const DEV2_HANDLE: i64 = 0x501100 // the DATA partition's device handle
83const FS2_ADDR: i64 = 0x502100 // its EFI_SIMPLE_FILE_SYSTEM
84const ROOT2_ADDR: i64 = 0x503100 // its root EFI_FILE
85const HBUF_ADDR: i64 = 0x509000 // the handle array firmware hands back
86const HCNT_ADDR: i64 = 0x50A000 // and its count
87// ⚠These MUST live outside the guest image. First placement (0x5200-0x5700) landed INSIDE the
88// loaded .text -- directly on the embedded KERNEL.NXE at 0x5280 -- so wiring the vtables silently
89// corrupted the payload, its checksum failed, and the shim took its refusal path to a black
90// screen. ★★★★★A MODELED PERIPHERAL PLACED INSIDE THE GUEST'S ADDRESS SPACE IS NOT A PERIPHERAL,
91// IT IS MEMORY CORRUPTION WEARING A DEVICE'S NAME. Image ~0x1000-0x6400, framebuffer to 0x4E8000.
92const LI_ADDR: i64 = 0x500000 // EFI_LOADED_IMAGE_PROTOCOL (+0x18 DeviceHandle)
93const DEV_HANDLE: i64 = 0x501000 // the ESP device handle we hand back
94const FS_ADDR: i64 = 0x502000 // EFI_SIMPLE_FILE_SYSTEM (+0x08 OpenVolume)
95const ROOT_ADDR: i64 = 0x503000 // root EFI_FILE_PROTOCOL (+0x08 Open)
96const FILE_ADDR: i64 = 0x504000 // opened EFI_FILE_PROTOCOL (+0x20 Read)
97const KFILE_LEN: i64 = 0x505000 // [0] = served file length
98const KFILE_DATA: i64 = 0x580000
99// AI2: the OPTIONAL assistant file is a SECOND named file on the same modeled ESP. Modeling it as a
100// distinct handle+buffer (not a second read of the same one) is what lets Open() be NAME-AWARE, which
101// is the only way the harness can exercise "the file is absent" -- the default state of the toggle.
102const AIFILE_ADDR: i64 = 0x507000 // opened EFI_FILE_PROTOCOL for the AI blob
103const AIFILE_LEN: i64 = 0x508000 // [0] = served AI blob length (0 = ABSENT, Open must refuse)
104const AIFILE_DATA: i64 = 0x600000 // served AI bytes (above the kernel window, inside MEMSZ)
105// HW1 (A16 spore): a modeled PCI config-space window. CONFIG_ADDRESS (0xCF8) is a SELECTOR --
106// writing it chooses which register a subsequent read returns, and changes no device state.
107// CONFIG_DATA (0xCFC) is READ ONLY here: a write to it would mutate a device's configuration,
108// so it is refused by construction. That is the whole never-brick rule for bus enumeration.
109const PCI_ADDR_PORT: i64 = 0xCF8
110const PCI_DATA_PORT: i64 = 0xCFC
111const PCI_LATCH: i64 = 0x506000 // last value written to CONFIG_ADDRESS
112const PCI_NDEV: i64 = 3 // modeled devices on bus 0, functions 0 // served file bytes (well clear of the framebuffer)
113// N4b: a modeled PS/2 controller. After ExitBootServices there is no ConIn, so a real OS talks
114// to the 8042 directly: port 0x64 is status (bit0 = a byte is waiting), port 0x60 is the data
115// register. Both are READS -- nothing here writes hardware state.
116const PS2_STATE: i64 = 0x4E00 // [0]=count [8]=index [16+8i]=scancodes
117const PS2_PORT_STATUS: i64 = 0x64
118const PS2_PORT_DATA: i64 = 0x60
119const GOP_ADDR: i64 = 0x5000
120const MODE_ADDR: i64 = 0x5100
121const FB_ADDR: i64 = 0x100000
122const FB_SIZE: i64 = 0x3E8000
123const FB_W_PIX: i64 = 1280
124const FB_H_PIX: i64 = 800
125
126// reg indices: 0 rax 1 rcx 2 rdx 3 rbx 4 rsp 5 rbp 6 rsi 7 rdi
127const R_RAX: i64 = 0
128const R_RCX: i64 = 1
129const R_RDX: i64 = 2
130const R_RSP: i64 = 4
131const R_RDI: i64 = 7
132
133// ===== flat-memory access ========================================================
134func m_r8(mem: *u8, a: i64) -> i64 { return mem[a] as i64 }
135func m_r64(mem: *u8, a: i64) -> i64 {
136 var v: i64 = 0; var i: i64 = 0
137 while i < 8 { v = v | ((mem[a + i] as i64) << (8 * i)); i = i + 1 }
138 return v
139}
140func m_w64(mem: *u8, a: i64, v: i64) -> i64 {
141 var i: i64 = 0
142 while i < 8 { mem[a + i] = ((v >> (8 * i)) & 0xff) as u8; i = i + 1 }
143 return 0
144}
145func m_w16(mem: *u8, a: i64, v: i64) -> i64 {
146 mem[a] = (v & 0xff) as u8; mem[a + 1] = ((v >> 8) & 0xff) as u8; return 0
147}
148// little-endian imm32, sign-extended (operands live in MEM alongside code)
149func m_i32(mem: *u8, off: i64) -> i64 {
150 var v: i64 = (mem[off] as i64) | ((mem[off+1] as i64) << 8) | ((mem[off+2] as i64) << 16) | ((mem[off+3] as i64) << 24)
151 if (v & 0x80000000) != 0 { v = v - (1 << 32) }
152 return v
153}
154// unsigned 32 from a file buffer (PE header fields)
155func f_u32(fb: *u8, off: i64) -> i64 {
156 return (fb[off] as i64) | ((fb[off+1] as i64) << 8) | ((fb[off+2] as i64) << 16) | ((fb[off+3] as i64) << 24)
157}
158func sx8(b: i64) -> i64 { if b >= 128 { return b - 256 } return b }
159
160// capture the UTF-16LE string at mem[straddr] (low bytes) into out[]; return new outn
161func cap_str(mem: *u8, straddr: i64, out: *u8, outn: i64) -> i64 {
162 var a: i64 = straddr; var n: i64 = outn; var go: i64 = 1
163 while go == 1 {
164 let lo: i64 = mem[a] as i64
165 let hi: i64 = mem[a + 1] as i64
166 if (lo | (hi << 8)) == 0 { go = 0 } else { out[n] = lo as u8; n = n + 1; a = a + 2 }
167 }
168 return n
169}
170
171// EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID 9042a9de-23dc-4a38-96fb-7aded080516a (UEFI-spec bytes, mixed-endian).
172// Restated from the spec here so the reader never borrows the writer's table -- LocateProtocol REFUSES (-33)
173// any other GUID instead of handing out the modeled GOP for whatever is asked.
174// EFI_LOADED_IMAGE_PROTOCOL_GUID 5B1B31A1-9562-11d2-8E3F-00A0C969723B
175func li_guid_b(i: i64) -> i64 {
176 if i==0 { return 0xA1 } if i==1 { return 0x31 } if i==2 { return 0x1B } if i==3 { return 0x5B }
177 if i==4 { return 0x62 } if i==5 { return 0x95 } if i==6 { return 0xD2 } if i==7 { return 0x11 }
178 if i==8 { return 0x8E } if i==9 { return 0x3F } if i==10 { return 0x00 } if i==11 { return 0xA0 }
179 if i==12 { return 0xC9 } if i==13 { return 0x69 } if i==14 { return 0x72 } return 0x3B
180}
181// EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID 964E5B22-6459-11D2-8E39-00A0C969723B
182func fs_guid_b(i: i64) -> i64 {
183 if i==0 { return 0x22 } if i==1 { return 0x5B } if i==2 { return 0x4E } if i==3 { return 0x96 }
184 if i==4 { return 0x59 } if i==5 { return 0x64 } if i==6 { return 0xD2 } if i==7 { return 0x11 }
185 if i==8 { return 0x8E } if i==9 { return 0x39 } if i==10 { return 0x00 } if i==11 { return 0xA0 }
186 if i==12 { return 0xC9 } if i==13 { return 0x69 } if i==14 { return 0x72 } return 0x3B
187}
188// Compare the UTF-16LE filename at mem[at] against one of the two names this modeled ESP serves.
189// which: 0 = "KERNEL.NXE", 1 = "NISHI.AI". The table is restated here rather than shared with the
190// loader's table -- a reader that borrows the writer's bytes cannot catch the writer's typo.
191func esp_name_ch(which: i64, i: i64) -> i64 {
192 if which == 0 {
193 if i==0 { return 0x4B } if i==1 { return 0x45 } if i==2 { return 0x52 } if i==3 { return 0x4E }
194 if i==4 { return 0x45 } if i==5 { return 0x4C } if i==6 { return 0x2E } if i==7 { return 0x4E }
195 if i==8 { return 0x58 } if i==9 { return 0x45 } return 0
196 }
197 if i==0 { return 0x4E } if i==1 { return 0x49 } if i==2 { return 0x53 } if i==3 { return 0x48 }
198 if i==4 { return 0x49 } if i==5 { return 0x2E } if i==6 { return 0x41 } if i==7 { return 0x49 }
199 return 0
200}
201func u16_name_is(mem: *u8, at: i64, which: i64) -> i64 {
202 var i: i64 = 0
203 var go: i64 = 1
204 while go == 1 {
205 let want: i64 = esp_name_ch(which, i)
206 let lo: i64 = mem[at + i * 2] as i64
207 let hi: i64 = mem[at + i * 2 + 1] as i64
208 if hi != 0 { return 0 }
209 if lo != want { return 0 }
210 if want == 0 { go = 0 }
211 i = i + 1
212 }
213 return 1
214}
215func guid_eq(mem: *u8, at: i64, which: i64) -> i64 {
216 var i: i64 = 0
217 while i < 16 {
218 var want: i64 = 0
219 if which == 0 { want = li_guid_b(i) } else { want = fs_guid_b(i) }
220 if (mem[at + i] as i64) != want { return 0 }
221 i = i + 1
222 }
223 return 1
224}
225
226
227// The N1-full file-chain hooks, in ONE place so the selftest exercises exactly what the
228// interpreter runs. Returns 0 = handled OK, negative = refusal sentinel, 1 = not my hook.
229// The modeled bus: three devices at slots 0,1,2. Everything else reads back all-ones, which is
230// exactly how real hardware says "nothing here" -- so the kernel's enumeration must treat
231// 0xFFFFFFFF as absence rather than as a device, or it will invent hardware.
232func pci_cfg_read(latch: i64) -> i64 {
233 if (latch & 0x80000000) == 0 { return 0xFFFFFFFF } // enable bit clear
234 let bus: i64 = (latch >> 16) & 0xFF
235 let dev: i64 = (latch >> 11) & 0x1F
236 let fun: i64 = (latch >> 8) & 0x07
237 let off: i64 = latch & 0xFC
238 if bus != 0 { return 0xFFFFFFFF }
239 if fun != 0 { return 0xFFFFFFFF }
240 if dev >= PCI_NDEV { return 0xFFFFFFFF }
241 if off == 0 {
242 if dev == 0 { return 0x12378086 } // host bridge (vendor 8086)
243 if dev == 1 { return 0x100E8086 } // network (vendor 8086)
244 return 0x00281AF4 // virtio block (vendor 1AF4)
245 }
246 if off == 8 {
247 if dev == 0 { return 0x06000001 } // class 06 bridge
248 if dev == 1 { return 0x02000001 } // class 02 network
249 return 0x01000001 // class 01 storage
250 }
251 return 0
252}
253
254func emu_hook_call(mem: *u8, tgt: i64, reg: *i64) -> i64 {
255 if tgt == HOOK6 { // HandleProtocol(rcx=handle, rdx=&GUID, r8=&iface)
256 if guid_eq(mem, reg[R_RDX], 0) == 1 {
257 m_w64(mem, reg[8], LI_ADDR); reg[R_RAX] = 0; return 0
258 }
259 if guid_eq(mem, reg[R_RDX], 1) == 1 {
260 // Two volumes now: the boot ESP and the DATA partition. Serve each its OWN filesystem,
261 // and refuse anything else -- a handle we did not hand out must never resolve.
262 if reg[R_RCX] == DEV_HANDLE { m_w64(mem, reg[8], FS_ADDR); reg[R_RAX] = 0; return 0 }
263 if reg[R_RCX] == DEV2_HANDLE { m_w64(mem, reg[8], FS2_ADDR); reg[R_RAX] = 0; return 0 }
264 return 0 - 39
265 }
266 return 0 - 33 // any other protocol: REFUSED
267 }
268 if tgt == HOOK7 { // OpenVolume(rcx=This, rdx=&root)
269 if reg[R_RCX] == FS_ADDR { m_w64(mem, reg[R_RDX], ROOT_ADDR); reg[R_RAX] = 0; return 0 }
270 if reg[R_RCX] == FS2_ADDR { m_w64(mem, reg[R_RDX], ROOT2_ADDR); reg[R_RAX] = 0; return 0 }
271 return 0 - 39
272 }
273 if tgt == HOOK10 { // LocateHandleBuffer(rcx=SearchType, rdx=&GUID,
274 // r8=SearchKey, r9=&count, [rsp+0x20]=&buffer)
275 if reg[R_RCX] != 2 { return 0 - 43 } // ByProtocol only -- AllHandles would
276 // hand back handles we never checked
277 if guid_eq(mem, reg[R_RDX], 1) == 0 { return 0 - 33 }
278 m_w64(mem, HBUF_ADDR + 0, DEV_HANDLE)
279 m_w64(mem, HBUF_ADDR + 8, DEV2_HANDLE)
280 m_w64(mem, reg[9], 2)
281 m_w64(mem, m_r64(mem, reg[R_RSP] + 0x20), HBUF_ADDR)
282 reg[R_RAX] = 0
283 return 0
284 }
285 if tgt == HOOK8 { // Open(rcx=This, rdx=&new, r8=name, r9=mode)
286 if reg[R_RCX] != ROOT_ADDR { if reg[R_RCX] != ROOT2_ADDR { return 0 - 39 } }
287 if reg[9] != 1 { return 0 - 40 } // READ only -- a writable open of the boot volume is
288 // refused by construction (never-brick posture)
289 // NAME-AWARE. Serving whatever is asked for would make "the optional file is missing" an
290 // UNTESTABLE state, and that state is the DEFAULT of the assistant toggle -- the one the
291 // harness most needs to exercise. Unknown name -> EFI_NOT_FOUND, exactly like real firmware.
292 if u16_name_is(mem, reg[8], 1) == 1 { // L"NISHI.AI"
293 // MODELLED DELIBERATELY: the assistant file lives ONLY on the DATA volume. A loader that
294 // opens it on its own boot volume gets NOT_FOUND here and must go looking.
295 if reg[R_RCX] != ROOT2_ADDR { reg[R_RAX] = EFI_NOT_FOUND; return 0 }
296 if m_r64(mem, AIFILE_LEN) <= 0 { reg[R_RAX] = EFI_NOT_FOUND; return 0 }
297 m_w64(mem, reg[R_RDX], AIFILE_ADDR); reg[R_RAX] = 0; return 0
298 }
299 if u16_name_is(mem, reg[8], 0) == 1 { // L"KERNEL.NXE" -- boot volume only
300 if reg[R_RCX] != ROOT_ADDR { reg[R_RAX] = EFI_NOT_FOUND; return 0 }
301 if m_r64(mem, KFILE_LEN) <= 0 { reg[R_RAX] = EFI_NOT_FOUND; return 0 }
302 m_w64(mem, reg[R_RDX], FILE_ADDR); reg[R_RAX] = 0; return 0
303 }
304 reg[R_RAX] = EFI_NOT_FOUND; return 0
305 }
306 if tgt == HOOK9 { // Read(rcx=This, rdx=&size, r8=buf)
307 if reg[R_RCX] == AIFILE_ADDR { // the optional assistant blob
308 let ahave: i64 = m_r64(mem, AIFILE_LEN)
309 var awant: i64 = m_r64(mem, reg[R_RDX])
310 if awant > ahave { awant = ahave }
311 var ai: i64 = 0
312 while ai < awant { mem[reg[8] + ai] = mem[AIFILE_DATA + ai]; ai = ai + 1 }
313 m_w64(mem, reg[R_RDX], awant)
314 reg[R_RAX] = 0
315 return 0
316 }
317 if reg[R_RCX] != FILE_ADDR { return 0 - 39 }
318 let have: i64 = m_r64(mem, KFILE_LEN)
319 var want: i64 = m_r64(mem, reg[R_RDX])
320 if want > have { want = have }
321 var ci: i64 = 0
322 while ci < want { mem[reg[8] + ci] = mem[KFILE_DATA + ci]; ci = ci + 1 }
323 m_w64(mem, reg[R_RDX], want)
324 reg[R_RAX] = 0
325 return 0
326 }
327 return 1
328}
329
330func gop_guid_b(i: i64) -> i64 {
331 if i==0 { return 0xDE } if i==1 { return 0xA9 } if i==2 { return 0x42 } if i==3 { return 0x90 }
332 if i==4 { return 0xDC } if i==5 { return 0x23 } if i==6 { return 0x38 } if i==7 { return 0x4A }
333 if i==8 { return 0x96 } if i==9 { return 0xFB } if i==10 { return 0x7A } if i==11 { return 0xDE }
334 if i==12 { return 0xD0 } if i==13 { return 0x80 } if i==14 { return 0x51 } return 0x6A
335}
336
337// ===== the interpreter: run from entry RVA; capture ConOut output into out; return outn or -err =====
338func emu_run(mem: *u8, entry: i64, out: *u8, trace: i64) -> i64 {
339 let reg: *i64 = sys_mmap(8 * 16) as *i64
340 var pc: i64 = entry
341 var outn: i64 = 0
342 reg[R_RSP] = STACK_TOP
343 reg[R_RSP] = reg[R_RSP] - 8
344 m_w64(mem, reg[R_RSP], RET_SENTINEL) // so the entry's final ret stops us
345 reg[R_RCX] = 0x1234 // ImageHandle
346 reg[R_RDX] = ST_ADDR // SystemTable*
347 var steps: i64 = 0
348 var flagv: i64 = 0 // last cmp/sub result (for jcc); ZF=(==0) SF=(<0)
349 while steps < RET_MAGIC_200000 {
350 steps = steps + 1
351 // An emulator must never fault on guest behaviour -- a wild pc is the GUEST's bug and must
352 // be REFUSED with evidence, not turned into a host segfault that says nothing.
353 if pc < 0 { e_p("EMU-WILDPC negative\n" as *u8); return 0 - 36 }
354 if (pc + 16) > MEMSZ {
355 e_p("EMU-WILDPC pc=0x" as *u8); e_fx(1, pc); e_p(" step=" as *u8); e_fn(1, steps); e_p("\n" as *u8)
356 return 0 - 36
357 }
358 if trace == 1 {
359 e_p("T pc=0x" as *u8); e_fx(1, pc); e_p(" op=0x" as *u8); e_fx(1, mem[pc] as i64)
360 e_p(" rdi=0x" as *u8); e_fx(1, reg[7]); e_p(" rcx=0x" as *u8); e_fx(1, reg[R_RCX])
361 e_p(" rsi=0x" as *u8); e_fx(1, reg[6]); e_p("\n" as *u8)
362 }
363 let b: i64 = mem[pc] as i64
364 var rexR: i64 = 0
365 var rexB: i64 = 0
366 var is_rexw: i64 = 0
367 if b == 0x48 { is_rexw = 1 }
368 if b == 0x4C { is_rexw = 1; rexR = 1 } // REX.WR -> r8/r9 as lea destinations
369 if b == 0x49 { is_rexw = 1; rexB = 1 } // REX.WB -> r8/r9 as r/m dest. N1-full adds
370 // EXACTLY mov r9,imm32 (49 C7 C1): Open()'s
371 // READ mode rides r9 and lea cannot carry an
372 // immediate. Every other 49-prefixed op is
373 // REFUSED below, not silently run as its
374 // 48-prefixed twin.
375 var is_jcc: i64 = 0
376 if b >= 0x74 { if b <= 0x7F { is_jcc = 1 } } // conditional jumps
377 if b == 0xC3 { // ret
378 let tgt: i64 = m_r64(mem, reg[R_RSP])
379 reg[R_RSP] = reg[R_RSP] + 8
380 if tgt == RET_SENTINEL { return outn } // clean program return
381 pc = tgt
382 } else { if b == 0xFF { // call: [base+disp8] (/2 mod01) or r64 (/2 mod11)
383 let m: i64 = mem[pc + 1] as i64
384 let ffdig: i64 = (m >> 3) & 7
385 if ffdig != 2 { if ffdig != 4 { return 0 - 21 } }
386 let ffmod: i64 = (m >> 6) & 3
387 if ffdig == 4 { // FF /4: jmp r64 (FF E0 = jmp rax) -- the shim->NXE handoff
388 if ffmod != 3 { return 0 - 21 }
389 pc = reg[m & 7]
390 } else {
391 // ONE hook dispatch for BOTH call forms. They were split once, and a firmware service
392 // reachable via `call [mem]` was then INVISIBLE via `call rax` -- the emulator jumped
393 // into the hook's address as if it were code (sentinel -29).
394 // ★A HOOK REGISTERED ON ONE CALL FORM IS NOT REGISTERED ON THE MECHANISM.
395 var tgt: i64 = 0
396 var ilen: i64 = 0
397 if ffmod == 3 { tgt = reg[m & 7]; ilen = 2 } // call r64
398 if ffmod == 1 { // call [base+disp8]
399 tgt = m_r64(mem, reg[m & 7] + sx8(mem[pc + 2] as i64)); ilen = 3
400 }
401 if ilen == 0 { return 0 - 22 }
402 var hooked: i64 = 1
403 // Once boot services are exited, the firmware is GONE. Any further service call is a
404 // use-after-free on real hardware; the model refuses it loudly instead of pretending.
405 if m_r64(mem, EBS_STATE) == 1 {
406 if tgt == HOOK { return 0 - 37 }
407 if tgt == HOOK2 { return 0 - 37 }
408 if tgt == HOOK3 { return 0 - 37 }
409 if tgt == HOOK4 { return 0 - 37 }
410 if tgt == HOOK5 { return 0 - 37 }
411 if tgt == HOOK10 { return 0 - 37 }
412 }
413 if tgt == HOOK { // ConOut->OutputString(rcx=This, rdx=CHAR16*)
414 outn = cap_str(mem, reg[R_RDX], out, outn)
415 reg[R_RAX] = 0 // EFI_SUCCESS
416 } else { if tgt == HOOK2 {
417 // GetMemoryMap(rcx=&MapSize, rdx=MapBuf, r8=&MapKey, r9=&DescSize, [rsp+0x20]=&Ver)
418 // Real two-call protocol: too small (or NULL buffer) -> BUFFER_TOO_SMALL + the
419 // required size; big enough -> SUCCESS + a MapKey that ExitBootServices will check.
420 let want: i64 = m_r64(mem, reg[R_RCX])
421 var mmreq: i64 = m_r64(mem, MM_SIZE_SLOT) // 0 = unset (selftest fixtures) -> default
422 if mmreq <= 0 { mmreq = MM_REQ_BYTES }
423 if reg[R_RDX] == 0 { m_w64(mem, reg[R_RCX], mmreq); reg[R_RAX] = EFI_BUFFER_TOO_SMALL }
424 else { if want < mmreq { m_w64(mem, reg[R_RCX], mmreq); reg[R_RAX] = EFI_BUFFER_TOO_SMALL }
425 else {
426 m_w64(mem, reg[R_RCX], mmreq) // actual bytes written
427 if reg[8] != 0 { m_w64(mem, reg[8], MM_MAPKEY) }
428 if reg[9] != 0 { m_w64(mem, reg[9], MM_DESC_SIZE) }
429 m_w64(mem, EBS_STATE + 8, MM_MAPKEY) // the key now outstanding
430 reg[R_RAX] = 0
431 } }
432 } else { if tgt == HOOK5 { // ExitBootServices(rcx=ImageHandle, rdx=MapKey)
433 let issued: i64 = m_r64(mem, EBS_STATE + 8)
434 if issued == 0 { reg[R_RAX] = EFI_INVALID_PARAM } // never got a map
435 else { if reg[R_RDX] != issued { reg[R_RAX] = EFI_INVALID_PARAM } // STALE key refused
436 else {
437 m_w64(mem, EBS_STATE, 1) // firmware surrendered; the kernel owns the machine
438 reg[R_RAX] = 0
439 } }
440 } else { if tgt == HOOK10 { hooked = 2 } else { if tgt == HOOK6 { hooked = 2 } else { if tgt == HOOK7 { hooked = 2
441 } else { if tgt == HOOK8 { hooked = 2 } else { if tgt == HOOK9 { hooked = 2
442 } else { if tgt == HOOK3 { // BootServices->LocateProtocol(rcx=&GUID, r8=&iface)
443 var gi: i64 = 0 // the GUID is CHECKED: wrong protocol -> refused
444 while gi < 16 { if (mem[reg[R_RCX] + gi] as i64) != gop_guid_b(gi) { return 0 - 33 } gi = gi + 1 }
445 m_w64(mem, reg[8], GOP_ADDR) // *r8 = the modeled GOP interface
446 reg[R_RAX] = 0
447 } else { if tgt == HOOK4 { // ConIn->ReadKeyStroke(rcx=This, rdx=EFI_INPUT_KEY*)
448 let qn: i64 = m_r64(mem, KEYQ_ADDR) // scripted keys drain in order, then NOT_READY
449 let qi: i64 = m_r64(mem, KEYQ_ADDR + 8)
450 if qi < qn {
451 m_w16(mem, reg[R_RDX], m_r64(mem, KEYQ_ADDR + 16 + qi * 16)) // ScanCode
452 m_w16(mem, reg[R_RDX] + 2, m_r64(mem, KEYQ_ADDR + 16 + qi * 16 + 8)) // UnicodeChar
453 m_w64(mem, KEYQ_ADDR + 8, qi + 1)
454 reg[R_RAX] = 0 // EFI_SUCCESS
455 } else {
456 reg[R_RAX] = EFI_NOT_READY // an empty queue is NOT-READY, never a fake key
457 }
458 } else { hooked = 0 } } } } } } } } } }
459 if hooked == 2 {
460 let hr: i64 = emu_hook_call(mem, tgt, reg)
461 if hr < 0 { return hr }
462 pc = pc + ilen
463 } else {
464 if hooked == 1 { pc = pc + ilen } else { // a real call: push the return address
465 reg[R_RSP] = reg[R_RSP] - 8
466 m_w64(mem, reg[R_RSP], pc + ilen)
467 pc = tgt
468 } } }
469 } else { if is_rexw == 1 { // REX.W (0x48) or REX.WR (0x4C) -- flat dispatch
470 let op: i64 = mem[pc + 1] as i64
471 var hd: i64 = 0
472 // REX.WB is implemented for ONE opcode. Letting the other handlers fire with rexB set
473 // would silently write the WRONG register -- the /digit lesson applied to prefixes:
474 // ★AN OPCODE IMPLEMENTED FOR ONE PREFIX IS NOT IMPLEMENTED, IT IS MIS-EXECUTED.
475 if rexB == 1 { if op != 0xC7 {
476 e_p("EMU-UNDECODED REX.WB op=0x" as *u8); e_fx(1, op)
477 e_p(" at pc=0x" as *u8); e_fx(1, pc); e_p("\n" as *u8)
478 return 0 - 28
479 } }
480 if op == 0x83 { // grp1 r/m64,imm8 (reg-direct): add/sub/and/cmp
481 let m: i64 = mem[pc + 2] as i64
482 let imm: i64 = sx8(mem[pc + 3] as i64)
483 let dig: i64 = (m >> 3) & 7
484 if dig == 0 { reg[m & 7] = reg[m & 7] + imm }
485 if dig == 5 { reg[m & 7] = reg[m & 7] - imm }
486 if dig == 4 { reg[m & 7] = reg[m & 7] & imm }
487 if dig == 7 { flagv = reg[m & 7] - imm }
488 pc = pc + 4; hd = 1
489 }
490 if op == 0x81 { // grp1 r/m64,imm32 -- a stride that outgrew imm8
491 let m81: i64 = mem[pc + 2] as i64
492 let imm81: i64 = m_i32(mem, pc + 3)
493 let dig81: i64 = (m81 >> 3) & 7
494 if dig81 == 0 { reg[m81 & 7] = reg[m81 & 7] + imm81 }
495 if dig81 == 5 { reg[m81 & 7] = reg[m81 & 7] - imm81 }
496 if dig81 == 4 { reg[m81 & 7] = reg[m81 & 7] & imm81 }
497 if dig81 == 7 { flagv = reg[m81 & 7] - imm81 }
498 pc = pc + 7; hd = 1
499 }
500 if op == 0xC7 { reg[(rexB * 8) + ((mem[pc + 2] as i64) & 7)] = m_i32(mem, pc + 3); pc = pc + 7; hd = 1 } // mov r/m64,imm32 (rexB -> r8/r9)
501 if op == 0xC1 { // grp2 r/m64, imm8 -- /4 = shl, /5 = shr
502 // ⚠This decoded EVERY 0xC1 as shr, ignoring the /digit, so `shl rax,11` silently
503 // executed as a RIGHT shift and the PCI slot never entered the selector (the latch
504 // sat at 0x80000000 for all 32 slots). ★★★★★AN OPCODE IMPLEMENTED FOR ONE /DIGIT
505 // IS NOT IMPLEMENTED -- IT IS MIS-EXECUTED FOR THE OTHERS.
506 let m: i64 = mem[pc + 2] as i64
507 let dig: i64 = (m >> 3) & 7
508 let amt: i64 = mem[pc + 3] as i64
509 if dig == 4 { reg[m & 7] = reg[m & 7] << amt; pc = pc + 4; hd = 1 }
510 if dig == 5 { reg[m & 7] = reg[m & 7] >> amt; pc = pc + 4; hd = 1 }
511 }
512 if op == 0xD3 { // grp2 r/m64, CL -- /4 = shl, /5 = shr
513 let m: i64 = mem[pc + 2] as i64
514 let dig3: i64 = (m >> 3) & 7
515 if dig3 == 4 { reg[m & 7] = reg[m & 7] << (reg[1] & 63); pc = pc + 3; hd = 1 }
516 if dig3 == 5 { reg[m & 7] = reg[m & 7] >> (reg[1] & 63); pc = pc + 3; hd = 1 }
517 }
518 if op == 0x31 { let m: i64 = mem[pc + 2] as i64; reg[m & 7] = reg[m & 7] ^ reg[(m >> 3) & 7]; pc = pc + 3; hd = 1 } // xor r64,r64 (reg-direct)
519 if op == 0x0F { // two-byte opcode: 0F AF /r = imul r64,r/m64
520 if (mem[pc + 2] as i64) == 0xAF { // signed multiply -- the AI1 multiply-accumulate
521 let m: i64 = mem[pc + 3] as i64
522 if ((m >> 6) & 3) == 3 { reg[(m >> 3) & 7] = reg[(m >> 3) & 7] * reg[m & 7]; pc = pc + 4; hd = 1 }
523 }
524 }
525 if op == 0x01 { let m: i64 = mem[pc + 2] as i64; reg[m & 7] = reg[m & 7] + reg[(m >> 3) & 7]; pc = pc + 3; hd = 1 }
526 if op == 0x29 { let m: i64 = mem[pc + 2] as i64; reg[m & 7] = reg[m & 7] - reg[(m >> 3) & 7]; pc = pc + 3; hd = 1 }
527 if op == 0x39 { let m: i64 = mem[pc + 2] as i64; flagv = reg[m & 7] - reg[(m >> 3) & 7]; pc = pc + 3; hd = 1 }
528 if op == 0x21 { let m: i64 = mem[pc + 2] as i64; reg[m & 7] = reg[m & 7] & reg[(m >> 3) & 7]; pc = pc + 3; hd = 1 }
529 if op == 0x89 { // mov r/m64,r64 (reg-direct / [reg+disp8] store)
530 let m: i64 = mem[pc + 2] as i64
531 let mod89: i64 = (m >> 6) & 3
532 let src89: i64 = (rexR * 8) + ((m >> 3) & 7)
533 if mod89 == 3 { reg[m & 7] = reg[src89]; pc = pc + 3; hd = 1 }
534 if mod89 == 1 {
535 if (m & 7) == 4 { m_w64(mem, reg[R_RSP] + sx8(mem[pc + 4] as i64), reg[src89]); pc = pc + 5; hd = 1 }
536 else { m_w64(mem, reg[m & 7] + sx8(mem[pc + 3] as i64), reg[src89]); pc = pc + 4; hd = 1 }
537 }
538 }
539 if op == 0x8B { // mov r64,[base+disp8|SIB+disp8|base+disp32] or reg-direct
540 let m: i64 = mem[pc + 2] as i64
541 let mod: i64 = (m >> 6) & 3
542 let dst: i64 = (m >> 3) & 7
543 if mod == 1 {
544 if (m & 7) == 4 { // SIB form (no-index assumed): base from the SIB byte
545 reg[dst] = m_r64(mem, reg[(mem[pc + 3] as i64) & 7] + sx8(mem[pc + 4] as i64)); pc = pc + 5; hd = 1
546 } else {
547 reg[dst] = m_r64(mem, reg[m & 7] + sx8(mem[pc + 3] as i64)); pc = pc + 4; hd = 1
548 }
549 }
550 if mod == 2 { if (m & 7) != 4 { reg[dst] = m_r64(mem, reg[m & 7] + m_i32(mem, pc + 3)); pc = pc + 7; hd = 1 } }
551 if mod == 0 { // mov r64,[base] -- no disp (AI1 vector walk)
552 if (m & 7) != 4 { if (m & 7) != 5 { reg[dst] = m_r64(mem, reg[m & 7]); pc = pc + 3; hd = 1 } }
553 }
554 if mod == 3 { reg[dst] = reg[m & 7]; pc = pc + 3; hd = 1 }
555 }
556 if op == 0x8D { // lea r64,[rip+disp32] (mod00) | [SIB-base+disp8] (mod01)
557 let m: i64 = mem[pc + 2] as i64
558 let lmod: i64 = (m >> 6) & 3
559 if lmod == 0 { reg[(rexR * 8) + ((m >> 3) & 7)] = (pc + 7) + m_i32(mem, pc + 3); pc = pc + 7; hd = 1 }
560 if lmod == 1 {
561 if (m & 7) == 4 { // lea r64,[rsp+disp8] shape (no-index SIB)
562 reg[(rexR * 8) + ((m >> 3) & 7)] = reg[(mem[pc + 3] as i64) & 7] + sx8(mem[pc + 4] as i64); pc = pc + 5; hd = 1
563 } else { // lea r64,[base+disp8]
564 reg[(rexR * 8) + ((m >> 3) & 7)] = reg[m & 7] + sx8(mem[pc + 3] as i64); pc = pc + 4; hd = 1
565 }
566 }
567 }
568 if hd == 0 {
569 e_p("EMU-UNDECODED rex=0x" as *u8); e_fx(1, b); e_p(" op=0x" as *u8); e_fx(1, op)
570 e_p(" modrm=0x" as *u8); e_fx(1, mem[pc + 2] as i64)
571 e_p(" at pc=0x" as *u8); e_fx(1, pc); e_p("\n" as *u8)
572 return 0 - 28
573 }
574 } else { if b == 0x31 { // xor r/m,r (reg-direct)
575 let m: i64 = mem[pc + 1] as i64
576 reg[m & 7] = reg[m & 7] ^ reg[(m >> 3) & 7]
577 pc = pc + 2
578 } else { if is_jcc == 1 { // jcc rel8 (74 jz/75 jnz/7C jl/7D jge/7E jle/7F jg)
579 let rel: i64 = sx8(mem[pc + 1] as i64)
580 var taken: i64 = 0
581 if b == 0x74 { if flagv == 0 { taken = 1 } }
582 if b == 0x75 { if flagv != 0 { taken = 1 } }
583 if b == 0x7C { if flagv < 0 { taken = 1 } }
584 if b == 0x7D { if flagv >= 0 { taken = 1 } }
585 if b == 0x7E { if flagv <= 0 { taken = 1 } }
586 if b == 0x7F { if flagv > 0 { taken = 1 } }
587 if taken == 1 { pc = (pc + 2) + rel } else { pc = pc + 2 }
588 } else { if b == 0xEB { // jmp rel8; EB FE self-jump = the app deliberately HOLDS
589 let rel: i64 = sx8(mem[pc + 1] as i64)
590 if rel == (0 - 2) { return 0 - 90 } // distinct HOLD return -- judged by MEASURING the framebuffer, not an error
591 pc = (pc + 2) + rel
592 } else { if b == 0xE9 { // jmp rel32 (a loop body >127B needs it)
593 pc = (pc + 5) + m_i32(mem, pc + 1)
594 } else { if b == 0x0F { // 0F 85 = jnz rel32 (loops >127B)
595 let two: i64 = mem[pc + 1] as i64
596 if two == 0x85 { // jnz rel32
597 if flagv != 0 { pc = (pc + 6) + m_i32(mem, pc + 2) } else { pc = pc + 6 }
598 } else { if two == 0x84 { // jz rel32
599 if flagv == 0 { pc = (pc + 6) + m_i32(mem, pc + 2) } else { pc = pc + 6 }
600 } else { return 0 - 42 } }
601 } else { if b == 0xBA { // mov edx,imm32 (the port selector)
602 var pv: i64 = m_i32(mem, pc + 1)
603 if pv < 0 { pv = pv + (1 << 32) }
604 reg[R_RDX] = pv
605 pc = pc + 5
606 } else { if b == 0xEF { // OUT dx,eax -- CONFIG_ADDRESS ONLY
607 if reg[R_RDX] != PCI_ADDR_PORT {
608 // A port WRITE anywhere else can mutate device or firmware state. Refused, and
609 // named, rather than quietly permitted. (never-brick, rule 26)
610 e_p("EMU-PORT refused OUT to port 0x" as *u8); e_fx(1, reg[R_RDX]); e_p("
611" as *u8)
612 return 0 - 41
613 }
614 m_w64(mem, PCI_LATCH, reg[R_RAX] & 0xFFFFFFFF)
615 pc = pc + 1
616 } else { if b == 0xED { // IN eax,dx -- CONFIG_DATA ONLY
617 if reg[R_RDX] != PCI_DATA_PORT {
618 e_p("EMU-PORT refused IN from port 0x" as *u8); e_fx(1, reg[R_RDX]); e_p("
619" as *u8)
620 return 0 - 41
621 }
622 let plat: i64 = m_r64(mem, PCI_LATCH)
623 reg[R_RAX] = pci_cfg_read(plat)
624 pc = pc + 1
625 } else { if b == 0xE4 { // IN al,imm8 -- modeled PS/2 only
626 let port: i64 = mem[pc + 1] as i64
627 if port == PS2_PORT_STATUS {
628 let n: i64 = m_r64(mem, PS2_STATE)
629 let ix: i64 = m_r64(mem, PS2_STATE + 8)
630 if ix < n { reg[R_RAX] = 1 } else { reg[R_RAX] = 0 } // bit0 = byte waiting
631 } else { if port == PS2_PORT_DATA {
632 let n2: i64 = m_r64(mem, PS2_STATE)
633 let ix2: i64 = m_r64(mem, PS2_STATE + 8)
634 if ix2 < n2 {
635 reg[R_RAX] = m_r64(mem, PS2_STATE + 16 + ix2 * 8)
636 m_w64(mem, PS2_STATE + 8, ix2 + 1)
637 } else { reg[R_RAX] = 0 }
638 } else {
639 // Any other port is REFUSED. An emulator that invents a value for an unmodeled
640 // port teaches the kernel that made-up hardware works.
641 e_p("EMU-PORT refused unmodeled port 0x" as *u8); e_fx(1, port); e_p("
642" as *u8)
643 return 0 - 38
644 } }
645 pc = pc + 2
646 } else { if b == 0xFC { // cld (this model is always forward)
647 pc = pc + 1
648 } else { if b == 0xF3 { // F3 AB rep stosd: eax -> rcx dwords at [rdi], ONE interpreter step
649 if (mem[pc + 1] as i64) != 0xAB { return 0 - 27 }
650 let cval: i64 = reg[R_RAX] & 0xFFFFFFFF
651 while reg[R_RCX] > 0 {
652 if reg[R_RDI] < 0 { return 0 - 34 } // store outside modeled memory = refused, never wrapped
653 if (reg[R_RDI] + 4) > MEMSZ { return 0 - 34 }
654 mem[reg[R_RDI]] = (cval & 0xff) as u8
655 mem[reg[R_RDI] + 1] = ((cval >> 8) & 0xff) as u8
656 mem[reg[R_RDI] + 2] = ((cval >> 16) & 0xff) as u8
657 mem[reg[R_RDI] + 3] = ((cval >> 24) & 0xff) as u8
658 reg[R_RDI] = reg[R_RDI] + 4
659 reg[R_RCX] = reg[R_RCX] - 1
660 }
661 pc = pc + 2
662 } else { if b >= 0xB8 {
663 if b <= 0xBF { // mov r32,imm32 (B8+rd, zero-extends into r64)
664 var iv: i64 = m_i32(mem, pc + 1)
665 if iv < 0 { iv = iv + (1 << 32) }
666 reg[b - 0xB8] = iv
667 pc = pc + 5
668 } else { return 0 - 29 }
669 } else { if b >= 0x50 { // push/pop r64 (0x50..0x5F)
670 if b <= 0x57 {
671 reg[R_RSP] = reg[R_RSP] - 8
672 m_w64(mem, reg[R_RSP], reg[b - 0x50])
673 pc = pc + 1
674 } else { if b <= 0x5F {
675 reg[b - 0x58] = m_r64(mem, reg[R_RSP])
676 reg[R_RSP] = reg[R_RSP] + 8
677 pc = pc + 1
678 } else { return 0 - 20 } }
679 } else {
680 // an undecoded opcode must say WHICH one and WHERE -- a bare sentinel costs a build
681 // cycle every time. (Learned twice today: name the failing tooth, name the failing byte.)
682 e_p("EMU-UNDECODED opcode=0x" as *u8); e_fx(1, b)
683 e_p(" next=0x" as *u8); e_fx(1, mem[pc + 1] as i64)
684 e_p(" at pc=0x" as *u8); e_fx(1, pc); e_p(" step=" as *u8); e_fn(1, steps); e_p("\n" as *u8)
685 return 0 - 29
686 } } } } } } } } } } } } } } } } // <- closes the dispatch chain ONLY, back to loop depth
687 // ⚠ONE closer per `} else { if …` link. This pile has now been wrong three times while
688 // adding opcodes; ALWAYS re-run the brace-depth counter after touching the dispatch.
689 } // <- closes `while`
690 // ⚠The pile above was ONE closer too long for a day: it ended the FUNCTION, so the next line
691 // closed the loop and everything below fell OUTSIDE emu_run -- silently, because a stray
692 // statement at module level is not an error. Symptom: segfault with ZERO output (the exit
693 // block got a synthesized return of param0, main read that pointer as a length and wrote far
694 // past a 512-byte buffer). ★★★★★A DEEP ELSE-CHAIN HIDES ITS OWN MIS-NESTING -- COUNT BRACE
695 // DEPTH MECHANICALLY, NEVER BY EYE. I blamed the compiler first; the compiler was innocent.
696 return 0 - 30 // step cap: a runaway, OR a live event loop
697}
698
699// ===== I/O + log =================================================================
700func e_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
701func e_fp(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
702func e_fn(fd: i64, v: i64) -> i64 {
703 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
704 let t: *u8 = sys_mmap(28); var k: i64 = 0
705 if m == 0 { t[0] = 48; k = 1 }
706 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
707 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
708 sys_write(fd, bb, k); return 0
709}
710
711// hex print (8 digits) -- the measured fill color is reported in the artifact's own terms
712func e_fx(fd: i64, v: i64) -> i64 {
713 let hx: *u8 = "0123456789ABCDEF" as *u8
714 let bb: *u8 = sys_mmap(16)
715 var i: i64 = 0
716 while i < 8 { bb[i] = hx[(v >> (28 - 4 * i)) & 15]; i = i + 1 }
717 sys_write(fd, bb, 8); return 0
718}
719
720// Dump the modeled framebuffer as a 24-bit BMP so the operator SEES what the sovereign lane
721// measured -- the picture and the verdict come from the SAME bytes (no second render path).
722func fb_dump_bmp(mem: *u8, base: i64, w: i64, h: i64, path: *u8) -> i64 {
723 let rowb: i64 = w * 3
724 var pad: i64 = 0
725 while ((rowb + pad) % 4) != 0 { pad = pad + 1 }
726 let imgsz: i64 = (rowb + pad) * h
727 let total: i64 = 54 + imgsz
728 let bm: *u8 = sys_mmap(total + 4096)
729 bm[0] = 66 as u8; bm[1] = 77 as u8 // "BM"
730 m_w32b(bm, 2, total); m_w32b(bm, 10, 54)
731 m_w32b(bm, 14, 40); m_w32b(bm, 18, w); m_w32b(bm, 22, h)
732 bm[26] = 1 as u8; bm[28] = 24 as u8 // planes=1, bpp=24
733 m_w32b(bm, 34, imgsz)
734 var y: i64 = 0
735 while y < h {
736 let srow: i64 = base + (h - 1 - y) * w * 4 // BMP rows are bottom-up
737 var d: i64 = 54 + y * (rowb + pad)
738 var x: i64 = 0
739 while x < w {
740 bm[d] = mem[srow + x * 4] // B
741 bm[d + 1] = mem[srow + x * 4 + 1] // G
742 bm[d + 2] = mem[srow + x * 4 + 2] // R
743 d = d + 3
744 x = x + 1
745 }
746 y = y + 1
747 }
748 let fd: i64 = sys_openat_wr(path, 0x1a4)
749 if fd < 0 { return 0 - 1 }
750 sys_write(fd, bm, total)
751 sys_close(fd)
752 return total
753}
754func m_w32b(b: *u8, o: i64, v: i64) -> i64 {
755 b[o] = (v & 0xff) as u8; b[o+1] = ((v >> 8) & 0xff) as u8
756 b[o+2] = ((v >> 16) & 0xff) as u8; b[o+3] = ((v >> 24) & 0xff) as u8
757 return 0
758}
759
760// atoi for the small positive coordinates the pixel probe takes
761func s_atoi(s: *u8) -> i64 {
762 var v: i64 = 0; var i: i64 = 0
763 while s[i] != (0 as u8) {
764 let d: i64 = (s[i] as i64) - 48
765 if d < 0 { return 0 - 1 }
766 if d > 9 { return 0 - 1 }
767 v = v * 10 + d; i = i + 1
768 }
769 return v
770}
771
772// --px <x> <y> : print the exact dword at one pixel. Generic harness verb -- the emulator learns
773// no kernel geometry, the CALLER states the coordinate, so a rung can assert a computed value
774// without the emulator being taught what that value means.
775func px_probe(mem: *u8, base: i64, argc: i64, argv: *i64) -> i64 {
776 var i: i64 = 2
777 while i < (argc - 2) {
778 if s_eq(argv[i] as *u8, "--px" as *u8) == 1 {
779 let x: i64 = s_atoi(argv[i + 1] as *u8)
780 let y: i64 = s_atoi(argv[i + 2] as *u8)
781 if x < 0 { return 0 }
782 if y < 0 { return 0 }
783 let a: i64 = base + (y * FB_W_PIX + x) * 4
784 let d: i64 = (mem[a] as i64) | ((mem[a+1] as i64) << 8) | ((mem[a+2] as i64) << 16) | ((mem[a+3] as i64) << 24)
785 e_p("NOS-PX x=" as *u8); e_fn(1, x); e_p(" y=" as *u8); e_fn(1, y)
786 e_p(" value=" as *u8); e_fn(1, d); e_p(" hex=0x" as *u8); e_fx(1, d); e_p("\n" as *u8)
787 return d
788 }
789 i = i + 1
790 }
791 return 0
792}
793
794// --shot <out.bmp>, scanned at ANY argv position -- the same treatment --kernel and --aifile
795// already get. It was previously read at argv[2] in the HOLD branch and argv[4] in the EVENT-LOOP
796// branch, so the position a caller needed depended on which path the payload happened to take, and
797// getting it wrong produced NO FILE, NO ERROR and EXIT 0. A FEATURE THAT ONLY FAILS SILENTLY IS
798// INDISTINGUISHABLE FROM ONE THAT WAS NEVER COMPILED IN, so the success path now announces itself.
799// One flag, one meaning, one implementation, two call sites. Debt 1786236016.
800// The scan ends on a FLAG, never by clobbering its own cursor: a loop that exits by overshooting
801// its index destroys the position it was searching for.
802func shot_if_asked(mem: *u8, base: i64, argc: i64, argv: *i64) -> i64 {
803 var i: i64 = 2
804 var found: i64 = 0
805 while i < (argc - 1) {
806 if s_eq(argv[i] as *u8, "--shot" as *u8) == 1 {
807 if found == 0 {
808 let sp: *u8 = argv[i + 1] as *u8
809 let bw: i64 = fb_dump_bmp(mem, base, FB_W_PIX, FB_H_PIX, sp)
810 e_p("NOS-SHOT: wrote " as *u8); e_fn(1, bw); e_p("B BMP -> " as *u8)
811 e_p(sp); e_p("\n" as *u8)
812 found = 1
813 }
814 }
815 i = i + 1
816 }
817 return found
818}
819
820func s_eq(a: *u8, b: *u8) -> i64 {
821 var i: i64 = 0
822 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
823 if b[i] != (0 as u8) { return 0 }
824 return 1
825}
826
827// MEASURE the modeled framebuffer: color := first dword (never assumed from any emitter constant),
828// outp[0]=color outp[1]=dwords-matching-color outp[2]=total-dwords outp[3]=zero-dwords
829// outp[4]=adjacent-transitions (a SCENE has many; a wash has 0; an unpainted hole shows in zeros).
830func fb_measure(mem: *u8, base: i64, size: i64, outp: *i64) -> i64 {
831 let ndw: i64 = size / 4
832 let color: i64 = (mem[base] as i64) | ((mem[base+1] as i64) << 8) | ((mem[base+2] as i64) << 16) | ((mem[base+3] as i64) << 24)
833 var matches: i64 = 0
834 var zeros: i64 = 0
835 var trans: i64 = 0
836 var prev: i64 = color
837 var i: i64 = 0
838 while i < ndw {
839 let o: i64 = base + i * 4
840 let d: i64 = (mem[o] as i64) | ((mem[o+1] as i64) << 8) | ((mem[o+2] as i64) << 16) | ((mem[o+3] as i64) << 24)
841 if d == color { matches = matches + 1 }
842 if d == 0 { zeros = zeros + 1 }
843 if d != prev { trans = trans + 1 }
844 prev = d
845 i = i + 1
846 }
847 outp[0] = color; outp[1] = matches; outp[2] = ndw; outp[3] = zeros; outp[4] = trans
848 return matches
849}
850
851// PURE verdict for a HOLDING app (testable without waiting on a real image):
852// 1 = PAINTED-AND-HOLDING (uniform nonzero wash covers 100%)
853// 2 = SCENE-PAINTED-AND-HOLDING (every dword nonzero AND >=4 transitions = a composed scene)
854// 0 = not painted (any zero dword, or a black wash)
855func hold_verdict(color: i64, matches: i64, ndw: i64, zeros: i64, trans: i64) -> i64 {
856 if ndw <= 0 { return 0 }
857 if color != 0 { if matches == ndw { return 1 } }
858 if zeros == 0 { if trans >= 4 { return 2 } }
859 return 0
860}
861
862// selftest byte writers
863func st_w(mem: *u8, o: i64, v: i64) -> i64 { mem[o] = (v & 0xff) as u8; return o + 1 }
864func st_i32(mem: *u8, o: i64, v: i64) -> i64 {
865 st_w(mem, o, v); st_w(mem, o + 1, v >> 8); st_w(mem, o + 2, v >> 16); st_w(mem, o + 3, v >> 24); return o + 4
866}
867
868// ===== in-process teeth (every selftest run refutable; negative controls are the point) ======
869// T1 hold-without-paint must NOT read as painted. T2 full paint + hold IS painted. T3 partial
870// paint must NOT read as painted (the 1000-permil bar has a bite). T4 wrong GUID is refused -33.
871func emu_selftest() -> i64 {
872 let out: *u8 = sys_mmap(512)
873 let mm: *i64 = sys_mmap(48) as *i64
874 var pass: i64 = 0
875
876 // T1: EB FE only -- HOLDS, framebuffer untouched (zero) -> not painted
877 var mem: *u8 = sys_mmap(MEMSZ)
878 var o: i64 = 0x1000
879 o = st_w(mem, o, 0xEB); o = st_w(mem, o, 0xFE)
880 var r: i64 = emu_run(mem, 0x1000, out, 0)
881 var c: i64 = 0
882 if r == (0 - 90) { fb_measure(mem, 0x2000, 0x400, mm); if mm[0] == 0 { c = 1 } }
883 if c == 1 { pass = pass + 1; e_p("EMU-T1 hold-unpainted GREEN\n" as *u8) } else { e_p("EMU-T1 RED\n" as *u8) }
884
885 // T2: mov rdi/rcx/eax + cld + rep stosd + hold -> painted 256/256, color as written
886 mem = sys_mmap(MEMSZ)
887 o = 0x1000
888 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC7); o = st_i32(mem, o, 0x2000)
889 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC1); o = st_i32(mem, o, 0x100)
890 o = st_w(mem, o, 0xB8); o = st_i32(mem, o, 0x00AA8844)
891 o = st_w(mem, o, 0xFC)
892 o = st_w(mem, o, 0xF3); o = st_w(mem, o, 0xAB)
893 o = st_w(mem, o, 0xEB); o = st_w(mem, o, 0xFE)
894 r = emu_run(mem, 0x1000, out, 0)
895 c = 0
896 if r == (0 - 90) {
897 fb_measure(mem, 0x2000, 0x400, mm)
898 if mm[0] == 0x00AA8844 { if mm[1] == 256 { if mm[2] == 256 { c = 1 } } }
899 }
900 if c == 1 { pass = pass + 1; e_p("EMU-T2 painted-and-holding GREEN\n" as *u8) } else { e_p("EMU-T2 RED\n" as *u8) }
901
902 // T3: same but only half the dwords -> 128/256, must NOT be full
903 mem = sys_mmap(MEMSZ)
904 o = 0x1000
905 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC7); o = st_i32(mem, o, 0x2000)
906 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC1); o = st_i32(mem, o, 0x80)
907 o = st_w(mem, o, 0xB8); o = st_i32(mem, o, 0x00AA8844)
908 o = st_w(mem, o, 0xFC)
909 o = st_w(mem, o, 0xF3); o = st_w(mem, o, 0xAB)
910 o = st_w(mem, o, 0xEB); o = st_w(mem, o, 0xFE)
911 r = emu_run(mem, 0x1000, out, 0)
912 c = 0
913 if r == (0 - 90) { fb_measure(mem, 0x2000, 0x400, mm); if mm[1] == 128 { if mm[2] == 256 { c = 1 } } }
914 if c == 1 { pass = pass + 1; e_p("EMU-T3 partial-refused GREEN\n" as *u8) } else { e_p("EMU-T3 RED\n" as *u8) }
915
916 // T4: LocateProtocol with a WRONG (all-zero) GUID -> refused with -33
917 mem = sys_mmap(MEMSZ)
918 o = 0x1000
919 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC0); o = st_i32(mem, o, HOOK3)
920 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC1); o = st_i32(mem, o, 0x3000)
921 o = st_w(mem, o, 0xFF); o = st_w(mem, o, 0xD0)
922 r = emu_run(mem, 0x1000, out, 0)
923 if r == (0 - 33) { pass = pass + 1; e_p("EMU-T4 guid-refused GREEN\n" as *u8) } else { e_p("EMU-T4 RED\n" as *u8) }
924
925 // T5: five distinct bands covering the whole region -> SCENE verdict (2), not uniform, not red
926 mem = sys_mmap(MEMSZ)
927 o = 0x1000
928 o = st_w(mem, o, 0xFC)
929 var bi: i64 = 0
930 while bi < 5 {
931 var bcnt: i64 = 51
932 if bi == 4 { bcnt = 52 }
933 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC7); o = st_i32(mem, o, 0x2000 + bi * 204)
934 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC1); o = st_i32(mem, o, bcnt)
935 o = st_w(mem, o, 0xB8); o = st_i32(mem, o, 0x11111111 * (bi + 1))
936 o = st_w(mem, o, 0xF3); o = st_w(mem, o, 0xAB)
937 bi = bi + 1
938 }
939 o = st_w(mem, o, 0xEB); o = st_w(mem, o, 0xFE)
940 r = emu_run(mem, 0x1000, out, 0)
941 c = 0
942 if r == (0 - 90) {
943 fb_measure(mem, 0x2000, 0x400, mm)
944 if hold_verdict(mm[0], mm[1], mm[2], mm[3], mm[4]) == 2 { c = 1 }
945 }
946 if c == 1 { pass = pass + 1; e_p("EMU-T5 scene-verdict GREEN\n" as *u8) } else { e_p("EMU-T5 RED\n" as *u8) }
947
948 // T6: full-region fill EXCEPT one zero dword -> a hole means NOT painted (verdict 0)
949 mem = sys_mmap(MEMSZ)
950 o = 0x1000
951 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC7); o = st_i32(mem, o, 0x2000)
952 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC1); o = st_i32(mem, o, 255)
953 o = st_w(mem, o, 0xB8); o = st_i32(mem, o, 0x66666666)
954 o = st_w(mem, o, 0xFC)
955 o = st_w(mem, o, 0xF3); o = st_w(mem, o, 0xAB)
956 o = st_w(mem, o, 0xEB); o = st_w(mem, o, 0xFE)
957 r = emu_run(mem, 0x1000, out, 0)
958 c = 0
959 if r == (0 - 90) {
960 fb_measure(mem, 0x2000, 0x400, mm)
961 if hold_verdict(mm[0], mm[1], mm[2], mm[3], mm[4]) == 0 { c = 1 }
962 }
963 if c == 1 { pass = pass + 1; e_p("EMU-T6 hole-refused GREEN\n" as *u8) } else { e_p("EMU-T6 RED\n" as *u8) }
964
965 // T7: the ConIn hook DRAINS a scripted queue exactly once per key and then reports NOT-READY.
966 // Queue of 2; the program reads 3 times -> 2 successes then a refusal, and rax proves which.
967 mem = sys_mmap(MEMSZ)
968 m_w64(mem, CI_ADDR + 0x08, HOOK4)
969 m_w64(mem, KEYQ_ADDR, 2)
970 m_w64(mem, KEYQ_ADDR + 8, 0)
971 m_w64(mem, KEYQ_ADDR + 16 + 8, 65) // 'A'
972 m_w64(mem, KEYQ_ADDR + 32 + 8, 66) // 'B'
973 o = 0x1000
974 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC1); o = st_i32(mem, o, CI_ADDR)
975 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0xC7); o = st_w(mem, o, 0xC2); o = st_i32(mem, o, 0x3000)
976 var kk: i64 = 0
977 while kk < 3 { // 3 reads against a 2-key queue
978 o = st_w(mem, o, 0x48); o = st_w(mem, o, 0x8B); o = st_w(mem, o, 0x41); o = st_w(mem, o, 0x08)
979 o = st_w(mem, o, 0xFF); o = st_w(mem, o, 0xD0)
980 kk = kk + 1
981 }
982 o = st_w(mem, o, 0xEB); o = st_w(mem, o, 0xFE)
983 r = emu_run(mem, 0x1000, out, 0)
984 c = 0
985 if r == (0 - 90) {
986 if m_r64(mem, KEYQ_ADDR + 8) == 2 { // exactly 2 drained, never 3
987 if (mem[0x3002] as i64) == 66 { c = 1 } // the LAST delivered key was 'B'
988 }
989 }
990 if c == 1 { pass = pass + 1; e_p("EMU-T7 conin-drain GREEN\n" as *u8) } else { e_p("EMU-T7 RED\n" as *u8) }
991
992 // T8: the N1-full file chain end to end THROUGH THE SAME emu_hook_call the interpreter uses,
993 // plus its refusals. A hook nobody has exercised is not a hook.
994 mem = sys_mmap(MEMSZ)
995 m_w64(mem, LI_ADDR + 0x18, DEV_HANDLE)
996 m_w64(mem, KFILE_LEN, 8)
997 var gi2: i64 = 0
998 while gi2 < 16 { mem[0x3000 + gi2] = li_guid_b(gi2) as u8; mem[0x3100 + gi2] = fs_guid_b(gi2) as u8; gi2 = gi2 + 1 }
999 var kb2: i64 = 0
1000 while kb2 < 8 { mem[KFILE_DATA + kb2] = (0x41 + kb2) as u8; kb2 = kb2 + 1 }
1001 let rg: *i64 = sys_mmap(8 * 16) as *i64
1002 var c8: i64 = 1
1003 rg[R_RCX] = 0x1234; rg[R_RDX] = 0x3000; rg[8] = 0x3200
1004 if emu_hook_call(mem, HOOK6, rg) != 0 { c8 = 0 }
1005 if m_r64(mem, 0x3200) != LI_ADDR { c8 = 0 }
1006 rg[R_RCX] = m_r64(mem, LI_ADDR + 0x18); rg[R_RDX] = 0x3100; rg[8] = 0x3208
1007 if emu_hook_call(mem, HOOK6, rg) != 0 { c8 = 0 }
1008 if m_r64(mem, 0x3208) != FS_ADDR { c8 = 0 }
1009 rg[R_RCX] = 0xDEAD; rg[R_RDX] = 0x3100; rg[8] = 0x3210
1010 if emu_hook_call(mem, HOOK6, rg) != (0 - 39) { c8 = 0 }
1011 rg[R_RCX] = FS_ADDR; rg[R_RDX] = 0x3218
1012 if emu_hook_call(mem, HOOK7, rg) != 0 { c8 = 0 }
1013 if m_r64(mem, 0x3218) != ROOT_ADDR { c8 = 0 }
1014 // Open() is NAME-AWARE now, so the test must present a real UTF-16LE name. The names are
1015 // RESTATED here as literals rather than read from esp_name_ch -- a test that borrows the
1016 // implementation's table cannot catch the implementation's typo.
1017 let knm: *u8 = "KERNEL.NXE" as *u8
1018 var ni: i64 = 0
1019 while knm[ni] != (0 as u8) { m_w16(mem, 0x3300 + ni * 2, knm[ni] as i64); ni = ni + 1 }
1020 m_w16(mem, 0x3300 + ni * 2, 0)
1021 let anm: *u8 = "NISHI.AI" as *u8
1022 var ai2: i64 = 0
1023 while anm[ai2] != (0 as u8) { m_w16(mem, 0x3340 + ai2 * 2, anm[ai2] as i64); ai2 = ai2 + 1 }
1024 m_w16(mem, 0x3340 + ai2 * 2, 0)
1025 let xnm: *u8 = "PASSWD.TXT" as *u8
1026 var xi: i64 = 0
1027 while xnm[xi] != (0 as u8) { m_w16(mem, 0x3380 + xi * 2, xnm[xi] as i64); xi = xi + 1 }
1028 m_w16(mem, 0x3380 + xi * 2, 0)
1029 rg[R_RCX] = ROOT_ADDR; rg[R_RDX] = 0x3220; rg[8] = 0x3300; rg[9] = 3
1030 if emu_hook_call(mem, HOOK8, rg) != (0 - 40) { c8 = 0 }
1031 rg[9] = 1
1032 if emu_hook_call(mem, HOOK8, rg) != 0 { c8 = 0 }
1033 if m_r64(mem, 0x3220) != FILE_ADDR { c8 = 0 }
1034 // NEG: a file this ESP does not serve is EFI_NOT_FOUND, never a silently-served handle.
1035 rg[R_RDX] = 0x3230; rg[8] = 0x3380
1036 m_w64(mem, 0x3230, 0)
1037 if emu_hook_call(mem, HOOK8, rg) != 0 { c8 = 0 }
1038 if rg[R_RAX] != EFI_NOT_FOUND { c8 = 0 }
1039 if m_r64(mem, 0x3230) != 0 { c8 = 0 }
1040 // The OPTIONAL assistant file: ABSENT (len 0) must be NOT_FOUND -- this is the DEFAULT state of
1041 // the toggle, and the state the loader must survive. Then present -> its own distinct handle.
1042 rg[R_RDX] = 0x3238; rg[8] = 0x3340
1043 m_w64(mem, 0x3238, 0)
1044 if emu_hook_call(mem, HOOK8, rg) != 0 { c8 = 0 }
1045 if rg[R_RAX] != EFI_NOT_FOUND { c8 = 0 }
1046 if m_r64(mem, 0x3238) != 0 { c8 = 0 }
1047 m_w64(mem, AIFILE_LEN, 4)
1048 var ab2: i64 = 0
1049 while ab2 < 4 { mem[AIFILE_DATA + ab2] = (0x61 + ab2) as u8; ab2 = ab2 + 1 }
1050 // FS-2: even WITH the file present, the BOOT volume must still refuse it -- the assistant file
1051 // lives on the DATA volume, and this is the check that makes "search every volume" testable.
1052 if emu_hook_call(mem, HOOK8, rg) != 0 { c8 = 0 }
1053 if rg[R_RAX] != EFI_NOT_FOUND { c8 = 0 }
1054 if m_r64(mem, 0x3238) != 0 { c8 = 0 }
1055 rg[R_RCX] = ROOT2_ADDR
1056 if emu_hook_call(mem, HOOK8, rg) != 0 { c8 = 0 }
1057 if m_r64(mem, 0x3238) != AIFILE_ADDR { c8 = 0 }
1058 // and the DATA volume must NOT serve the kernel: one file, one home.
1059 rg[R_RDX] = 0x3248; rg[8] = 0x3300
1060 m_w64(mem, 0x3248, 0)
1061 if emu_hook_call(mem, HOOK8, rg) != 0 { c8 = 0 }
1062 if rg[R_RAX] != EFI_NOT_FOUND { c8 = 0 }
1063 // LocateHandleBuffer hands back BOTH device handles, by protocol, with a real count
1064 rg[R_RSP] = 0x7000
1065 m_w64(mem, 0x7020, 0x7100)
1066 rg[R_RCX] = 2; rg[R_RDX] = 0x3100; rg[8] = 0; rg[9] = 0x7108
1067 if emu_hook_call(mem, HOOK10, rg) != 0 { c8 = 0 }
1068 if m_r64(mem, 0x7108) != 2 { c8 = 0 }
1069 let hb: i64 = m_r64(mem, 0x7100)
1070 if m_r64(mem, hb) != DEV_HANDLE { c8 = 0 }
1071 if m_r64(mem, hb + 8) != DEV2_HANDLE { c8 = 0 }
1072 rg[R_RCX] = 1 // AllHandles must be REFUSED, not served
1073 if emu_hook_call(mem, HOOK10, rg) != (0 - 43) { c8 = 0 }
1074 rg[R_RCX] = ROOT_ADDR
1075 // and its Read serves the AI bytes, NOT the kernel's
1076 m_w64(mem, 0x3240, 64)
1077 rg[R_RCX] = AIFILE_ADDR; rg[R_RDX] = 0x3240; rg[8] = 0x3500
1078 if emu_hook_call(mem, HOOK9, rg) != 0 { c8 = 0 }
1079 if m_r64(mem, 0x3240) != 4 { c8 = 0 }
1080 var ax2: i64 = 0
1081 while ax2 < 4 { if (mem[0x3500 + ax2] as i64) != (0x61 + ax2) { c8 = 0 } ax2 = ax2 + 1 }
1082 m_w64(mem, AIFILE_LEN, 0)
1083 rg[R_RCX] = ROOT_ADDR; rg[R_RDX] = 0x3220; rg[8] = 0x3300; rg[9] = 1
1084 if emu_hook_call(mem, HOOK8, rg) != 0 { c8 = 0 }
1085 m_w64(mem, 0x3228, 64)
1086 rg[R_RCX] = FILE_ADDR; rg[R_RDX] = 0x3228; rg[8] = 0x3400
1087 if emu_hook_call(mem, HOOK9, rg) != 0 { c8 = 0 }
1088 if m_r64(mem, 0x3228) != 8 { c8 = 0 }
1089 var rb2: i64 = 0
1090 while rb2 < 8 { if (mem[0x3400 + rb2] as i64) != (0x41 + rb2) { c8 = 0 } rb2 = rb2 + 1 }
1091 if c8 == 1 { pass = pass + 1; e_p("EMU-T8 esp-file-chain GREEN
1092" as *u8) } else { e_p("EMU-T8 RED
1093" as *u8) }
1094
1095 let lf: i64 = sys_openat_append("knowledge/status/nishi_os.log" as *u8, 0x1a4)
1096 if lf >= 0 {
1097 e_fp(lf, "NOSEMU selftest teeth=" as *u8); e_fn(lf, pass); e_fp(lf, "of8 verdict=" as *u8)
1098 if pass == 8 { e_fp(lf, "GREEN\n" as *u8) } else { e_fp(lf, "RED\n" as *u8) }
1099 sys_close(lf)
1100 }
1101 if pass == 8 {
1102 e_p("EMU-SELFTEST GREEN 8/8\n" as *u8)
1103 sys_exit(0); return 0
1104 }
1105 e_p("EMU-SELFTEST RED\n" as *u8)
1106 sys_exit(1); return 1
1107}
1108
1109func main(argc: i64, argv: *i64) -> i64 {
1110 var path: *u8 = "_offc/nx_boot_uefi.efi" as *u8
1111 if argc >= 2 { path = argv[1] as *u8 }
1112 if argc >= 2 { if s_eq(path, "selftest" as *u8) == 1 { return emu_selftest() } }
1113
1114 // load the .efi
1115 let lenp: *i64 = sys_mmap(16) as *i64
1116 let fb: *u8 = sys_read_file(path, lenp)
1117 let flen: i64 = lenp[0]
1118 if flen <= 0 { e_p("NOS-EXEC REFUSED: cannot read " as *u8); e_p(path); e_p("\n" as *u8); sys_exit(2); return 2 }
1119
1120 // parse the PE: entry RVA + first section (.text) load
1121 let entry: i64 = f_u32(fb, 0x98 + 16)
1122 let vaddr: i64 = f_u32(fb, 0x188 + 12)
1123 let rawsz: i64 = f_u32(fb, 0x188 + 16)
1124 let rawptr: i64 = f_u32(fb, 0x188 + 20)
1125
1126 let mem: *u8 = sys_mmap(MEMSZ)
1127 var i: i64 = 0
1128 while i < rawsz { mem[vaddr + i] = fb[rawptr + i]; i = i + 1 }
1129
1130 // mock UEFI: SystemTable + ConOut + FirmwareVendor string, OutputString = HOOK sentinel
1131 m_w64(mem, ST_ADDR + 0x18, FV_ADDR) // SystemTable->FirmwareVendor
1132 m_w64(mem, ST_ADDR + 0x40, CO_ADDR) // SystemTable->ConOut
1133 m_w64(mem, CO_ADDR + 0x08, HOOK) // ConOut->OutputString
1134 m_w64(mem, ST_ADDR + 0x30, CI_ADDR) // SystemTable->ConIn
1135 m_w64(mem, CI_ADDR + 0x08, HOOK4) // ConIn->ReadKeyStroke (hook, scripted queue)
1136 m_w64(mem, ST_ADDR + 0x60, BS_ADDR) // SystemTable->BootServices
1137 m_w64(mem, BS_ADDR + 0x38, HOOK2) // BootServices->GetMemoryMap (hook)
1138 m_w64(mem, BS_ADDR + 0xE8, HOOK5) // BootServices->ExitBootServices (UEFI spec offset)
1139 m_w64(mem, BS_ADDR + 0x98, HOOK6) // BootServices->HandleProtocol
1140 m_w64(mem, BS_ADDR + 0x138, HOOK10) // BootServices->LocateHandleBuffer (FS-2 volume search)
1141 m_w64(mem, FS2_ADDR + 0x08, HOOK7) // the DATA volume's OpenVolume
1142 m_w64(mem, ROOT2_ADDR + 0x08, HOOK8) // its root Open
1143 m_w64(mem, LI_ADDR + 0x18, DEV_HANDLE) // LoadedImage->DeviceHandle (the ESP we booted from)
1144 m_w64(mem, FS_ADDR + 0x08, HOOK7) // SimpleFileSystem->OpenVolume
1145 m_w64(mem, ROOT_ADDR + 0x08, HOOK8) // EFI_FILE->Open
1146 m_w64(mem, FILE_ADDR + 0x20, HOOK9) // EFI_FILE->Read
1147 m_w64(mem, AIFILE_ADDR + 0x20, HOOK9) // the OPTIONAL assistant file needs its OWN Read slot.
1148 // Omitting it made [rcx+0x20] read 0 and the loader
1149 // `call rax` jumped to address 0 -- the emulator refused
1150 // with EMU-UNDECODED at pc=0 rather than pretending.
1151 // A SECOND HANDLE IS A SECOND VTABLE, NOT A SECOND NAME.
1152 m_w64(mem, BS_ADDR + 0x140, HOOK3) // BootServices->LocateProtocol (hook, GUID-checked)
1153 m_w64(mem, GOP_ADDR + 0x18, MODE_ADDR) // gop->Mode
1154 m_w64(mem, MODE_ADDR + 0x18, FB_ADDR) // Mode->FrameBufferBase (a real in-MEM framebuffer)
1155 m_w64(mem, MODE_ADDR + 0x20, FB_SIZE) // Mode->FrameBufferSize = 1280x800x4 (mirrors the OVMF oracle mode)
1156 // FirmwareVendor = UTF-16 "NISHI-FW"
1157 m_w16(mem, FV_ADDR + 0, 0x4E); m_w16(mem, FV_ADDR + 2, 0x49); m_w16(mem, FV_ADDR + 4, 0x53)
1158 m_w16(mem, FV_ADDR + 6, 0x48); m_w16(mem, FV_ADDR + 8, 0x49); m_w16(mem, FV_ADDR + 10, 0x2D)
1159 m_w16(mem, FV_ADDR + 12, 0x46); m_w16(mem, FV_ADDR + 14, 0x57); m_w16(mem, FV_ADDR + 16, 0x00)
1160
1161 // scripted keyboard: nx_emu_uefi <img> --keys <ascii-string> (each char = one ReadKeyStroke
1162 // SUCCESS in order; the queue then reports NOT-READY forever, exactly like idle firmware)
1163 var nkeys: i64 = 0
1164 if argc >= 4 {
1165 if s_eq(argv[2] as *u8, "--keys" as *u8) == 1 {
1166 let ks: *u8 = argv[3] as *u8
1167 while ks[nkeys] != (0 as u8) {
1168 m_w64(mem, KEYQ_ADDR + 16 + nkeys * 16, 0) // ScanCode 0 = a unicode key
1169 m_w64(mem, KEYQ_ADDR + 16 + nkeys * 16 + 8, ks[nkeys] as i64)
1170 nkeys = nkeys + 1
1171 }
1172 m_w64(mem, KEYQ_ADDR, nkeys)
1173 m_w64(mem, KEYQ_ADDR + 8, 0)
1174 var pk: i64 = 0
1175 while pk < nkeys {
1176 m_w64(mem, PS2_STATE + 16 + pk * 8, ks[pk] as i64)
1177 pk = pk + 1
1178 }
1179 m_w64(mem, PS2_STATE, nkeys)
1180 m_w64(mem, PS2_STATE + 8, 0)
1181 }
1182 }
1183
1184 // N1-full: --kernel <file> makes the modeled ESP serve REAL bytes -- a harness that invents
1185 // file contents proves nothing. Scanned at ANY argv position (the --keys positional trap is
1186 // not being extended to a second flag). Without --kernel the served length is 0, Read hands
1187 // back nothing, and the shim's magic check takes its NXE! refusal path -- so the missing-file
1188 // negative control costs nothing to run.
1189 var ka: i64 = 2
1190 while (ka + 1) < argc {
1191 if s_eq(argv[ka] as *u8, "--aifile" as *u8) == 1 {
1192 let alp: *i64 = sys_mmap(16) as *i64
1193 let ab: *u8 = sys_read_file(argv[ka + 1] as *u8, alp)
1194 let alen: i64 = alp[0]
1195 if alen <= 0 { e_p("NOS-EXEC REFUSED: cannot read --aifile\n" as *u8); sys_exit(2); return 2 }
1196 if alen > 0x100000 { e_p("NOS-EXEC REFUSED: --aifile exceeds the modeled window (0x100000)\n" as *u8); sys_exit(2); return 2 }
1197 var ac: i64 = 0
1198 while ac < alen { mem[AIFILE_DATA + ac] = ab[ac]; ac = ac + 1 }
1199 m_w64(mem, AIFILE_LEN, alen)
1200 }
1201 // --mmsize <bytes>: pin the modeled GetMemoryMap size. Real EDK2 returned 0x18F0 where this
1202 // organ models 0x1800 (debt 1786237098), so a rung that needs to assert a ram-map value must
1203 // be able to state the one it MEASURED rather than inherit ours. Decimal.
1204 if s_eq(argv[ka] as *u8, "--mmsize" as *u8) == 1 {
1205 let mmv: i64 = s_atoi(argv[ka + 1] as *u8)
1206 if mmv <= 0 { e_p("NOS-EXEC REFUSED: --mmsize must be a positive decimal byte count\n" as *u8); sys_exit(2); return 2 }
1207 m_w64(mem, MM_SIZE_SLOT, mmv)
1208 e_p("NOS-MMSIZE: modeled GetMemoryMap size PINNED to " as *u8); e_fn(1, mmv)
1209 e_p(" (default " as *u8); e_fn(1, MM_REQ_BYTES); e_p(" is a MODEL, not a measurement)\n" as *u8)
1210 }
1211 if s_eq(argv[ka] as *u8, "--kernel" as *u8) == 1 {
1212 let klp: *i64 = sys_mmap(16) as *i64
1213 let kb: *u8 = sys_read_file(argv[ka + 1] as *u8, klp)
1214 let klen: i64 = klp[0]
1215 if klen <= 0 { e_p("NOS-EXEC REFUSED: cannot read --kernel file\n" as *u8); sys_exit(2); return 2 }
1216 if klen > 0x60000 { e_p("NOS-EXEC REFUSED: --kernel exceeds the modeled ESP window (0x60000)\n" as *u8); sys_exit(2); return 2 }
1217 var kc: i64 = 0
1218 while kc < klen { mem[KFILE_DATA + kc] = kb[kc]; kc = kc + 1 }
1219 m_w64(mem, KFILE_LEN, klen)
1220 }
1221 ka = ka + 1
1222 }
1223
1224 let out: *u8 = sys_mmap(512)
1225 var tracen: i64 = 0
1226 if argc >= 3 { if s_eq(argv[2] as *u8, "--trace" as *u8) == 1 { tracen = 1 } }
1227 let outn: i64 = emu_run(mem, entry, out, tracen)
1228
1229 // -30 = the step cap. For an EVENT-LOOP kernel that is NOT an error: a live poll loop is what
1230 // an OS does. Judge it the same way as a hold -- by MEASURING the screen it owns.
1231 if outn == (0 - 90) { } else { if outn == (0 - 30) { } else { if outn < 0 {
1232 e_p("NOS-EXEC RED: interpreter sentinel " as *u8); e_fn(1, outn); e_p(" on " as *u8); e_p(path); e_p("\n" as *u8)
1233 let lf3: i64 = sys_openat_append("knowledge/status/nishi_os.log" as *u8, 0x1a4)
1234 if lf3 >= 0 { e_fp(lf3, "NOSEXEC name=" as *u8); e_fp(lf3, path); e_fp(lf3, " err=" as *u8); e_fn(lf3, outn); e_fp(lf3, " verdict=RED\n" as *u8); sys_close(lf3) }
1235 sys_exit(1); return 1
1236 } } }
1237
1238 if outn == (0 - 30) { // live event loop: measure, report keys consumed
1239 let fbb2: i64 = m_r64(mem, MODE_ADDR + 0x18)
1240 let fbs2: i64 = m_r64(mem, MODE_ADDR + 0x20)
1241 let m2: *i64 = sys_mmap(48) as *i64
1242 fb_measure(mem, fbb2, fbs2, m2)
1243 let drained: i64 = m_r64(mem, KEYQ_ADDR + 8)
1244 px_probe(mem, fbb2, argc, argv)
1245 let hv2: i64 = hold_verdict(m2[0], m2[1], m2[2], m2[3], m2[4])
1246 shot_if_asked(mem, fbb2, argc, argv)
1247 let ebs: i64 = m_r64(mem, EBS_STATE)
1248 e_p("NOS-EXEC: " as *u8); e_p(path); e_p(" RUNS an event loop; keys_consumed=" as *u8)
1249 e_fn(1, drained); e_p("/" as *u8); e_fn(1, nkeys); e_p(" zeros=" as *u8); e_fn(1, m2[3])
1250 e_p(" transitions=" as *u8); e_fn(1, m2[4])
1251 e_p(" firmware_exited=" as *u8); e_fn(1, ebs); e_p("\n" as *u8)
1252 // every scripted key must actually have been READ. Scripting NO keys is not a failure --
1253 // it proves the screen, just not the input; say exactly that instead of crying RED.
1254 var kok: i64 = 0
1255 if drained == nkeys { kok = 1 }
1256 let lf4: i64 = sys_openat_append("knowledge/status/nishi_os.log" as *u8, 0x1a4)
1257 if lf4 >= 0 {
1258 e_fp(lf4, "NOSRUN name=" as *u8); e_fp(lf4, path)
1259 e_fp(lf4, " executed=sovereign-x86-emu loop=1 keys_consumed=" as *u8); e_fn(lf4, drained)
1260 e_fp(lf4, " of=" as *u8); e_fn(lf4, nkeys)
1261 e_fp(lf4, " zeros=" as *u8); e_fn(lf4, m2[3])
1262 e_fp(lf4, " transitions=" as *u8); e_fn(lf4, m2[4])
1263 e_fp(lf4, " firmware_exited=" as *u8); e_fn(lf4, ebs)
1264 e_fp(lf4, " verdict=" as *u8)
1265 if hv2 > 0 { if kok == 1 { e_fp(lf4, "RUNNING-AND-PAINTED\n" as *u8) } else { e_fp(lf4, "RED\n" as *u8) } }
1266 else { e_fp(lf4, "RED\n" as *u8) }
1267 sys_close(lf4)
1268 }
1269 if hv2 > 0 { if kok == 1 {
1270 e_p("NOS-EXEC GREEN: RUNNING-AND-PAINTED -- the kernel owns the screen" as *u8)
1271 if nkeys > 0 { e_p(" AND consumed every scripted keystroke" as *u8) } else { e_p(" (no keys scripted: input not exercised)" as *u8) }
1272 e_p(" (sovereign, no qemu)\n" as *u8)
1273 sys_exit(0); return 0
1274 } }
1275 e_p("NOS-EXEC RED: event loop ran but the screen or the key trace did not check out\n" as *u8)
1276 sys_exit(1); return 1
1277 }
1278
1279 if outn == (0 - 90) { // EB FE: the app parks HOLDING the screen -- measure, don't error
1280 let fbbase: i64 = m_r64(mem, MODE_ADDR + 0x18)
1281 let fbsize: i64 = m_r64(mem, MODE_ADDR + 0x20)
1282 let mm: *i64 = sys_mmap(48) as *i64
1283 fb_measure(mem, fbbase, fbsize, mm)
1284 let color: i64 = mm[0]
1285 let matches: i64 = mm[1]
1286 let ndw: i64 = mm[2]
1287 let zeros: i64 = mm[3]
1288 let trans: i64 = mm[4]
1289 var permil: i64 = 0
1290 if ndw > 0 { permil = (matches * 1000) / ndw }
1291 px_probe(mem, fbbase, argc, argv)
1292 let hv: i64 = hold_verdict(color, matches, ndw, zeros, trans)
1293 shot_if_asked(mem, fbbase, argc, argv)
1294 e_p("NOS-EXEC: " as *u8); e_p(path); e_p(" HOLDS (EB FE); modeled-GOP fill " as *u8)
1295 e_fn(1, matches); e_p("/" as *u8); e_fn(1, ndw); e_p(" dwords " as *u8); e_fn(1, permil)
1296 e_p(" permil zeros=" as *u8); e_fn(1, zeros); e_p(" transitions=" as *u8); e_fn(1, trans)
1297 e_p(" firmware_exited=" as *u8); e_fn(1, m_r64(mem, EBS_STATE))
1298 e_p(" ps2_consumed=" as *u8); e_fn(1, m_r64(mem, PS2_STATE + 8))
1299 e_p("/" as *u8); e_fn(1, m_r64(mem, PS2_STATE))
1300 e_p(" color=0x" as *u8); e_fx(1, color); e_p("\n" as *u8)
1301 let lf2: i64 = sys_openat_append("knowledge/status/nishi_os.log" as *u8, 0x1a4)
1302 if lf2 >= 0 {
1303 e_fp(lf2, "NOSEXEC name=" as *u8); e_fp(lf2, path)
1304 e_fp(lf2, " executed=sovereign-x86-emu hold=1 fb_dwords=" as *u8); e_fn(lf2, ndw)
1305 e_fp(lf2, " match_dwords=" as *u8); e_fn(lf2, matches)
1306 e_fp(lf2, " fill_permil=" as *u8); e_fn(lf2, permil)
1307 e_fp(lf2, " zeros=" as *u8); e_fn(lf2, zeros)
1308 e_fp(lf2, " transitions=" as *u8); e_fn(lf2, trans)
1309 e_fp(lf2, " firmware_exited=" as *u8); e_fn(lf2, m_r64(mem, EBS_STATE))
1310 e_fp(lf2, " ps2_consumed=" as *u8); e_fn(lf2, m_r64(mem, PS2_STATE + 8))
1311 e_fp(lf2, " color=0x" as *u8); e_fx(lf2, color)
1312 e_fp(lf2, " verdict=" as *u8)
1313 if hv == 1 { e_fp(lf2, "PAINTED-AND-HOLDING\n" as *u8) }
1314 if hv == 2 { e_fp(lf2, "SCENE-PAINTED-AND-HOLDING\n" as *u8) }
1315 if hv == 0 { e_fp(lf2, "RED\n" as *u8) }
1316 sys_close(lf2)
1317 }
1318 if hv == 1 {
1319 e_p("NOS-EXEC GREEN: PAINTED-AND-HOLDING -- the app filled 100.0% of the modeled framebuffer and holds the screen (sovereign, no qemu)\n" as *u8)
1320 sys_exit(0); return 0
1321 }
1322 if hv == 2 {
1323 e_p("NOS-EXEC GREEN: SCENE-PAINTED-AND-HOLDING -- every pixel written, composed multi-color scene, screen held (sovereign, no qemu)\n" as *u8)
1324 sys_exit(0); return 0
1325 }
1326 e_p("NOS-EXEC RED: the app holds but the modeled framebuffer is not fully painted\n" as *u8)
1327 sys_exit(1); return 1
1328 }
1329
1330 if outn < 0 {
1331 e_p("NOS-EXEC RED: interpreter sentinel " as *u8); e_fn(1, outn); e_p(" on " as *u8); e_p(path); e_p("\n" as *u8)
1332 let lf: i64 = sys_openat_append("knowledge/status/nishi_os.log" as *u8, 0x1a4)
1333 if lf >= 0 { e_fp(lf, "NOSEXEC name=" as *u8); e_fp(lf, path); e_fp(lf, " err=" as *u8); e_fn(lf, outn); e_fp(lf, " verdict=RED\n" as *u8); sys_close(lf) }
1334 sys_exit(1); return 1
1335 }
1336
1337 // assert: captured console output begins with the expected prefix (default "NISHI",
1338 // override via argv[2] so the gate is reusable per rung -- exact match keeps its teeth)
1339 out[outn] = 0 as u8
1340 var exp: *u8 = "NISHI" as *u8
1341 if argc >= 3 { exp = argv[2] as *u8 }
1342 var ok: i64 = 1
1343 var j: i64 = 0
1344 while exp[j] != (0 as u8) {
1345 if j >= outn { ok = 0 } else { if out[j] != exp[j] { ok = 0 } }
1346 j = j + 1
1347 }
1348 if j == 0 { ok = 0 }
1349
1350 e_p("NOS-EXEC: " as *u8); e_p(path); e_p(" entry=0x" as *u8); e_fn(1, entry)
1351 e_p(" captured-console=[" as *u8); sys_write(1, out, outn); e_p("] chars=" as *u8); e_fn(1, outn); e_p("\n" as *u8)
1352
1353 let lf: i64 = sys_openat_append("knowledge/status/nishi_os.log" as *u8, 0x1a4)
1354 if lf >= 0 {
1355 e_fp(lf, "NOSEXEC name=" as *u8); e_fp(lf, path)
1356 e_fp(lf, " executed=sovereign-x86-emu console_chars=" as *u8); e_fn(lf, outn)
1357 e_fp(lf, " expect=" as *u8); e_fp(lf, exp); e_fp(lf, " verdict=" as *u8)
1358 if ok == 1 { e_fp(lf, "GREEN\n" as *u8) } else { e_fp(lf, "RED\n" as *u8) }
1359 sys_close(lf)
1360 }
1361
1362 if ok == 1 {
1363 e_p("NOS-EXEC GREEN: emitted .efi EXECUTES on the sovereign x86 emu and prints the expected output (boot-proof, no qemu/laptop)\n" as *u8)
1364 sys_exit(0); return 0
1365 }
1366 e_p("NOS-EXEC RED: console output did not begin with the expected prefix\n" as *u8)
1367 sys_exit(1); return 1
1368}