Skip to content

Commit b2d445a

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

File tree

5 files changed

+362
-1
lines changed

5 files changed

+362
-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": 79.9,
2+
"coverage_score": 79.2,
33
"exclude_path": "",
44
"crate_features": ""
55
}

src/interrupt/kvm/legacy_irq.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,53 @@ impl InterruptSourceGroup for LegacyIrq {
176176
Ok(())
177177
}
178178
}
179+
180+
#[cfg(test)]
181+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
182+
mod test {
183+
use super::*;
184+
use kvm_ioctls::{Kvm, VmFd};
185+
186+
fn create_vm_fd() -> VmFd {
187+
let kvm = Kvm::new().unwrap();
188+
kvm.create_vm().unwrap()
189+
}
190+
191+
#[test]
192+
#[allow(unreachable_patterns)]
193+
fn test_legacy_interrupt_group() {
194+
let vmfd = Arc::new(create_vm_fd());
195+
let rounting = Arc::new(KvmIrqRouting::new(vmfd.clone()));
196+
let base = 0;
197+
let count = 1;
198+
let group = LegacyIrq::new(base, count, vmfd.clone(), rounting.clone()).unwrap();
199+
200+
let mut legacy_fds = Vec::with_capacity(1);
201+
legacy_fds.push(InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {}));
202+
203+
match group.interrupt_type() {
204+
InterruptSourceType::LegacyIrq => {}
205+
_ => {
206+
panic!();
207+
}
208+
}
209+
assert_eq!(group.len(), 1);
210+
assert_eq!(group.base(), base);
211+
assert!(group.enable(&legacy_fds).is_ok());
212+
assert!(group.irqfd(0).unwrap().write(1).is_ok());
213+
assert!(group.trigger(0, 0x168).is_ok());
214+
assert!(group.ack(0, 0x168).is_ok());
215+
assert!(group.trigger(1, 0x168).is_err());
216+
assert!(group.ack(1, 0x168).is_err());
217+
assert!(group
218+
.update(
219+
0,
220+
&InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {})
221+
)
222+
.is_ok());
223+
assert!(group.disable().is_ok());
224+
225+
assert!(LegacyIrq::new(base, 2, vmfd.clone(), rounting.clone()).is_err());
226+
assert!(LegacyIrq::new(110, 1, vmfd.clone(), rounting.clone()).is_err());
227+
}
228+
}

src/interrupt/kvm/mod.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,157 @@ impl KvmIrqRouting {
237237
self.set_routing(&routes)
238238
}
239239
}
240+
241+
#[cfg(any(target = "x86", target = "x86_64"))]
242+
#[cfg(test)]
243+
mod test {
244+
use super::*;
245+
use kvm_ioctls::{Kvm, VmFd};
246+
247+
//const VFIO_PCI_MSI_IRQ_INDEX: u32 = 1;
248+
249+
fn create_vm_fd() -> VmFd {
250+
let kvm = Kvm::new().unwrap();
251+
kvm.create_vm().unwrap()
252+
}
253+
254+
fn create_irq_group(
255+
manager: Arc<KvmIrqManager>,
256+
_vmfd: Arc<VmFd>,
257+
) -> Arc<Box<dyn InterruptSourceGroup>> {
258+
let base = 0;
259+
let count = 1;
260+
261+
manager
262+
.create_group(InterruptSourceType::LegacyIrq, base, count)
263+
.unwrap()
264+
}
265+
266+
fn create_msi_group(
267+
manager: Arc<KvmIrqManager>,
268+
_vmfd: Arc<VmFd>,
269+
) -> Arc<Box<dyn InterruptSourceGroup>> {
270+
let base = 168;
271+
let count = 32;
272+
273+
manager
274+
.create_group(InterruptSourceType::MsiIrq, base, count)
275+
.unwrap()
276+
}
277+
278+
const MASTER_PIC: usize = 7;
279+
const SLAVE_PIC: usize = 8;
280+
const IOAPIC: usize = 23;
281+
282+
#[test]
283+
fn test_create_kvmirqmanager() {
284+
let vmfd = Arc::new(create_vm_fd());
285+
let manager = KvmIrqManager::new(vmfd.clone());
286+
assert!(vmfd.create_irq_chip().is_ok());
287+
assert!(manager.initialize().is_ok());
288+
}
289+
290+
#[test]
291+
fn test_kvmirqmanager_opt() {
292+
let vmfd = Arc::new(create_vm_fd());
293+
assert!(vmfd.create_irq_chip().is_ok());
294+
let manager = Arc::new(KvmIrqManager::new(vmfd.clone()));
295+
assert!(manager.initialize().is_ok());
296+
//irq
297+
let group = create_irq_group(manager.clone(), vmfd.clone());
298+
let _ = group.clone();
299+
assert!(manager.destroy_group(group).is_ok());
300+
//msi
301+
let group = create_msi_group(manager.clone(), vmfd.clone());
302+
let _ = group.clone();
303+
assert!(manager.destroy_group(group).is_ok());
304+
}
305+
306+
#[test]
307+
fn test_irqrouting_initialize_legacy() {
308+
let vmfd = Arc::new(create_vm_fd());
309+
let routing = KvmIrqRouting::new(vmfd.clone());
310+
assert!(routing.initialize().is_err());
311+
assert!(vmfd.create_irq_chip().is_ok());
312+
assert!(routing.initialize().is_ok());
313+
let routes = &routing.routes.lock().unwrap();
314+
assert_eq!(routes.len(), MASTER_PIC + SLAVE_PIC + IOAPIC);
315+
}
316+
317+
#[test]
318+
fn test_routing_opt() {
319+
// pub(super) fn modify(&self, entry: &kvm_irq_routing_entry) -> Result<()> {
320+
let vmfd = Arc::new(create_vm_fd());
321+
let routing = KvmIrqRouting::new(vmfd.clone());
322+
assert!(routing.initialize().is_err());
323+
assert!(vmfd.create_irq_chip().is_ok());
324+
assert!(routing.initialize().is_ok());
325+
326+
let mut entry = kvm_irq_routing_entry {
327+
gsi: 8,
328+
type_: KVM_IRQ_ROUTING_IRQCHIP,
329+
..Default::default()
330+
};
331+
332+
// Safe because we are initializing all fields of the `irqchip` struct.
333+
unsafe {
334+
entry.u.irqchip.irqchip = 0;
335+
entry.u.irqchip.pin = 3;
336+
}
337+
338+
let entrys = vec![entry.clone()];
339+
340+
assert!(routing.modify(&entry).is_err());
341+
assert!(routing.add(&entrys).is_ok());
342+
unsafe {
343+
entry.u.irqchip.pin = 4;
344+
}
345+
assert!(routing.modify(&entry).is_ok());
346+
assert!(routing.remove(&entrys).is_ok());
347+
assert!(routing.modify(&entry).is_err());
348+
}
349+
350+
#[test]
351+
fn test_routing_commit() {
352+
let vmfd = Arc::new(create_vm_fd());
353+
let routing = KvmIrqRouting::new(vmfd.clone());
354+
355+
assert!(routing.initialize().is_err());
356+
assert!(vmfd.create_irq_chip().is_ok());
357+
assert!(routing.initialize().is_ok());
358+
359+
let mut entry = kvm_irq_routing_entry {
360+
gsi: 8,
361+
type_: KVM_IRQ_ROUTING_IRQCHIP,
362+
..Default::default()
363+
};
364+
unsafe {
365+
entry.u.irqchip.irqchip = 0;
366+
entry.u.irqchip.pin = 3;
367+
}
368+
369+
routing
370+
.routes
371+
.lock()
372+
.unwrap()
373+
.insert(hash_key(&entry), entry);
374+
let routes = routing.routes.lock().unwrap();
375+
assert!(routing.commit(&routes).is_ok());
376+
}
377+
378+
#[test]
379+
fn test_has_key() {
380+
let gsi = 4;
381+
let mut entry = kvm_irq_routing_entry {
382+
gsi,
383+
type_: KVM_IRQ_ROUTING_IRQCHIP,
384+
..Default::default()
385+
};
386+
// Safe because we are initializing all fields of the `irqchip` struct.
387+
unsafe {
388+
entry.u.irqchip.irqchip = KVM_IRQCHIP_PIC_MASTER;
389+
entry.u.irqchip.pin = gsi;
390+
}
391+
assert_eq!(hash_key(&entry), 0x0001_0000_0004);
392+
}
393+
}

src/interrupt/kvm/msi_irq.rs

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

src/interrupt/kvm/pci_msi_irq.rs

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

0 commit comments

Comments
 (0)