Skip to content

Commit f3bd7b1

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

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

src/interrupt/kvm/mod.rs

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

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)