1use crate::cpu::{apic, cpu, global_pointers, ioapic, memory, pic};
2use crate::native_devices;
3use std::collections::VecDeque;
4use std::io::Write;
5use std::sync::{Mutex, OnceLock};
6use std::time::Instant;
7
8static START: OnceLock<Instant> = OnceLock::new();
9static UART0: OnceLock<Mutex<UartState>> = OnceLock::new();
10
11#[derive(Default)]
12struct UartState {
13 ints: u8,
14 baud_rate: u16,
15 line_control: u8,
16 lsr: u8,
17 fifo_control: u8,
18 ier: u8,
19 iir: u8,
20 modem_control: u8,
21 modem_status: u8,
22 scratch: u8,
23 irq: u8,
24 input: VecDeque<u8>,
25}
26
27fn uart0() -> &'static Mutex<UartState> {
28 UART0.get_or_init(|| Mutex::new(UartState::default()))
29}
30
31fn uart_read(port: i32) -> i32 {
32 let offset = (port - 0x3F8) as u8;
33 let mut uart = uart0().lock().expect("UART0 mutex poisoned");
34 match offset {
35 0 if uart.line_control & 0x80 != 0 => (uart.baud_rate & 0xFF) as i32,
36 0 => uart.input.pop_front().unwrap_or(0) as i32,
37 1 if uart.line_control & 0x80 != 0 => (uart.baud_rate >> 8) as i32,
38 1 => (uart.ier & 0x0F) as i32,
39 2 => {
40 let fifo = if uart.fifo_control & 1 != 0 { 0xC0 } else { 0 };
41 (uart.iir | fifo) as i32
42 }
43 3 => uart.line_control as i32,
44 4 => uart.modem_control as i32,
45 5 => (uart.lsr | if uart.input.is_empty() { 0 } else { 0x01 }) as i32,
46 6 => uart.modem_status as i32,
47 7 => uart.scratch as i32,
48 _ => 0xFF,
49 }
50}
51
52fn restore_uart_state(state: &[serde_json::Value]) -> Result<(), String> {
53 if state.len() < 11 {
54 return Err(format!(
55 "UART state has {} fields; expected 11",
56 state.len()
57 ));
58 }
59 let mut uart = uart0()
60 .lock()
61 .map_err(|_| "UART0 mutex poisoned".to_owned())?;
62 uart.ints = state[0]
63 .as_i64()
64 .ok_or_else(|| "UART ints is not an integer".to_owned())? as u8;
65 uart.baud_rate = state[1]
66 .as_i64()
67 .ok_or_else(|| "UART baud rate is not an integer".to_owned())? as u16;
68 uart.line_control = state[2]
69 .as_i64()
70 .ok_or_else(|| "UART line control is not an integer".to_owned())?
71 as u8;
72 uart.lsr = state[3]
73 .as_i64()
74 .ok_or_else(|| "UART LSR is not an integer".to_owned())? as u8;
75 uart.fifo_control = state[4]
76 .as_i64()
77 .ok_or_else(|| "UART FIFO control is not an integer".to_owned())?
78 as u8;
79 uart.ier = state[5]
80 .as_i64()
81 .ok_or_else(|| "UART IER is not an integer".to_owned())? as u8;
82 uart.iir = state[6]
83 .as_i64()
84 .ok_or_else(|| "UART IIR is not an integer".to_owned())? as u8;
85 uart.modem_control = state[7]
86 .as_i64()
87 .ok_or_else(|| "UART modem control is not an integer".to_owned())?
88 as u8;
89 uart.modem_status = state[8]
90 .as_i64()
91 .ok_or_else(|| "UART modem status is not an integer".to_owned())?
92 as u8;
93 uart.scratch = state[9]
94 .as_i64()
95 .ok_or_else(|| "UART scratch is not an integer".to_owned())? as u8;
96 uart.irq = state[10]
97 .as_i64()
98 .ok_or_else(|| "UART IRQ is not an integer".to_owned())? as u8;
99 Ok(())
100}
101
102fn uart_write(port: i32, value: i32) {
103 let offset = (port - 0x3F8) as u8;
104 let byte = value as u8;
105 let mut output = None;
106 {
107 let mut uart = uart0().lock().expect("UART0 mutex poisoned");
108 match offset {
109 0 if uart.line_control & 0x80 != 0 => {
110 uart.baud_rate = (uart.baud_rate & 0xFF00) | byte as u16;
111 }
112 0 => output = Some(byte),
113 1 if uart.line_control & 0x80 != 0 => {
114 uart.baud_rate = (uart.baud_rate & 0x00FF) | ((byte as u16) << 8);
115 }
116 1 => uart.ier = byte & 0x0F,
117 2 => uart.fifo_control = byte,
118 3 => uart.line_control = byte,
119 4 => uart.modem_control = byte,
120 7 => uart.scratch = byte,
121 _ => {}
122 }
123 }
124 if let Some(byte) = output {
125 let mut stdout = std::io::stdout().lock();
126 let _ = stdout.write_all(&[byte]);
127 let _ = stdout.flush();
128 }
129}
130
131#[no_mangle]
135pub extern "C" fn cpu_exception_hook(_interrupt: i32) -> bool {
136 false
137}
138
139#[no_mangle]
140pub extern "C" fn microtick() -> f64 {
141 START.get_or_init(Instant::now).elapsed().as_secs_f64() * 1000.0
142}
143
144#[no_mangle]
145pub extern "C" fn run_hardware_timers(_acpi_enabled: bool, _now: f64) -> f64 {
146 0.0
147}
148
149#[no_mangle]
150pub extern "C" fn cpu_event_halt() {}
151
152#[no_mangle]
153pub extern "C" fn stop_idling() {}
154
155#[no_mangle]
156pub extern "C" fn get_rand_int() -> i32 {
157 0x1357_9BDF
158}
159
160#[no_mangle]
161pub extern "C" fn io_port_read8(port: i32) -> i32 {
162 if let Some(value) = native_devices::io_read8(port) {
163 value
164 } else if (0x3F8..=0x3FF).contains(&port) {
165 uart_read(port)
166 } else {
167 0xFF
168 }
169}
170
171#[no_mangle]
172pub extern "C" fn io_port_read16(port: i32) -> i32 {
173 native_devices::io_read16(port).unwrap_or(0xFFFF)
174}
175
176#[no_mangle]
177pub extern "C" fn io_port_read32(port: i32) -> i32 {
178 native_devices::io_read32(port).unwrap_or(-1)
179}
180
181#[no_mangle]
182pub extern "C" fn io_port_write8(port: i32, value: i32) {
183 if !native_devices::io_write8(port, value) && (0x3F8..=0x3FF).contains(&port) {
184 uart_write(port, value);
185 }
186}
187
188#[no_mangle]
189pub extern "C" fn io_port_write16(port: i32, value: i32) {
190 if !native_devices::io_write16(port, value) {}
191}
192
193#[no_mangle]
194pub extern "C" fn io_port_write32(port: i32, value: i32) {
195 if !native_devices::io_write32(port, value) {}
196}
197
198#[no_mangle]
199pub extern "C" fn mmap_read8(addr: u32) -> i32 {
200 native_devices::mmio_read8(addr).unwrap_or(0xFF)
201}
202
203#[no_mangle]
204pub extern "C" fn mmap_read32(addr: u32) -> i32 {
205 native_devices::mmio_read32(addr).unwrap_or(-1)
206}
207
208#[no_mangle]
209pub extern "C" fn mmap_write8(addr: u32, value: i32) {
210 let _ = native_devices::mmio_write8(addr, value);
211}
212
213#[no_mangle]
214pub extern "C" fn mmap_write16(addr: u32, value: i32) {
215 let _ = native_devices::mmio_write16(addr, value);
216}
217
218#[no_mangle]
219pub extern "C" fn mmap_write32(addr: u32, value: i32) {
220 let _ = native_devices::mmio_write32(addr, value);
221}
222
223#[no_mangle]
224pub extern "C" fn mmap_write64(_addr: u32, _v0: i32, _v1: i32) {}
225
226#[no_mangle]
227pub extern "C" fn mmap_write128(_addr: u32, _v0: i32, _v1: i32, _v2: i32, _v3: i32) {}
228
229pub struct NativeCpu {
235 state_arena: Box<[u8; 4096]>,
236 ram_bytes: u32,
237 vga_bytes: u32,
238 last_timer_tick: Instant,
239}
240
241impl NativeCpu {
242 pub fn new(ram_bytes: u32, vga_bytes: u32) -> Self {
243 assert!(ram_bytes > 0, "RAM size must be non-zero");
244 assert!(vga_bytes > 0, "VGA memory size must be non-zero");
245
246 let mut state_arena = Box::new([0u8; 4096]);
247 unsafe {
248 global_pointers::init(state_arena.as_mut_ptr());
249 let _ = memory::allocate_memory(ram_bytes);
250 let _ = memory::svga_allocate_memory(vga_bytes);
251 *global_pointers::memory_size = ram_bytes;
252 memory::vga_memory_size = vga_bytes;
253 cpu::reset_cpu();
254 }
255
256 Self {
257 state_arena,
258 ram_bytes,
259 vga_bytes,
260 last_timer_tick: Instant::now(),
261 }
262 }
263
264 pub fn ram_bytes(&self) -> u32 {
265 self.ram_bytes
266 }
267
268 pub fn vga_bytes(&self) -> u32 {
269 self.vga_bytes
270 }
271
272 pub fn step(&mut self, max_instructions: u32) -> u32 {
273 unsafe {
274 let halted = *global_pointers::in_hlt;
275 let timer_due = self.last_timer_tick.elapsed() >= std::time::Duration::from_millis(1);
276 if halted || timer_due {
277 let now = microtick();
278 if *global_pointers::acpi_enabled {
279 let _ = apic::apic_timer(now);
280 cpu::handle_irqs();
281 } else {
282 pic::set_irq(0);
283 cpu::handle_irqs();
284 pic::clear_irq(0);
285 cpu::handle_irqs();
286 }
287 self.last_timer_tick = Instant::now();
288 }
289 cpu::main_loop_native_interpreter(max_instructions)
290 }
291 }
292
293 pub fn read_memory(&self, address: u32, output: &mut [u8]) -> bool {
294 if address.checked_add(output.len() as u32).is_none()
295 || address + output.len() as u32 > self.ram_bytes
296 {
297 return false;
298 }
299 unsafe {
300 output.copy_from_slice(std::slice::from_raw_parts(
301 memory::mem8.add(address as usize),
302 output.len(),
303 ));
304 }
305 true
306 }
307
308 pub fn write_memory(&mut self, address: u32, input: &[u8]) -> bool {
309 if address.checked_add(input.len() as u32).is_none()
310 || address + input.len() as u32 > self.ram_bytes
311 {
312 return false;
313 }
314 unsafe {
315 std::slice::from_raw_parts_mut(memory::mem8.add(address as usize), input.len())
316 .copy_from_slice(input);
317 }
318 true
319 }
320
321 pub fn instruction_pointer(&self) -> u32 {
322 unsafe { *global_pointers::instruction_pointer as u32 }
323 }
324
325 pub fn halted(&self) -> bool {
326 unsafe { *global_pointers::in_hlt }
327 }
328
329 pub fn state_arena(&self) -> &[u8; 4096] {
330 &self.state_arena
331 }
332
333 pub fn set_9p_root(&mut self, path: impl AsRef<std::path::Path>) -> Result<(), String> {
334 native_devices::set_9p_root(path)
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use super::NativeCpu;
341
342 #[test]
343 fn native_interpreter_executes_reset_vector_hlt() {
344 let mut cpu = NativeCpu::new(128 * 1024 * 1024, 8 * 1024 * 1024);
345 assert!(cpu.write_memory(0xFFFF0, &[0xF4]));
346 assert_eq!(cpu.instruction_pointer(), 0xFFFF0);
347 assert_eq!(cpu.step(1), 1);
348 assert!(cpu.halted());
349 }
350}
351
352impl NativeCpu {
353 pub fn restore_v86_state(
358 &mut self,
359 state: &serde_json::Value,
360 buffers: &[Vec<u8>],
361 ) -> Result<(), String> {
362 let slots = state
363 .as_array()
364 .ok_or_else(|| "v86 state is not an array".to_owned())?;
365
366 let memory_size = scalar(slots, 0)? as u32;
367 if memory_size != self.ram_bytes {
368 return Err(format!(
369 "state RAM is {memory_size} bytes, NativeCpu has {} bytes",
370 self.ram_bytes
371 ));
372 }
373
374 let segment_state = buffer_for(slots, buffers, 1)?;
375 if segment_state.len() != 16 {
376 return Err(format!(
377 "state[1] length {} != expected 16",
378 segment_state.len()
379 ));
380 }
381 unsafe {
382 std::slice::from_raw_parts_mut(global_pointers::segment_is_null as *mut u8, 8)
383 .copy_from_slice(&segment_state[..8]);
384 std::slice::from_raw_parts_mut(global_pointers::segment_access_bytes, 8)
385 .copy_from_slice(&segment_state[8..]);
386 }
387 copy_i32_buffer(slots, buffers, 2, unsafe {
388 std::slice::from_raw_parts_mut(global_pointers::segment_offsets as *mut u8, 32)
389 })?;
390 copy_u32_buffer(slots, buffers, 3, unsafe {
391 std::slice::from_raw_parts_mut(global_pointers::segment_limits as *mut u8, 32)
392 })?;
393
394 unsafe {
395 *global_pointers::memory_size = memory_size;
396 *global_pointers::protected_mode = scalar(slots, 4)? != 0;
397 *global_pointers::idtr_offset = scalar(slots, 5)? as i32;
398 *global_pointers::idtr_size = scalar(slots, 6)? as i32;
399 *global_pointers::gdtr_offset = scalar(slots, 7)? as i32;
400 *global_pointers::gdtr_size = scalar(slots, 8)? as i32;
401 }
402 copy_i32_buffer(slots, buffers, 10, unsafe {
403 std::slice::from_raw_parts_mut(global_pointers::cr as *mut u8, 32)
404 })?;
405 unsafe {
406 *global_pointers::cpl = scalar(slots, 11)? as u8;
407 *global_pointers::is_32 = scalar(slots, 13)? != 0;
408 *global_pointers::stack_size_32 = scalar(slots, 16)? != 0;
409 *global_pointers::in_hlt = scalar(slots, 17)? != 0;
410 *global_pointers::last_virt_eip = scalar(slots, 18)? as i32;
411 *global_pointers::eip_phys = scalar(slots, 19)? as i32;
412 *global_pointers::sysenter_cs = scalar(slots, 22)? as i32;
413 *global_pointers::sysenter_eip = scalar(slots, 23)? as i32;
414 *global_pointers::sysenter_esp = scalar(slots, 24)? as i32;
415 *global_pointers::prefixes = scalar(slots, 25)? as u8;
416 *global_pointers::flags = scalar(slots, 26)? as i32;
417 *global_pointers::flags_changed = scalar(slots, 27)? as i32;
418 *global_pointers::last_op1 = scalar(slots, 28)? as i32;
419 *global_pointers::last_op_size = scalar(slots, 30)? as i32;
420 *global_pointers::instruction_pointer = scalar(slots, 37)? as i32;
421 *global_pointers::previous_ip = scalar(slots, 38)? as i32;
422 }
423 copy_i32_buffer(slots, buffers, 39, unsafe {
424 std::slice::from_raw_parts_mut(global_pointers::reg32 as *mut u8, 32)
425 })?;
426 copy_u16_buffer(slots, buffers, 40, unsafe {
427 std::slice::from_raw_parts_mut(global_pointers::sreg as *mut u8, 16)
428 })?;
429 copy_i32_buffer(slots, buffers, 41, unsafe {
430 std::slice::from_raw_parts_mut(global_pointers::dreg as *mut u8, 32)
431 })?;
432 copy_u64_buffer(slots, buffers, 42, unsafe {
433 std::slice::from_raw_parts_mut(global_pointers::reg_pdpte as *mut u8, 32)
434 })?;
435
436 let tsc = buffer_for(slots, buffers, 43)?;
437 if tsc.len() >= 8 {
438 let low = u32::from_le_bytes(tsc[0..4].try_into().unwrap());
439 let high = u32::from_le_bytes(tsc[4..8].try_into().unwrap());
440 unsafe {
441 cpu::set_tsc(low, high);
442 }
443 }
444
445 if let Some(uart_state) = slots.get(54).and_then(serde_json::Value::as_array) {
446 restore_uart_state(uart_state)?;
447 }
448 if let Some(pic_state) = slots.get(60).and_then(serde_json::Value::as_array) {
449 let master = byte_array_from_state(pic_state, 13, "PIC master")?;
450 let slave_value = pic_state
451 .get(5)
452 .ok_or_else(|| "PIC state has no slave controller".to_owned())?;
453 let slave_array = slave_value
454 .as_array()
455 .ok_or_else(|| "PIC slave state is not an array".to_owned())?;
456 let slave = byte_array_from_values(slave_array, 13, "PIC slave")?;
457 pic::restore_state(&master, &slave);
458 }
459
460 if slots.get(46).is_some_and(|value| !value.is_null()) {
461 let apic_state = buffer_for(slots, buffers, 46)?;
462 apic::restore_state_bytes(apic_state)?;
463 unsafe {
464 *global_pointers::apic_enabled = true;
465 *global_pointers::acpi_enabled = true;
466 }
467 }
468 if slots.get(63).is_some_and(|value| !value.is_null()) {
469 let ioapic_state = buffer_for(slots, buffers, 63)?;
470 ioapic::restore_state_bytes(ioapic_state)?;
471 }
472
473 unsafe {
474 *global_pointers::tss_size_32 = scalar(slots, 64)? != 0;
475 }
476 copy_buffer(slots, buffers, 66, unsafe {
477 std::slice::from_raw_parts_mut(global_pointers::reg_xmm as *mut u8, 128)
478 })?;
479 copy_buffer(slots, buffers, 67, unsafe {
480 std::slice::from_raw_parts_mut(global_pointers::fpu_st as *mut u8, 128)
481 })?;
482 unsafe {
483 *global_pointers::fpu_stack_empty = scalar(slots, 68)? as u8;
484 *global_pointers::fpu_stack_ptr = scalar(slots, 69)? as u8;
485 *global_pointers::fpu_control_word = scalar(slots, 70)? as u16;
486 *global_pointers::fpu_ip = scalar(slots, 71)? as i32;
487 *global_pointers::fpu_ip_selector = scalar(slots, 72)? as i32;
488 *global_pointers::fpu_dp = scalar(slots, 73)? as i32;
489 *global_pointers::fpu_dp_selector = scalar(slots, 74)? as i32;
490 *global_pointers::fpu_opcode = scalar(slots, 75)? as i32;
491 *global_pointers::last_result = slots
492 .get(86)
493 .and_then(serde_json::Value::as_i64)
494 .unwrap_or(0) as i32;
495 *global_pointers::fpu_status_word = slots
496 .get(87)
497 .and_then(serde_json::Value::as_i64)
498 .unwrap_or(0) as u16;
499 *global_pointers::mxcsr = slots
500 .get(88)
501 .and_then(serde_json::Value::as_i64)
502 .unwrap_or(0x1F80) as i32;
503 }
504
505 let packed_memory = buffer_for(slots, buffers, 77)?;
506 let bitmap = buffer_for(slots, buffers, 78)?;
507 unsafe {
508 std::ptr::write_bytes(memory::mem8, 0, self.ram_bytes as usize);
509 }
510 let page_count = self.ram_bytes as usize / 0x1000;
511 let mut packed_page = 0usize;
512 for page in 0..page_count {
513 if bitmap
514 .get(page >> 3)
515 .map_or(false, |byte| byte & (1 << (page & 7)) != 0)
516 {
517 let src_start = packed_page * 0x1000;
518 let src_end = src_start + 0x1000;
519 if src_end > packed_memory.len() {
520 return Err("packed memory buffer is shorter than bitmap population".to_owned());
521 }
522 unsafe {
523 std::ptr::copy_nonoverlapping(
524 packed_memory.as_ptr().add(src_start),
525 memory::mem8.add(page * 0x1000),
526 0x1000,
527 );
528 }
529 packed_page += 1;
530 }
531 }
532 if packed_page * 0x1000 != packed_memory.len() {
533 return Err(format!(
534 "packed memory has {} pages but bitmap references {}",
535 packed_memory.len() / 0x1000,
536 packed_page
537 ));
538 }
539
540 native_devices::restore_state(state, buffers)?;
541 cpu::update_state_flags();
542 unsafe {
543 cpu::full_clear_tlb();
544 }
545 Ok(())
546 }
547}
548
549fn buffer_for<'a>(
550 state: &[serde_json::Value],
551 buffers: &'a [Vec<u8>],
552 index: usize,
553) -> Result<&'a [u8], String> {
554 let buffer_id = state
555 .get(index)
556 .and_then(serde_json::Value::as_object)
557 .and_then(|object| object.get("buffer_id"))
558 .and_then(serde_json::Value::as_u64)
559 .ok_or_else(|| format!("state[{index}] is not a typed buffer"))?
560 as usize;
561 buffers
562 .get(buffer_id)
563 .map(Vec::as_slice)
564 .ok_or_else(|| format!("buffer id {buffer_id} is out of range"))
565}
566
567fn byte_array_from_state(
568 state: &[serde_json::Value],
569 len: usize,
570 name: &str,
571) -> Result<[u8; 13], String> {
572 byte_array_from_values(state, len, name)
573}
574
575fn byte_array_from_values(
576 state: &[serde_json::Value],
577 len: usize,
578 name: &str,
579) -> Result<[u8; 13], String> {
580 if len != 13 || state.len() < len {
581 return Err(format!("{name} has {} fields; expected {len}", state.len()));
582 }
583 let mut result = [0u8; 13];
584 for (index, value) in state.iter().take(len).enumerate() {
585 if index == 5 {
586 continue;
589 }
590 result[index] = value
591 .as_i64()
592 .ok_or_else(|| format!("{name}[{index}] is not an integer"))?
593 as u8;
594 }
595 Ok(result)
596}
597
598fn scalar(state: &[serde_json::Value], index: usize) -> Result<i64, String> {
599 state
600 .get(index)
601 .and_then(serde_json::Value::as_i64)
602 .ok_or_else(|| format!("state[{index}] is not an integer scalar"))
603}
604
605fn copy_buffer(
606 state: &[serde_json::Value],
607 buffers: &[Vec<u8>],
608 index: usize,
609 target: &mut [u8],
610) -> Result<(), String> {
611 let source = buffer_for(state, buffers, index)?;
612 if source.len() != target.len() {
613 return Err(format!(
614 "state[{index}] length {} != expected {}",
615 source.len(),
616 target.len()
617 ));
618 }
619 target.copy_from_slice(source);
620 Ok(())
621}
622
623fn copy_i32_buffer(
624 state: &[serde_json::Value],
625 buffers: &[Vec<u8>],
626 index: usize,
627 target: &mut [u8],
628) -> Result<(), String> {
629 copy_buffer(state, buffers, index, target)
630}
631
632fn copy_u16_buffer(
633 state: &[serde_json::Value],
634 buffers: &[Vec<u8>],
635 index: usize,
636 target: &mut [u8],
637) -> Result<(), String> {
638 copy_buffer(state, buffers, index, target)
639}
640
641fn copy_u32_buffer(
642 state: &[serde_json::Value],
643 buffers: &[Vec<u8>],
644 index: usize,
645 target: &mut [u8],
646) -> Result<(), String> {
647 copy_buffer(state, buffers, index, target)
648}
649
650fn copy_u64_buffer(
651 state: &[serde_json::Value],
652 buffers: &[Vec<u8>],
653 index: usize,
654 target: &mut [u8],
655) -> Result<(), String> {
656 copy_buffer(state, buffers, index, target)
657}