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