Skip to content

Commit 34393fe

Browse files
juliusxlhjiangliu
authored andcommitted
Add unit tests for interrupt manager
Signed-off-by: 守情 <[email protected]>
1 parent 5559e26 commit 34393fe

File tree

4 files changed

+344
-0
lines changed

4 files changed

+344
-0
lines changed

src/interrupt/kvm_irq/legacy_irq.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,52 @@ impl InterruptSourceGroup for LegacyIrq {
115115
}
116116
}
117117
}
118+
119+
#[cfg(test)]
120+
mod test {
121+
use super::*;
122+
use kvm_ioctls::{Kvm, VmFd};
123+
124+
fn create_vm_fd() -> VmFd {
125+
let kvm = Kvm::new().unwrap();
126+
kvm.create_vm().unwrap()
127+
}
128+
129+
#[test]
130+
#[allow(unreachable_patterns)]
131+
fn test_legacy_interrupt_group() {
132+
let vmfd = Arc::new(create_vm_fd());
133+
let rounting = Arc::new(KvmIrqRouting::new(vmfd.clone()));
134+
let base = 0;
135+
let count = 1;
136+
let group = LegacyIrq::new(base, count, vmfd.clone(), rounting.clone()).unwrap();
137+
138+
let mut legacy_fds = Vec::with_capacity(1);
139+
legacy_fds.push(InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {}));
140+
141+
match group.get_type() {
142+
InterruptSourceType::LegacyIrq => {}
143+
_ => {
144+
panic!();
145+
}
146+
}
147+
assert_eq!(group.len(), 1);
148+
assert_eq!(group.get_base(), base);
149+
assert!(group.enable(&legacy_fds).is_ok());
150+
assert!(group.get_irqfd(0).unwrap().write(1).is_ok());
151+
assert!(group.trigger(0, 0x168).is_ok());
152+
assert!(group.ack(0, 0x168).is_ok());
153+
assert!(group.trigger(1, 0x168).is_err());
154+
assert!(group.ack(1, 0x168).is_err());
155+
assert!(group
156+
.modify(
157+
0,
158+
&InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {})
159+
)
160+
.is_ok());
161+
assert!(group.disable().is_ok());
162+
163+
assert!(LegacyIrq::new(base, 2, vmfd.clone(), rounting.clone()).is_err());
164+
assert!(LegacyIrq::new(110, 1, vmfd.clone(), rounting.clone()).is_err());
165+
}
166+
}

src/interrupt/kvm_irq/mod.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,157 @@ impl KvmIrqRouting {
300300
Ok(())
301301
}
302302
}
303+
304+
#[cfg(any(target = "x86", target = "x86_64"))]
305+
#[cfg(test)]
306+
mod test {
307+
use super::*;
308+
use kvm_ioctls::{Kvm, VmFd};
309+
310+
//const VFIO_PCI_MSI_IRQ_INDEX: u32 = 1;
311+
312+
fn create_vm_fd() -> VmFd {
313+
let kvm = Kvm::new().unwrap();
314+
kvm.create_vm().unwrap()
315+
}
316+
317+
fn create_irq_group(
318+
manager: Arc<KvmIrqManager>,
319+
_vmfd: Arc<VmFd>,
320+
) -> Arc<Box<dyn InterruptSourceGroup>> {
321+
let base = 0;
322+
let count = 1;
323+
324+
manager
325+
.create_group(InterruptSourceType::LegacyIrq, base, count)
326+
.unwrap()
327+
}
328+
329+
fn create_msi_group(
330+
manager: Arc<KvmIrqManager>,
331+
_vmfd: Arc<VmFd>,
332+
) -> Arc<Box<dyn InterruptSourceGroup>> {
333+
let base = 168;
334+
let count = 32;
335+
336+
manager
337+
.create_group(InterruptSourceType::MsiIrq, base, count)
338+
.unwrap()
339+
}
340+
341+
const MASTER_PIC: usize = 7;
342+
const SLAVE_PIC: usize = 8;
343+
const IOAPIC: usize = 23;
344+
345+
#[test]
346+
fn test_create_kvmirqmanager() {
347+
let vmfd = Arc::new(create_vm_fd());
348+
let manager = KvmIrqManager::new(vmfd.clone());
349+
assert!(vmfd.create_irq_chip().is_ok());
350+
assert!(manager.initialize().is_ok());
351+
}
352+
353+
#[test]
354+
fn test_kvmirqmanager_opt() {
355+
let vmfd = Arc::new(create_vm_fd());
356+
assert!(vmfd.create_irq_chip().is_ok());
357+
let manager = Arc::new(KvmIrqManager::new(vmfd.clone()));
358+
assert!(manager.initialize().is_ok());
359+
//irq
360+
let group = create_irq_group(manager.clone(), vmfd.clone());
361+
let _ = group.clone();
362+
assert!(manager.destroy_group(group).is_ok());
363+
//msi
364+
let group = create_msi_group(manager.clone(), vmfd.clone());
365+
let _ = group.clone();
366+
assert!(manager.destroy_group(group).is_ok());
367+
}
368+
369+
#[test]
370+
fn test_irqrouting_initialize_legacy() {
371+
let vmfd = Arc::new(create_vm_fd());
372+
let routing = KvmIrqRouting::new(vmfd.clone());
373+
assert!(routing.initialize().is_err());
374+
assert!(vmfd.create_irq_chip().is_ok());
375+
assert!(routing.initialize().is_ok());
376+
let routes = &routing.routes.lock().unwrap();
377+
assert_eq!(routes.len(), MASTER_PIC + SLAVE_PIC + IOAPIC);
378+
}
379+
380+
#[test]
381+
fn test_routing_opt() {
382+
// pub(super) fn modify(&self, entry: &kvm_irq_routing_entry) -> Result<()> {
383+
let vmfd = Arc::new(create_vm_fd());
384+
let routing = KvmIrqRouting::new(vmfd.clone());
385+
assert!(routing.initialize().is_err());
386+
assert!(vmfd.create_irq_chip().is_ok());
387+
assert!(routing.initialize().is_ok());
388+
389+
let mut entry = kvm_irq_routing_entry {
390+
gsi: 8,
391+
type_: KVM_IRQ_ROUTING_IRQCHIP,
392+
..Default::default()
393+
};
394+
395+
// Safe because we are initializing all fields of the `irqchip` struct.
396+
unsafe {
397+
entry.u.irqchip.irqchip = 0;
398+
entry.u.irqchip.pin = 3;
399+
}
400+
401+
let entrys = vec![entry.clone()];
402+
403+
assert!(routing.modify(&entry).is_err());
404+
assert!(routing.add(&entrys).is_ok());
405+
unsafe {
406+
entry.u.irqchip.pin = 4;
407+
}
408+
assert!(routing.modify(&entry).is_ok());
409+
assert!(routing.remove(&entrys).is_ok());
410+
assert!(routing.modify(&entry).is_err());
411+
}
412+
413+
#[test]
414+
fn test_routing_commit() {
415+
let vmfd = Arc::new(create_vm_fd());
416+
let routing = KvmIrqRouting::new(vmfd.clone());
417+
418+
assert!(routing.initialize().is_err());
419+
assert!(vmfd.create_irq_chip().is_ok());
420+
assert!(routing.initialize().is_ok());
421+
422+
let mut entry = kvm_irq_routing_entry {
423+
gsi: 8,
424+
type_: KVM_IRQ_ROUTING_IRQCHIP,
425+
..Default::default()
426+
};
427+
unsafe {
428+
entry.u.irqchip.irqchip = 0;
429+
entry.u.irqchip.pin = 3;
430+
}
431+
432+
routing
433+
.routes
434+
.lock()
435+
.unwrap()
436+
.insert(hash_key(&entry), entry);
437+
let routes = routing.routes.lock().unwrap();
438+
assert!(routing.commit(&routes).is_ok());
439+
}
440+
441+
#[test]
442+
fn test_has_key() {
443+
let gsi = 4;
444+
let mut entry = kvm_irq_routing_entry {
445+
gsi,
446+
type_: KVM_IRQ_ROUTING_IRQCHIP,
447+
..Default::default()
448+
};
449+
// Safe because we are initializing all fields of the `irqchip` struct.
450+
unsafe {
451+
entry.u.irqchip.irqchip = KVM_IRQCHIP_PIC_MASTER;
452+
entry.u.irqchip.pin = gsi;
453+
}
454+
assert_eq!(hash_key(&entry), 0x0001_0000_0004);
455+
}
456+
}

src/interrupt/kvm_irq/msi_irq.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,70 @@ pub(super) fn create_msi_routing_entries(
5757
}
5858
Ok(entries)
5959
}
60+
61+
#[cfg(test)]
62+
mod test {
63+
use super::*;
64+
65+
#[test]
66+
fn test_create_msiconfig() {
67+
let config = MsiConfig::new();
68+
config.irqfd.write(1).unwrap();
69+
}
70+
71+
#[test]
72+
fn test_new_msi_routing_single() {
73+
let test_gsi = 4;
74+
let msi_source_config = MsiIrqSourceConfig {
75+
high_addr: 0x1234,
76+
low_addr: 0x5678,
77+
data: 0x9876,
78+
};
79+
let entry = new_msi_routing_entry(test_gsi, &msi_source_config);
80+
assert_eq!(entry.gsi, test_gsi);
81+
assert_eq!(entry.type_, KVM_IRQ_ROUTING_MSI);
82+
unsafe {
83+
assert_eq!(entry.u.msi.address_hi, msi_source_config.high_addr);
84+
assert_eq!(entry.u.msi.address_lo, msi_source_config.low_addr);
85+
assert_eq!(entry.u.msi.data, msi_source_config.data);
86+
}
87+
}
88+
89+
#[cfg(all(
90+
feature = "legacy_irq",
91+
any(target_arch = "x86", target_arch = "x86_64")
92+
))]
93+
#[test]
94+
fn test_new_msi_routing_multi() {
95+
let mut msi_fds = Vec::with_capacity(16);
96+
for _ in 0..16 {
97+
msi_fds.push(InterruptSourceConfig::MsiIrq(MsiIrqSourceConfig {
98+
high_addr: 0x1234,
99+
low_addr: 0x5678,
100+
data: 0x9876,
101+
}));
102+
}
103+
let mut legacy_fds = Vec::with_capacity(16);
104+
for _ in 0..16 {
105+
legacy_fds.push(InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {}));
106+
}
107+
108+
let base = 0;
109+
let entrys = create_msi_routing_entries(0, &msi_fds).unwrap();
110+
111+
for (i, entry) in entrys.iter().enumerate() {
112+
assert_eq!(entry.gsi, (base + i) as u32);
113+
assert_eq!(entry.type_, KVM_IRQ_ROUTING_MSI);
114+
if let InterruptSourceConfig::MsiIrq(config) = &msi_fds[i] {
115+
unsafe {
116+
assert_eq!(entry.u.msi.address_hi, config.high_addr);
117+
assert_eq!(entry.u.msi.address_lo, config.low_addr);
118+
assert_eq!(entry.u.msi.data, config.data);
119+
}
120+
}
121+
}
122+
123+
assert!(create_msi_routing_entries(0, &legacy_fds).is_err());
124+
assert!(create_msi_routing_entries(!0, &msi_fds).is_err());
125+
}
126+
}

src/interrupt/kvm_irq/pci_msi_irq.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,77 @@ impl InterruptSourceGroup for PciMsiIrq {
146146
Ok(())
147147
}
148148
}
149+
150+
#[cfg(test)]
151+
mod test {
152+
use super::*;
153+
use kvm_ioctls::{Kvm, VmFd};
154+
155+
fn create_vm_fd() -> VmFd {
156+
let kvm = Kvm::new().unwrap();
157+
kvm.create_vm().unwrap()
158+
}
159+
160+
#[test]
161+
#[allow(unreachable_patterns)]
162+
fn test_msi_interrupt_group() {
163+
let vmfd = Arc::new(create_vm_fd());
164+
assert!(vmfd.create_irq_chip().is_ok());
165+
166+
let rounting = Arc::new(KvmIrqRouting::new(vmfd.clone()));
167+
assert!(rounting.initialize().is_ok());
168+
169+
let base = 168;
170+
let count = 32;
171+
let group = PciMsiIrq::new(base, count, vmfd.clone(), rounting.clone()).unwrap();
172+
let mut msi_fds = Vec::with_capacity(count as usize);
173+
174+
match group.get_type() {
175+
InterruptSourceType::MsiIrq => {}
176+
_ => {
177+
panic!();
178+
}
179+
}
180+
181+
for _ in 0..count {
182+
let msi_source_config = MsiIrqSourceConfig {
183+
high_addr: 0x1234,
184+
low_addr: 0x5678,
185+
data: 0x9876,
186+
};
187+
msi_fds.push(InterruptSourceConfig::MsiIrq(msi_source_config));
188+
}
189+
190+
assert!(group.enable(&msi_fds).is_ok());
191+
assert_eq!(group.len(), count);
192+
assert_eq!(group.get_base(), base);
193+
194+
for i in 0..count {
195+
let msi_source_config = MsiIrqSourceConfig {
196+
high_addr: i + 0x1234,
197+
low_addr: i + 0x5678,
198+
data: i + 0x9876,
199+
};
200+
assert!(group.get_irqfd(i).unwrap().write(1).is_ok());
201+
assert!(group.trigger(i, 0x168).is_err());
202+
assert!(group.trigger(i, 0).is_ok());
203+
assert!(group.ack(i, 0x168).is_err());
204+
assert!(group.ack(i, 0).is_ok());
205+
assert!(group
206+
.modify(0, &InterruptSourceConfig::MsiIrq(msi_source_config))
207+
.is_ok());
208+
}
209+
assert!(group.trigger(33, 0x168).is_err());
210+
assert!(group.ack(33, 0x168).is_err());
211+
assert!(group.disable().is_ok());
212+
213+
assert!(PciMsiIrq::new(
214+
base,
215+
MAX_MSI_IRQS_PER_DEVICE + 1,
216+
vmfd.clone(),
217+
rounting.clone()
218+
)
219+
.is_err());
220+
assert!(PciMsiIrq::new(1100, 1, vmfd.clone(), rounting.clone()).is_err());
221+
}
222+
}

0 commit comments

Comments
 (0)