use std::sync::Arc;
use assert_matches::assert_matches;
use parking_lot::Mutex;
use crate::hv::tests::TestIrqFd;
use crate::hv::{Error as HvError, MsiSender};
use crate::mem::emulated::Mmio;
use super::{IOREGSEL, IOWIN, IoApic};
#[derive(Debug, Default)]
struct TestMsiSender {
messages: Arc<Mutex<Vec<(u64, u32)>>>,
}
impl MsiSender for TestMsiSender {
type IrqFd = TestIrqFd;
fn send(&self, addr: u64, data: u32) -> Result<(), HvError> {
self.messages.lock().push((addr, data));
Ok(())
}
fn create_irqfd(&self) -> Result<Self::IrqFd, HvError> {
Ok(TestIrqFd::default())
}
}
#[test]
fn test_ioapic_read_write() {
let io_apic = IoApic::new(TestMsiSender::default());
io_apic.write(IOREGSEL, 4, 0x10).unwrap();
assert_eq!(io_apic.read(IOREGSEL, 4).unwrap(), 0x10);
io_apic.write(IOWIN, 4, 0x12345678).unwrap();
assert_eq!(io_apic.read(IOWIN, 4).unwrap(), 0x12345678);
io_apic.write(IOREGSEL, 4, 0x11).unwrap();
io_apic.write(IOWIN, 4, 0xabcdef00).unwrap();
assert_eq!(io_apic.read(IOWIN, 4).unwrap(), 0xabcdef00);
let regs = io_apic.regs.lock();
assert_eq!(regs.redirtbl[0].0, 0xabcdef0012345678);
}
#[test]
fn test_ioapic_service_pin() {
let msi_sender = TestMsiSender::default();
let messages = msi_sender.messages.clone();
let io_apic = IoApic::new(msi_sender);
let redirtbl_entry = (2u64 << 56) | 0x24;
io_apic.write(IOREGSEL, 4, 0x18).unwrap();
io_apic
.write(IOWIN, 4, (redirtbl_entry & 0xFFFFFFFF) as u64)
.unwrap();
io_apic.write(IOREGSEL, 4, 0x19).unwrap();
io_apic
.write(IOWIN, 4, (redirtbl_entry >> 32) as u64)
.unwrap();
io_apic.service_pin(4).unwrap();
let messages = messages.lock();
assert_matches!(messages.as_slice(), [(0xfee02000, 0x24)]);
}