use super::*;
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_out_i8042_reset_is_shutdown_signal() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
assert!(
dispatch_io_out(&com1, &com2, I8042_CMD_PORT, &[I8042_CMD_RESET_CPU]),
"I8042 reset (0xFE to port 0x64) must signal shutdown"
);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_out_i8042_non_reset() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
assert!(!dispatch_io_out(&com1, &com2, I8042_CMD_PORT, &[0x00]));
}
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_out_serial_com1() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
assert!(!dispatch_io_out(&com1, &com2, console::COM1_BASE, b"A"));
}
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_out_serial_com2() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
assert!(!dispatch_io_out(&com1, &com2, console::COM2_BASE, b"B"));
let output = com2.lock().output();
assert!(output.contains('B'));
}
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_out_unknown_port() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
assert!(!dispatch_io_out(&com1, &com2, 0x1234, &[0xFF]));
}
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_in_i8042_status() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let mut data = [0xFFu8; 1];
dispatch_io_in(&com1, &com2, I8042_CMD_PORT, &mut data);
assert_eq!(data[0], 0);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_in_i8042_data() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let mut data = [0xFFu8; 1];
dispatch_io_in(&com1, &com2, I8042_DATA_PORT, &mut data);
assert_eq!(data[0], 0);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn dispatch_io_in_unknown_port() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let mut data = [0xFFu8; 1];
dispatch_io_in(&com1, &com2, 0x1234, &mut data);
assert_eq!(data[0], 0xFF, "unknown port should not modify data");
}
#[test]
#[cfg(target_arch = "x86_64")]
fn classify_exit_io_out_i8042_reset_is_shutdown() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let data = [I8042_CMD_RESET_CPU];
let mut exit = VcpuExit::IoOut(I8042_CMD_PORT, &data);
let action = classify_exit(&com1, &com2, None, None, None, None, &mut exit);
assert!(
matches!(action, Some(ExitAction::Shutdown)),
"IoOut(0x64, [0xFE]) — i8042 reset — must classify as Shutdown"
);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn classify_exit_io_out_serial_is_continue() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let data = [b'Z'];
let mut exit = VcpuExit::IoOut(console::COM1_BASE, &data);
let action = classify_exit(&com1, &com2, None, None, None, None, &mut exit);
assert!(
matches!(action, Some(ExitAction::Continue)),
"IoOut to COM1 must classify as Continue (no reboot)"
);
assert!(com1.lock().output().contains('Z'));
}
#[test]
#[cfg(target_arch = "x86_64")]
fn classify_exit_io_in_serial_is_continue() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let mut data = [0xFFu8; 1];
let mut exit = VcpuExit::IoIn(console::COM1_BASE, &mut data);
let action = classify_exit(&com1, &com2, None, None, None, None, &mut exit);
assert!(
matches!(action, Some(ExitAction::Continue)),
"IoIn to COM1 must classify as Continue"
);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn classify_exit_x86_mmio_read_unmapped_returns_0xff() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let mut buf = [0u8; 4];
let mut exit = VcpuExit::MmioRead(0x1000, &mut buf);
let action = classify_exit(&com1, &com2, None, None, None, None, &mut exit);
assert!(
matches!(action, Some(ExitAction::Continue)),
"Unmapped MMIO read must classify as Continue (not Fatal)"
);
assert_eq!(
buf,
[0xff, 0xff, 0xff, 0xff],
"Unmapped MMIO read must fill the data buffer with 0xFF — \
leaving stale bytes would surface as phantom guest reads"
);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn classify_exit_x86_mmio_write_unmapped_is_continue() {
let com1 = PiMutex::new(console::Serial::new(console::COM1_BASE));
let com2 = PiMutex::new(console::Serial::new(console::COM2_BASE));
let data = [0xAAu8, 0xBB];
let mut exit = VcpuExit::MmioWrite(0x1000, &data);
let action = classify_exit(&com1, &com2, None, None, None, None, &mut exit);
assert!(
matches!(action, Some(ExitAction::Continue)),
"Unmapped MMIO write must classify as Continue"
);
}