Skip to content

Commit eefb5ff

Browse files
juliusxlhjiangliu
authored andcommitted
Add unit tests for interrupt manager
Signed-off-by: 守情 <liheng.xlh@alibaba-inc.com>
1 parent dad695e commit eefb5ff

File tree

5 files changed

+361
-1
lines changed

5 files changed

+361
-1
lines changed

coverage_config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 75.8,
2+
"coverage_score": 74.3,
33
"exclude_path": "",
44
"crate_features": ""
55
}

src/interrupt/kvm/legacy_irq.rs

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

src/interrupt/kvm/mod.rs

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

src/interrupt/kvm/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/pci_msi_irq.rs

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

0 commit comments

Comments
 (0)