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();
10static PS2: OnceLock<Mutex<Ps2State>> = OnceLock::new();
11
12#[derive(Default)]
13struct Ps2State {
14 output: VecDeque<u8>,
15 command_byte: u8,
16 pending_command: u8,
17}
18
19fn ps2() -> &'static Mutex<Ps2State> {
20 PS2.get_or_init(|| {
21 Mutex::new(Ps2State {
22 command_byte: 0x01,
23 ..Ps2State::default()
24 })
25 })
26}
27
28#[derive(Default)]
29struct UartState {
30 ints: u8,
31 baud_rate: u16,
32 line_control: u8,
33 lsr: u8,
34 fifo_control: u8,
35 ier: u8,
36 iir: u8,
37 modem_control: u8,
38 modem_status: u8,
39 scratch: u8,
40 irq: u8,
41 input: VecDeque<u8>,
42}
43
44fn uart0() -> &'static Mutex<UartState> {
45 UART0.get_or_init(|| Mutex::new(UartState::default()))
46}
47
48fn ps2_read(port: i32) -> Option<i32> {
49 let mut controller = ps2().lock().ok()?;
50 match port {
51 0x60 => {
52 let value = controller.output.pop_front().unwrap_or(0);
53 let more = !controller.output.is_empty();
54 drop(controller);
55 unsafe {
56 crate::cpu::cpu::device_lower_irq(1);
57 if more {
58 crate::cpu::cpu::device_raise_irq(1);
59 }
60 }
61 Some(value as i32)
62 }
63 0x64 => Some(if controller.output.is_empty() { 0 } else { 1 }),
64 _ => None,
65 }
66}
67
68fn ps2_write(port: i32, value: i32) -> bool {
69 let Ok(mut controller) = ps2().lock() else {
70 return false;
71 };
72 match port {
73 0x64 => {
74 controller.pending_command = value as u8;
75 true
76 }
77 0x60 => {
78 if controller.pending_command == 0x60 {
79 controller.command_byte = value as u8;
80 }
81 controller.pending_command = 0;
82 true
83 }
84 _ => false,
85 }
86}
87
88fn keycode_for_ascii(byte: u8) -> Option<(u8, bool)> {
89 let upper = byte.to_ascii_uppercase();
90 let shifted = byte.is_ascii_uppercase();
91 let code = match upper {
92 b'A' => 0x1E,
93 b'B' => 0x30,
94 b'C' => 0x2E,
95 b'D' => 0x20,
96 b'E' => 0x12,
97 b'F' => 0x21,
98 b'G' => 0x22,
99 b'H' => 0x23,
100 b'I' => 0x17,
101 b'J' => 0x24,
102 b'K' => 0x25,
103 b'L' => 0x26,
104 b'M' => 0x32,
105 b'N' => 0x31,
106 b'O' => 0x18,
107 b'P' => 0x19,
108 b'Q' => 0x10,
109 b'R' => 0x13,
110 b'S' => 0x1F,
111 b'T' => 0x14,
112 b'U' => 0x16,
113 b'V' => 0x2F,
114 b'W' => 0x11,
115 b'X' => 0x2D,
116 b'Y' => 0x15,
117 b'Z' => 0x2C,
118 b'1' | b'!' => 0x02,
119 b'2' | b'@' => 0x03,
120 b'3' | b'#' => 0x04,
121 b'4' | b'$' => 0x05,
122 b'5' | b'%' => 0x06,
123 b'6' | b'^' => 0x07,
124 b'7' | b'&' => 0x08,
125 b'8' | b'*' => 0x09,
126 b'9' | b'(' => 0x0A,
127 b'0' | b')' => 0x0B,
128 b'-' | b'_' => 0x0C,
129 b'=' | b'+' => 0x0D,
130 b'[' | b'{' => 0x1A,
131 b']' | b'}' => 0x1B,
132 b';' | b':' => 0x27,
133 b'\'' | b'"' => 0x28,
134 b'`' | b'~' => 0x29,
135 b'\\' | b'|' => 0x2B,
136 b',' | b'<' => 0x33,
137 b'.' | b'>' => 0x34,
138 b'/' | b'?' => 0x35,
139 b' ' => 0x39,
140 b'\n' | b'\r' => 0x1C,
141 b'\t' => 0x0F,
142 8 => 0x0E,
143 _ => return None,
144 };
145 let shifted = shifted
146 || matches!(byte, b'!'..=b'&' | b'('..=b'+' | b':' | b'<'..=b'>' | b'?' | b'@' | b'^' | b'_' | b'{' | b'|' | b'}' | b'~' | b'"');
147 Some((code, shifted))
148}
149
150pub fn inject_keyboard_text(text: &str) -> usize {
151 let Ok(mut controller) = ps2().lock() else {
152 return 0;
153 };
154 let mut count = 0;
155 for byte in text.bytes() {
156 let Some((code, shifted)) = keycode_for_ascii(byte) else {
157 continue;
158 };
159 if shifted {
160 controller.output.push_back(0x2A);
161 }
162 controller.output.push_back(code);
163 controller.output.push_back(code | 0x80);
164 if shifted {
165 controller.output.push_back(0xAA);
166 }
167 count += 1;
168 }
169 drop(controller);
170 if count > 0 {
171 unsafe { crate::cpu::cpu::device_raise_irq(1) };
172 }
173 count
174}
175
176fn uart_read(port: i32) -> i32 {
177 let offset = (port - 0x3F8) as u8;
178 let mut uart = uart0().lock().expect("UART0 mutex poisoned");
179 match offset {
180 0 if uart.line_control & 0x80 != 0 => (uart.baud_rate & 0xFF) as i32,
181 0 => uart.input.pop_front().unwrap_or(0) as i32,
182 1 if uart.line_control & 0x80 != 0 => (uart.baud_rate >> 8) as i32,
183 1 => (uart.ier & 0x0F) as i32,
184 2 => {
185 let fifo = if uart.fifo_control & 1 != 0 { 0xC0 } else { 0 };
186 (uart.iir | fifo) as i32
187 }
188 3 => uart.line_control as i32,
189 4 => uart.modem_control as i32,
190 5 => (uart.lsr | if uart.input.is_empty() { 0 } else { 0x01 }) as i32,
191 6 => uart.modem_status as i32,
192 7 => uart.scratch as i32,
193 _ => 0xFF,
194 }
195}
196
197fn restore_uart_state(state: &[serde_json::Value]) -> Result<(), String> {
198 if state.len() < 11 {
199 return Err(format!(
200 "UART state has {} fields; expected 11",
201 state.len()
202 ));
203 }
204 let mut uart = uart0()
205 .lock()
206 .map_err(|_| "UART0 mutex poisoned".to_owned())?;
207 uart.ints = state[0]
208 .as_i64()
209 .ok_or_else(|| "UART ints is not an integer".to_owned())? as u8;
210 uart.baud_rate = state[1]
211 .as_i64()
212 .ok_or_else(|| "UART baud rate is not an integer".to_owned())? as u16;
213 uart.line_control = state[2]
214 .as_i64()
215 .ok_or_else(|| "UART line control is not an integer".to_owned())?
216 as u8;
217 uart.lsr = state[3]
218 .as_i64()
219 .ok_or_else(|| "UART LSR is not an integer".to_owned())? as u8;
220 uart.fifo_control = state[4]
221 .as_i64()
222 .ok_or_else(|| "UART FIFO control is not an integer".to_owned())?
223 as u8;
224 uart.ier = state[5]
225 .as_i64()
226 .ok_or_else(|| "UART IER is not an integer".to_owned())? as u8;
227 uart.iir = state[6]
228 .as_i64()
229 .ok_or_else(|| "UART IIR is not an integer".to_owned())? as u8;
230 uart.modem_control = state[7]
231 .as_i64()
232 .ok_or_else(|| "UART modem control is not an integer".to_owned())?
233 as u8;
234 uart.modem_status = state[8]
235 .as_i64()
236 .ok_or_else(|| "UART modem status is not an integer".to_owned())?
237 as u8;
238 uart.scratch = state[9]
239 .as_i64()
240 .ok_or_else(|| "UART scratch is not an integer".to_owned())? as u8;
241 uart.irq = state[10]
242 .as_i64()
243 .ok_or_else(|| "UART IRQ is not an integer".to_owned())? as u8;
244 Ok(())
245}
246
247fn uart_write(port: i32, value: i32) {
248 let offset = (port - 0x3F8) as u8;
249 let byte = value as u8;
250 let mut output = None;
251 {
252 let mut uart = uart0().lock().expect("UART0 mutex poisoned");
253 match offset {
254 0 if uart.line_control & 0x80 != 0 => {
255 uart.baud_rate = (uart.baud_rate & 0xFF00) | byte as u16;
256 }
257 0 => output = Some(byte),
258 1 if uart.line_control & 0x80 != 0 => {
259 uart.baud_rate = (uart.baud_rate & 0x00FF) | ((byte as u16) << 8);
260 }
261 1 => uart.ier = byte & 0x0F,
262 2 => uart.fifo_control = byte,
263 3 => uart.line_control = byte,
264 4 => uart.modem_control = byte,
265 7 => uart.scratch = byte,
266 _ => {}
267 }
268 }
269 if let Some(byte) = output {
270 let mut stdout = std::io::stdout().lock();
271 let _ = stdout.write_all(&[byte]);
272 let _ = stdout.flush();
273 }
274}
275
276#[no_mangle]
280pub extern "C" fn cpu_exception_hook(_interrupt: i32) -> bool {
281 false
282}
283
284#[no_mangle]
285pub extern "C" fn microtick() -> f64 {
286 START.get_or_init(Instant::now).elapsed().as_secs_f64() * 1000.0
287}
288
289#[no_mangle]
290pub extern "C" fn run_hardware_timers(_acpi_enabled: bool, _now: f64) -> f64 {
291 0.0
292}
293
294#[no_mangle]
295pub extern "C" fn cpu_event_halt() {}
296
297#[no_mangle]
298pub extern "C" fn stop_idling() {}
299
300#[no_mangle]
301pub extern "C" fn get_rand_int() -> i32 {
302 0x1357_9BDF
303}
304
305#[no_mangle]
306pub extern "C" fn io_port_read8(port: i32) -> i32 {
307 if let Some(value) = ps2_read(port) {
308 value
309 } else if let Some(value) = native_devices::io_read8(port) {
310 value
311 } else if (0x3F8..=0x3FF).contains(&port) {
312 uart_read(port)
313 } else {
314 0xFF
315 }
316}
317
318#[no_mangle]
319pub extern "C" fn io_port_read16(port: i32) -> i32 {
320 native_devices::io_read16(port).unwrap_or(0xFFFF)
321}
322
323#[no_mangle]
324pub extern "C" fn io_port_read32(port: i32) -> i32 {
325 native_devices::io_read32(port).unwrap_or(-1)
326}
327
328#[no_mangle]
329pub extern "C" fn io_port_write8(port: i32, value: i32) {
330 if !ps2_write(port, value)
331 && !native_devices::io_write8(port, value)
332 && (0x3F8..=0x3FF).contains(&port)
333 {
334 uart_write(port, value);
335 }
336}
337
338#[no_mangle]
339pub extern "C" fn io_port_write16(port: i32, value: i32) {
340 if !native_devices::io_write16(port, value) {}
341}
342
343#[no_mangle]
344pub extern "C" fn io_port_write32(port: i32, value: i32) {
345 if !native_devices::io_write32(port, value) {}
346}
347
348#[no_mangle]
349pub extern "C" fn mmap_read8(addr: u32) -> i32 {
350 native_devices::mmio_read8(addr).unwrap_or(0xFF)
351}
352
353#[no_mangle]
354pub extern "C" fn mmap_read32(addr: u32) -> i32 {
355 native_devices::mmio_read32(addr).unwrap_or(-1)
356}
357
358#[no_mangle]
359pub extern "C" fn mmap_write8(addr: u32, value: i32) {
360 let _ = native_devices::mmio_write8(addr, value);
361}
362
363#[no_mangle]
364pub extern "C" fn mmap_write16(addr: u32, value: i32) {
365 let _ = native_devices::mmio_write16(addr, value);
366}
367
368#[no_mangle]
369pub extern "C" fn mmap_write32(addr: u32, value: i32) {
370 let _ = native_devices::mmio_write32(addr, value);
371}
372
373#[no_mangle]
374pub extern "C" fn mmap_write64(_addr: u32, _v0: i32, _v1: i32) {}
375
376#[no_mangle]
377pub extern "C" fn mmap_write128(_addr: u32, _v0: i32, _v1: i32, _v2: i32, _v3: i32) {}
378
379pub struct NativeCpu {
385 state_arena: Box<[u8; 4096]>,
386 ram_bytes: u32,
387 vga_bytes: u32,
388 last_timer_tick: Instant,
389 screen_width: u32,
390 screen_height: u32,
391 screen_bpp: u32,
392 graphical_mode: bool,
393}
394
395impl NativeCpu {
396 pub fn new(ram_bytes: u32, vga_bytes: u32) -> Self {
397 assert!(ram_bytes > 0, "RAM size must be non-zero");
398 assert!(vga_bytes > 0, "VGA memory size must be non-zero");
399
400 let mut state_arena = Box::new([0u8; 4096]);
401 unsafe {
402 global_pointers::init(state_arena.as_mut_ptr());
403 let _ = memory::allocate_memory(ram_bytes);
404 let _ = memory::svga_allocate_memory(vga_bytes);
405 *global_pointers::memory_size = ram_bytes;
406 memory::vga_memory_size = vga_bytes;
407 cpu::reset_cpu();
408 }
409
410 Self {
411 state_arena,
412 ram_bytes,
413 vga_bytes,
414 last_timer_tick: Instant::now(),
415 screen_width: 80,
416 screen_height: 25,
417 screen_bpp: 0,
418 graphical_mode: false,
419 }
420 }
421
422 pub fn ram_bytes(&self) -> u32 {
423 self.ram_bytes
424 }
425
426 pub fn vga_bytes(&self) -> u32 {
427 self.vga_bytes
428 }
429
430 pub fn step(&mut self, max_instructions: u32) -> u32 {
431 unsafe {
432 let halted = *global_pointers::in_hlt;
433 let timer_due = self.last_timer_tick.elapsed() >= std::time::Duration::from_millis(1);
434 if halted || timer_due {
435 let now = microtick();
436 if *global_pointers::acpi_enabled {
437 let _ = apic::apic_timer(now);
438 cpu::handle_irqs();
439 } else {
440 pic::set_irq(0);
441 cpu::handle_irqs();
442 pic::clear_irq(0);
443 cpu::handle_irqs();
444 }
445 self.last_timer_tick = Instant::now();
446 }
447 cpu::main_loop_native_interpreter(max_instructions)
448 }
449 }
450
451 pub fn read_memory(&self, address: u32, output: &mut [u8]) -> bool {
452 if address.checked_add(output.len() as u32).is_none()
453 || address + output.len() as u32 > self.ram_bytes
454 {
455 return false;
456 }
457 unsafe {
458 output.copy_from_slice(std::slice::from_raw_parts(
459 memory::mem8.add(address as usize),
460 output.len(),
461 ));
462 }
463 true
464 }
465
466 pub fn write_memory(&mut self, address: u32, input: &[u8]) -> bool {
467 if address.checked_add(input.len() as u32).is_none()
468 || address + input.len() as u32 > self.ram_bytes
469 {
470 return false;
471 }
472 unsafe {
473 std::slice::from_raw_parts_mut(memory::mem8.add(address as usize), input.len())
474 .copy_from_slice(input);
475 }
476 true
477 }
478
479 pub fn instruction_pointer(&self) -> u32 {
480 unsafe { *global_pointers::instruction_pointer as u32 }
481 }
482
483 pub fn halted(&self) -> bool {
484 unsafe { *global_pointers::in_hlt }
485 }
486
487 pub fn state_arena(&self) -> &[u8; 4096] {
488 &self.state_arena
489 }
490
491 pub fn vga_framebuffer_rgb(&self) -> Option<(u32, u32, Vec<u8>)> {
495 if !self.graphical_mode || self.screen_width == 0 || self.screen_height == 0 {
496 return None;
497 }
498 let pixels = (self.screen_width as usize).checked_mul(self.screen_height as usize)?;
499 let mut output = vec![0u8; pixels.checked_mul(3)?];
500 unsafe {
501 if memory::vga_mem8.is_null() || self.screen_bpp != 32 {
502 return None;
503 }
504 let source_len = pixels.checked_mul(4)?;
505 if source_len > self.vga_bytes as usize {
506 return None;
507 }
508 let source = std::slice::from_raw_parts(memory::vga_mem8, source_len);
509 for (index, rgb) in output.chunks_exact_mut(3).enumerate() {
510 let pixel = &source[index * 4..index * 4 + 4];
511 rgb.copy_from_slice(&[pixel[2], pixel[1], pixel[0]]);
512 }
513 }
514 Some((self.screen_width, self.screen_height, output))
515 }
516
517 pub fn set_9p_root(&mut self, path: impl AsRef<std::path::Path>) -> Result<(), String> {
518 native_devices::set_9p_root(path)
519 }
520}
521
522#[cfg(test)]
523mod tests {
524 use super::NativeCpu;
525
526 #[test]
527 fn native_interpreter_executes_reset_vector_hlt() {
528 let mut cpu = NativeCpu::new(128 * 1024 * 1024, 8 * 1024 * 1024);
529 assert!(cpu.write_memory(0xFFFF0, &[0xF4]));
530 assert_eq!(cpu.instruction_pointer(), 0xFFFF0);
531 assert_eq!(cpu.step(1), 1);
532 assert!(cpu.halted());
533 }
534}
535
536impl NativeCpu {
537 pub fn restore_v86_state(
542 &mut self,
543 state: &serde_json::Value,
544 buffers: &[Vec<u8>],
545 ) -> Result<(), String> {
546 let slots = state
547 .as_array()
548 .ok_or_else(|| "v86 state is not an array".to_owned())?;
549
550 let memory_size = scalar(slots, 0)? as u32;
551 if memory_size != self.ram_bytes {
552 return Err(format!(
553 "state RAM is {memory_size} bytes, NativeCpu has {} bytes",
554 self.ram_bytes
555 ));
556 }
557
558 let segment_state = buffer_for(slots, buffers, 1)?;
559 if segment_state.len() != 16 {
560 return Err(format!(
561 "state[1] length {} != expected 16",
562 segment_state.len()
563 ));
564 }
565 unsafe {
566 std::slice::from_raw_parts_mut(global_pointers::segment_is_null as *mut u8, 8)
567 .copy_from_slice(&segment_state[..8]);
568 std::slice::from_raw_parts_mut(global_pointers::segment_access_bytes, 8)
569 .copy_from_slice(&segment_state[8..]);
570 }
571 copy_i32_buffer(slots, buffers, 2, unsafe {
572 std::slice::from_raw_parts_mut(global_pointers::segment_offsets as *mut u8, 32)
573 })?;
574 copy_u32_buffer(slots, buffers, 3, unsafe {
575 std::slice::from_raw_parts_mut(global_pointers::segment_limits as *mut u8, 32)
576 })?;
577
578 unsafe {
579 *global_pointers::memory_size = memory_size;
580 *global_pointers::protected_mode = scalar(slots, 4)? != 0;
581 *global_pointers::idtr_offset = scalar(slots, 5)? as i32;
582 *global_pointers::idtr_size = scalar(slots, 6)? as i32;
583 *global_pointers::gdtr_offset = scalar(slots, 7)? as i32;
584 *global_pointers::gdtr_size = scalar(slots, 8)? as i32;
585 }
586 copy_i32_buffer(slots, buffers, 10, unsafe {
587 std::slice::from_raw_parts_mut(global_pointers::cr as *mut u8, 32)
588 })?;
589 unsafe {
590 *global_pointers::cpl = scalar(slots, 11)? as u8;
591 *global_pointers::is_32 = scalar(slots, 13)? != 0;
592 *global_pointers::stack_size_32 = scalar(slots, 16)? != 0;
593 *global_pointers::in_hlt = scalar(slots, 17)? != 0;
594 *global_pointers::last_virt_eip = scalar(slots, 18)? as i32;
595 *global_pointers::eip_phys = scalar(slots, 19)? as i32;
596 *global_pointers::sysenter_cs = scalar(slots, 22)? as i32;
597 *global_pointers::sysenter_eip = scalar(slots, 23)? as i32;
598 *global_pointers::sysenter_esp = scalar(slots, 24)? as i32;
599 *global_pointers::prefixes = scalar(slots, 25)? as u8;
600 *global_pointers::flags = scalar(slots, 26)? as i32;
601 *global_pointers::flags_changed = scalar(slots, 27)? as i32;
602 *global_pointers::last_op1 = scalar(slots, 28)? as i32;
603 *global_pointers::last_op_size = scalar(slots, 30)? as i32;
604 *global_pointers::instruction_pointer = scalar(slots, 37)? as i32;
605 *global_pointers::previous_ip = scalar(slots, 38)? as i32;
606 }
607 copy_i32_buffer(slots, buffers, 39, unsafe {
608 std::slice::from_raw_parts_mut(global_pointers::reg32 as *mut u8, 32)
609 })?;
610 copy_u16_buffer(slots, buffers, 40, unsafe {
611 std::slice::from_raw_parts_mut(global_pointers::sreg as *mut u8, 16)
612 })?;
613 copy_i32_buffer(slots, buffers, 41, unsafe {
614 std::slice::from_raw_parts_mut(global_pointers::dreg as *mut u8, 32)
615 })?;
616 copy_u64_buffer(slots, buffers, 42, unsafe {
617 std::slice::from_raw_parts_mut(global_pointers::reg_pdpte as *mut u8, 32)
618 })?;
619
620 let tsc = buffer_for(slots, buffers, 43)?;
621 if tsc.len() >= 8 {
622 let low = u32::from_le_bytes(tsc[0..4].try_into().unwrap());
623 let high = u32::from_le_bytes(tsc[4..8].try_into().unwrap());
624 unsafe {
625 cpu::set_tsc(low, high);
626 }
627 }
628
629 if let Some(uart_state) = slots.get(54).and_then(serde_json::Value::as_array) {
630 restore_uart_state(uart_state)?;
631 }
632 if let Some(pic_state) = slots.get(60).and_then(serde_json::Value::as_array) {
633 let master = byte_array_from_state(pic_state, 13, "PIC master")?;
634 let slave_value = pic_state
635 .get(5)
636 .ok_or_else(|| "PIC state has no slave controller".to_owned())?;
637 let slave_array = slave_value
638 .as_array()
639 .ok_or_else(|| "PIC slave state is not an array".to_owned())?;
640 let slave = byte_array_from_values(slave_array, 13, "PIC slave")?;
641 pic::restore_state(&master, &slave);
642 }
643
644 if slots.get(46).is_some_and(|value| !value.is_null()) {
645 let apic_state = buffer_for(slots, buffers, 46)?;
646 apic::restore_state_bytes(apic_state)?;
647 unsafe {
648 *global_pointers::apic_enabled = true;
649 *global_pointers::acpi_enabled = true;
650 }
651 }
652 if slots.get(63).is_some_and(|value| !value.is_null()) {
653 let ioapic_state = buffer_for(slots, buffers, 63)?;
654 ioapic::restore_state_bytes(ioapic_state)?;
655 }
656
657 if let Some(vga_state) = slots.get(52).and_then(serde_json::Value::as_array) {
658 self.screen_width = vga_state
659 .get(15)
660 .and_then(serde_json::Value::as_i64)
661 .unwrap_or(0) as u32;
662 self.screen_height = vga_state
663 .get(16)
664 .and_then(serde_json::Value::as_i64)
665 .unwrap_or(0) as u32;
666 self.screen_bpp = vga_state
667 .get(19)
668 .and_then(serde_json::Value::as_i64)
669 .unwrap_or(0) as u32;
670 self.graphical_mode = vga_state
671 .get(9)
672 .and_then(serde_json::Value::as_bool)
673 .unwrap_or(false);
674 if let Some(value) = vga_state.get(39) {
675 let buffer_id = value
676 .get("buffer_id")
677 .and_then(serde_json::Value::as_u64)
678 .ok_or_else(|| "VGA state[39] is not a typed buffer".to_owned())?
679 as usize;
680 let svga = buffers
681 .get(buffer_id)
682 .ok_or_else(|| format!("VGA buffer id {buffer_id} is out of range"))?;
683 let vga_len = self.vga_bytes as usize;
684 if svga.len() > vga_len {
685 return Err(format!(
686 "VGA framebuffer {} exceeds allocated {} bytes",
687 svga.len(),
688 vga_len
689 ));
690 }
691 unsafe {
692 std::ptr::copy_nonoverlapping(svga.as_ptr(), memory::vga_mem8, svga.len());
693 }
694 }
695 }
696
697 unsafe {
698 *global_pointers::tss_size_32 = scalar(slots, 64)? != 0;
699 }
700 copy_buffer(slots, buffers, 66, unsafe {
701 std::slice::from_raw_parts_mut(global_pointers::reg_xmm as *mut u8, 128)
702 })?;
703 copy_buffer(slots, buffers, 67, unsafe {
704 std::slice::from_raw_parts_mut(global_pointers::fpu_st as *mut u8, 128)
705 })?;
706 unsafe {
707 *global_pointers::fpu_stack_empty = scalar(slots, 68)? as u8;
708 *global_pointers::fpu_stack_ptr = scalar(slots, 69)? as u8;
709 *global_pointers::fpu_control_word = scalar(slots, 70)? as u16;
710 *global_pointers::fpu_ip = scalar(slots, 71)? as i32;
711 *global_pointers::fpu_ip_selector = scalar(slots, 72)? as i32;
712 *global_pointers::fpu_dp = scalar(slots, 73)? as i32;
713 *global_pointers::fpu_dp_selector = scalar(slots, 74)? as i32;
714 *global_pointers::fpu_opcode = scalar(slots, 75)? as i32;
715 *global_pointers::last_result = slots
716 .get(86)
717 .and_then(serde_json::Value::as_i64)
718 .unwrap_or(0) as i32;
719 *global_pointers::fpu_status_word = slots
720 .get(87)
721 .and_then(serde_json::Value::as_i64)
722 .unwrap_or(0) as u16;
723 *global_pointers::mxcsr = slots
724 .get(88)
725 .and_then(serde_json::Value::as_i64)
726 .unwrap_or(0x1F80) as i32;
727 }
728
729 let packed_memory = buffer_for(slots, buffers, 77)?;
730 let bitmap = buffer_for(slots, buffers, 78)?;
731 unsafe {
732 std::ptr::write_bytes(memory::mem8, 0, self.ram_bytes as usize);
733 }
734 let page_count = self.ram_bytes as usize / 0x1000;
735 let mut packed_page = 0usize;
736 for page in 0..page_count {
737 if bitmap
738 .get(page >> 3)
739 .map_or(false, |byte| byte & (1 << (page & 7)) != 0)
740 {
741 let src_start = packed_page * 0x1000;
742 let src_end = src_start + 0x1000;
743 if src_end > packed_memory.len() {
744 return Err("packed memory buffer is shorter than bitmap population".to_owned());
745 }
746 unsafe {
747 std::ptr::copy_nonoverlapping(
748 packed_memory.as_ptr().add(src_start),
749 memory::mem8.add(page * 0x1000),
750 0x1000,
751 );
752 }
753 packed_page += 1;
754 }
755 }
756 if packed_page * 0x1000 != packed_memory.len() {
757 return Err(format!(
758 "packed memory has {} pages but bitmap references {}",
759 packed_memory.len() / 0x1000,
760 packed_page
761 ));
762 }
763
764 native_devices::restore_state(state, buffers)?;
765 cpu::update_state_flags();
766 unsafe {
767 cpu::full_clear_tlb();
768 }
769 Ok(())
770 }
771}
772
773fn buffer_for<'a>(
774 state: &[serde_json::Value],
775 buffers: &'a [Vec<u8>],
776 index: usize,
777) -> Result<&'a [u8], String> {
778 let buffer_id = state
779 .get(index)
780 .and_then(serde_json::Value::as_object)
781 .and_then(|object| object.get("buffer_id"))
782 .and_then(serde_json::Value::as_u64)
783 .ok_or_else(|| format!("state[{index}] is not a typed buffer"))?
784 as usize;
785 buffers
786 .get(buffer_id)
787 .map(Vec::as_slice)
788 .ok_or_else(|| format!("buffer id {buffer_id} is out of range"))
789}
790
791fn byte_array_from_state(
792 state: &[serde_json::Value],
793 len: usize,
794 name: &str,
795) -> Result<[u8; 13], String> {
796 byte_array_from_values(state, len, name)
797}
798
799fn byte_array_from_values(
800 state: &[serde_json::Value],
801 len: usize,
802 name: &str,
803) -> Result<[u8; 13], String> {
804 if len != 13 || state.len() < len {
805 return Err(format!("{name} has {} fields; expected {len}", state.len()));
806 }
807 let mut result = [0u8; 13];
808 for (index, value) in state.iter().take(len).enumerate() {
809 if index == 5 {
810 continue;
813 }
814 result[index] = value
815 .as_i64()
816 .ok_or_else(|| format!("{name}[{index}] is not an integer"))?
817 as u8;
818 }
819 Ok(result)
820}
821
822fn scalar(state: &[serde_json::Value], index: usize) -> Result<i64, String> {
823 state
824 .get(index)
825 .and_then(serde_json::Value::as_i64)
826 .ok_or_else(|| format!("state[{index}] is not an integer scalar"))
827}
828
829fn copy_buffer(
830 state: &[serde_json::Value],
831 buffers: &[Vec<u8>],
832 index: usize,
833 target: &mut [u8],
834) -> Result<(), String> {
835 let source = buffer_for(state, buffers, index)?;
836 if source.len() != target.len() {
837 return Err(format!(
838 "state[{index}] length {} != expected {}",
839 source.len(),
840 target.len()
841 ));
842 }
843 target.copy_from_slice(source);
844 Ok(())
845}
846
847fn copy_i32_buffer(
848 state: &[serde_json::Value],
849 buffers: &[Vec<u8>],
850 index: usize,
851 target: &mut [u8],
852) -> Result<(), String> {
853 copy_buffer(state, buffers, index, target)
854}
855
856fn copy_u16_buffer(
857 state: &[serde_json::Value],
858 buffers: &[Vec<u8>],
859 index: usize,
860 target: &mut [u8],
861) -> Result<(), String> {
862 copy_buffer(state, buffers, index, target)
863}
864
865fn copy_u32_buffer(
866 state: &[serde_json::Value],
867 buffers: &[Vec<u8>],
868 index: usize,
869 target: &mut [u8],
870) -> Result<(), String> {
871 copy_buffer(state, buffers, index, target)
872}
873
874fn copy_u64_buffer(
875 state: &[serde_json::Value],
876 buffers: &[Vec<u8>],
877 index: usize,
878 target: &mut [u8],
879) -> Result<(), String> {
880 copy_buffer(state, buffers, index, target)
881}
882
883#[cfg(test)]
884mod keyboard_tests {
885 use super::keycode_for_ascii;
886
887 #[test]
888 fn maps_lowercase_without_shift() {
889 assert_eq!(keycode_for_ascii(b'a'), Some((0x1E, false)));
890 assert_eq!(keycode_for_ascii(b'z'), Some((0x2C, false)));
891 }
892
893 #[test]
894 fn maps_uppercase_and_punctuation_with_shift() {
895 assert_eq!(keycode_for_ascii(b'A'), Some((0x1E, true)));
896 assert_eq!(keycode_for_ascii(b'!'), Some((0x02, true)));
897 assert_eq!(keycode_for_ascii(b'_'), Some((0x0C, true)));
898 }
899
900 #[test]
901 fn maps_shell_control_characters() {
902 assert_eq!(keycode_for_ascii(b' '), Some((0x39, false)));
903 assert_eq!(keycode_for_ascii(b'\n'), Some((0x1C, false)));
904 assert_eq!(keycode_for_ascii(b'\t'), Some((0x0F, false)));
905 }
906}