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