Skip to content

Commit 1014c62

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

File tree

4 files changed

+348
-0
lines changed

4 files changed

+348
-0
lines changed

src/interrupt/kvm/legacy_irq.rs

+48
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,51 @@ impl InterruptSourceGroup for LegacyIrq {
156156
self.irqfd.write(1)
157157
}
158158
}
159+
160+
#[cfg(test)]
161+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
162+
mod test {
163+
use super::*;
164+
use kvm_ioctls::{Kvm, VmFd};
165+
166+
fn create_vm_fd() -> VmFd {
167+
let kvm = Kvm::new().unwrap();
168+
kvm.create_vm().unwrap()
169+
}
170+
171+
#[test]
172+
#[allow(unreachable_patterns)]
173+
fn test_legacy_interrupt_group() {
174+
let vmfd = Arc::new(create_vm_fd());
175+
let rounting = Arc::new(KvmIrqRouting::new(vmfd.clone()));
176+
let base = 0;
177+
let count = 1;
178+
let group = LegacyIrq::new(base, count, vmfd.clone(), rounting.clone()).unwrap();
179+
180+
let mut legacy_fds = Vec::with_capacity(1);
181+
legacy_fds.push(InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {}));
182+
183+
match group.interrupt_type() {
184+
InterruptSourceType::LegacyIrq => {}
185+
_ => {
186+
panic!();
187+
}
188+
}
189+
assert_eq!(group.len(), 1);
190+
assert_eq!(group.base(), base);
191+
assert!(group.enable(&legacy_fds).is_ok());
192+
assert!(group.notifier(0).unwrap().write(1).is_ok());
193+
assert!(group.trigger(0).is_ok());
194+
assert!(group.trigger(1).is_err());
195+
assert!(group
196+
.update(
197+
0,
198+
&InterruptSourceConfig::LegacyIrq(LegacyIrqSourceConfig {})
199+
)
200+
.is_ok());
201+
assert!(group.disable().is_ok());
202+
203+
assert!(LegacyIrq::new(base, 2, vmfd.clone(), rounting.clone()).is_err());
204+
assert!(LegacyIrq::new(110, 1, vmfd, rounting).is_err());
205+
}
206+
}

src/interrupt/kvm/mod.rs

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

src/interrupt/kvm/msi_generic.rs

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

src/interrupt/kvm/msi_irq.rs

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

0 commit comments

Comments
 (0)