Skip to content

Commit

Permalink
Add unit tests for interrupt manager
Browse files Browse the repository at this point in the history
Signed-off-by: 守情 <[email protected]>
  • Loading branch information
juliusxlh authored and jiangliu committed Jan 31, 2020
1 parent 303f113 commit b4180eb
Show file tree
Hide file tree
Showing 4 changed files with 361 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/interrupt/kvm/legacy_irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,53 @@ impl InterruptSourceGroup for LegacyIrq {
Ok(())
}
}

#[cfg(test)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod test {
use super::*;
use kvm_ioctls::{Kvm, VmFd};

fn create_vm_fd() -> VmFd {
let kvm = Kvm::new().unwrap();
kvm.create_vm().unwrap()
}

#[test]
#[allow(unreachable_patterns)]
fn test_legacy_interrupt_group() {
let vmfd = Arc::new(create_vm_fd());
let rounting = Arc::new(KvmIrqRouting::new(vmfd.clone()));
let base = 0;
let count = 1;
let group = LegacyIrq::new(base, count, vmfd.clone(), rounting.clone()).unwrap();

let mut legacy_fds = Vec::with_capacity(1);
legacy_fds.push(InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {}));

match group.interrupt_type() {
InterruptSourceType::LegacyIrq => {}
_ => {
panic!();
}
}
assert_eq!(group.len(), 1);
assert_eq!(group.base(), base);
assert!(group.enable(&legacy_fds).is_ok());
assert!(group.irqfd(0).unwrap().write(1).is_ok());
assert!(group.trigger(0, 0x168).is_ok());
assert!(group.ack(0, 0x168).is_ok());
assert!(group.trigger(1, 0x168).is_err());
assert!(group.ack(1, 0x168).is_err());
assert!(group
.update(
0,
&InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {})
)
.is_ok());
assert!(group.disable().is_ok());

assert!(LegacyIrq::new(base, 2, vmfd.clone(), rounting.clone()).is_err());
assert!(LegacyIrq::new(110, 1, vmfd.clone(), rounting.clone()).is_err());
}
}
154 changes: 154 additions & 0 deletions src/interrupt/kvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,157 @@ impl KvmIrqRouting {
self.set_routing(&routes)
}
}

#[cfg(any(target = "x86", target = "x86_64"))]
#[cfg(test)]
mod test {
use super::*;
use kvm_ioctls::{Kvm, VmFd};

//const VFIO_PCI_MSI_IRQ_INDEX: u32 = 1;

fn create_vm_fd() -> VmFd {
let kvm = Kvm::new().unwrap();
kvm.create_vm().unwrap()
}

fn create_irq_group(
manager: Arc<KvmIrqManager>,
_vmfd: Arc<VmFd>,
) -> Arc<Box<dyn InterruptSourceGroup>> {
let base = 0;
let count = 1;

manager
.create_group(InterruptSourceType::LegacyIrq, base, count)
.unwrap()
}

fn create_msi_group(
manager: Arc<KvmIrqManager>,
_vmfd: Arc<VmFd>,
) -> Arc<Box<dyn InterruptSourceGroup>> {
let base = 168;
let count = 32;

manager
.create_group(InterruptSourceType::MsiIrq, base, count)
.unwrap()
}

const MASTER_PIC: usize = 7;
const SLAVE_PIC: usize = 8;
const IOAPIC: usize = 23;

#[test]
fn test_create_kvmirqmanager() {
let vmfd = Arc::new(create_vm_fd());
let manager = KvmIrqManager::new(vmfd.clone());
assert!(vmfd.create_irq_chip().is_ok());
assert!(manager.initialize().is_ok());
}

#[test]
fn test_kvmirqmanager_opt() {
let vmfd = Arc::new(create_vm_fd());
assert!(vmfd.create_irq_chip().is_ok());
let manager = Arc::new(KvmIrqManager::new(vmfd.clone()));
assert!(manager.initialize().is_ok());
//irq
let group = create_irq_group(manager.clone(), vmfd.clone());
let _ = group.clone();
assert!(manager.destroy_group(group).is_ok());
//msi
let group = create_msi_group(manager.clone(), vmfd.clone());
let _ = group.clone();
assert!(manager.destroy_group(group).is_ok());
}

#[test]
fn test_irqrouting_initialize_legacy() {
let vmfd = Arc::new(create_vm_fd());
let routing = KvmIrqRouting::new(vmfd.clone());
assert!(routing.initialize().is_err());
assert!(vmfd.create_irq_chip().is_ok());
assert!(routing.initialize().is_ok());
let routes = &routing.routes.lock().unwrap();
assert_eq!(routes.len(), MASTER_PIC + SLAVE_PIC + IOAPIC);
}

#[test]
fn test_routing_opt() {
// pub(super) fn modify(&self, entry: &kvm_irq_routing_entry) -> Result<()> {
let vmfd = Arc::new(create_vm_fd());
let routing = KvmIrqRouting::new(vmfd.clone());
assert!(routing.initialize().is_err());
assert!(vmfd.create_irq_chip().is_ok());
assert!(routing.initialize().is_ok());

let mut entry = kvm_irq_routing_entry {
gsi: 8,
type_: KVM_IRQ_ROUTING_IRQCHIP,
..Default::default()
};

// Safe because we are initializing all fields of the `irqchip` struct.
unsafe {
entry.u.irqchip.irqchip = 0;
entry.u.irqchip.pin = 3;
}

let entrys = vec![entry.clone()];

assert!(routing.modify(&entry).is_err());
assert!(routing.add(&entrys).is_ok());
unsafe {
entry.u.irqchip.pin = 4;
}
assert!(routing.modify(&entry).is_ok());
assert!(routing.remove(&entrys).is_ok());
assert!(routing.modify(&entry).is_err());
}

#[test]
fn test_routing_commit() {
let vmfd = Arc::new(create_vm_fd());
let routing = KvmIrqRouting::new(vmfd.clone());

assert!(routing.initialize().is_err());
assert!(vmfd.create_irq_chip().is_ok());
assert!(routing.initialize().is_ok());

let mut entry = kvm_irq_routing_entry {
gsi: 8,
type_: KVM_IRQ_ROUTING_IRQCHIP,
..Default::default()
};
unsafe {
entry.u.irqchip.irqchip = 0;
entry.u.irqchip.pin = 3;
}

routing
.routes
.lock()
.unwrap()
.insert(hash_key(&entry), entry);
let routes = routing.routes.lock().unwrap();
assert!(routing.commit(&routes).is_ok());
}

#[test]
fn test_has_key() {
let gsi = 4;
let mut entry = kvm_irq_routing_entry {
gsi,
type_: KVM_IRQ_ROUTING_IRQCHIP,
..Default::default()
};
// Safe because we are initializing all fields of the `irqchip` struct.
unsafe {
entry.u.irqchip.irqchip = KVM_IRQCHIP_PIC_MASTER;
entry.u.irqchip.pin = gsi;
}
assert_eq!(hash_key(&entry), 0x0001_0000_0004);
}
}
67 changes: 67 additions & 0 deletions src/interrupt/kvm/msi_irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,70 @@ pub(super) fn create_msi_routing_entries(
}
Ok(entries)
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_create_msiconfig() {
let config = MsiConfig::new();
config.irqfd.write(1).unwrap();
}

#[test]
fn test_new_msi_routing_single() {
let test_gsi = 4;
let msi_source_config = MsiIrqSourceConfig {
high_addr: 0x1234,
low_addr: 0x5678,
data: 0x9876,
};
let entry = new_msi_routing_entry(test_gsi, &msi_source_config);
assert_eq!(entry.gsi, test_gsi);
assert_eq!(entry.type_, KVM_IRQ_ROUTING_MSI);
unsafe {
assert_eq!(entry.u.msi.address_hi, msi_source_config.high_addr);
assert_eq!(entry.u.msi.address_lo, msi_source_config.low_addr);
assert_eq!(entry.u.msi.data, msi_source_config.data);
}
}

#[cfg(all(
feature = "legacy_irq",
any(target_arch = "x86", target_arch = "x86_64")
))]
#[test]
fn test_new_msi_routing_multi() {
let mut msi_fds = Vec::with_capacity(16);
for _ in 0..16 {
msi_fds.push(InterruptSourceConfig::MsiIrq(MsiIrqSourceConfig {
high_addr: 0x1234,
low_addr: 0x5678,
data: 0x9876,
}));
}
let mut legacy_fds = Vec::with_capacity(16);
for _ in 0..16 {
legacy_fds.push(InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {}));
}

let base = 0;
let entrys = create_msi_routing_entries(0, &msi_fds).unwrap();

for (i, entry) in entrys.iter().enumerate() {
assert_eq!(entry.gsi, (base + i) as u32);
assert_eq!(entry.type_, KVM_IRQ_ROUTING_MSI);
if let InterruptSourceConfig::MsiIrq(config) = &msi_fds[i] {
unsafe {
assert_eq!(entry.u.msi.address_hi, config.high_addr);
assert_eq!(entry.u.msi.address_lo, config.low_addr);
assert_eq!(entry.u.msi.data, config.data);
}
}
}

assert!(create_msi_routing_entries(0, &legacy_fds).is_err());
assert!(create_msi_routing_entries(!0, &msi_fds).is_err());
}
}
90 changes: 90 additions & 0 deletions src/interrupt/kvm/pci_msi_irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,93 @@ impl InterruptSourceGroup for PciMsiIrq {
Ok(())
}
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[cfg(test)]
mod test {
use super::*;
use kvm_ioctls::{Kvm, VmFd};

fn create_vm_fd() -> VmFd {
let kvm = Kvm::new().unwrap();
kvm.create_vm().unwrap()
}

#[test]
#[allow(unreachable_patterns)]
fn test_msi_interrupt_group() {
let vmfd = Arc::new(create_vm_fd());
assert!(vmfd.create_irq_chip().is_ok());

let rounting = Arc::new(KvmIrqRouting::new(vmfd.clone()));
assert!(rounting.initialize().is_ok());

let base = 168;
let count = 32;
let group = PciMsiIrq::new(
base,
count,
DEFAULT_MAX_MSI_IRQS_PER_DEVICE,
vmfd.clone(),
rounting.clone(),
)
.unwrap();
let mut msi_fds = Vec::with_capacity(count as usize);

match group.interrupt_type() {
InterruptSourceType::PciMsiIrq => {}
_ => {
panic!();
}
}

for _ in 0..count {
let msi_source_config = MsiIrqSourceConfig {
high_addr: 0x1234,
low_addr: 0x5678,
data: 0x9876,
};
msi_fds.push(InterruptSourceConfig::MsiIrq(msi_source_config));
}

assert!(group.enable(&msi_fds).is_ok());
assert_eq!(group.len(), count);
assert_eq!(group.base(), base);

for i in 0..count {
let msi_source_config = MsiIrqSourceConfig {
high_addr: i + 0x1234,
low_addr: i + 0x5678,
data: i + 0x9876,
};
assert!(group.irqfd(i).unwrap().write(1).is_ok());
assert!(group.trigger(i, 0x168).is_err());
assert!(group.trigger(i, 0).is_ok());
assert!(group.ack(i, 0x168).is_err());
assert!(group.ack(i, 0).is_ok());
assert!(group
.update(0, &InterruptSourceConfig::MsiIrq(msi_source_config))
.is_ok());
}
assert!(group.trigger(33, 0x168).is_err());
assert!(group.ack(33, 0x168).is_err());
assert!(group.disable().is_ok());

assert!(PciMsiIrq::new(
base,
DEFAULT_MAX_MSI_IRQS_PER_DEVICE + 1,
DEFAULT_MAX_MSI_IRQS_PER_DEVICE,
vmfd.clone(),
rounting.clone()
)
.is_err());
assert!(PciMsiIrq::new(
1100,
1,
DEFAULT_MAX_MSI_IRQS_PER_DEVICE,
vmfd.clone(),
rounting.clone()
)
.is_err());
}
}

0 comments on commit b4180eb

Please sign in to comment.