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