Skip to content

Commit c2cafa6

Browse files
committed
struct to describe resource allocation constraints
Add ResourceConstraint enum to describe devices's resource allocation constraints, so we could build better flow among the VMM, the device manager and the device object. Signed-off-by: Liu Jiang <[email protected]> Signed-off-by: 守情 <[email protected]> Signed-off-by: Samuel Ortiz <[email protected]>
1 parent dd4d9d8 commit c2cafa6

File tree

2 files changed

+276
-1
lines changed

2 files changed

+276
-1
lines changed

coverage_config.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 0,
2+
"coverage_score": 75.8,
33
"exclude_path": "",
44
"crate_features": ""
55
}

src/resources.rs

+275
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,110 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
//! Structs to manage device resources.
5+
//!
6+
//! The high level flow of resource management among the VMM, the device manager, and the device
7+
//! is as below:
8+
//! 1) the VMM creates a new device object.
9+
//! 2) the VMM asks the new device object for its resource constraints.
10+
//! 3) the VMM allocates resources for the device object according to resource constraints.
11+
//! 4) the VMM passes the allocated resources to the device object.
12+
//! 5) the VMM registers the new device onto corresponding device managers according the allocated
13+
//! resources.
14+
15+
use std::{u16, u32, u64};
16+
17+
/// Enumeration describing a device's resource constraints.
18+
pub enum ResourceConstraint {
19+
/// Constraint for an IO Port address range.
20+
PioAddress {
21+
/// Allocating resource within the range [`min`, `max`] if specified.
22+
range: Option<(u16, u16)>,
23+
/// Alignment for the allocated address.
24+
align: u16,
25+
/// Size for the allocated address range.
26+
size: u16,
27+
},
28+
/// Constraint for a Memory Mapped IO address range.
29+
MmioAddress {
30+
/// Allocating resource within the range [`min`, `max`] if specified.
31+
range: Option<(u64, u64)>,
32+
/// Alignment for the allocated address.
33+
align: u64,
34+
/// Size for the allocated address range.
35+
size: u64,
36+
},
37+
/// Constraint for a legacy IRQ.
38+
LegacyIrq {
39+
/// Reserving the pre-allocated IRQ if it's specified.
40+
irq: Option<u32>,
41+
},
42+
/// Constraint for PCI MSI IRQs.
43+
PciMsiIrq {
44+
/// Number of Irqs to allocate.
45+
size: u32,
46+
},
47+
/// Constraint for PCI MSIx IRQs.
48+
PciMsixIrq {
49+
/// Number of Irqs to allocate.
50+
size: u32,
51+
},
52+
/// Constraint for generic IRQs.
53+
GenericIrq {
54+
/// Number of Irqs to allocate.
55+
size: u32,
56+
},
57+
/// Constraint for KVM mem_slot indexes to map memory into the guest.
58+
KvmMemSlot {
59+
/// Allocating kvm memory slots starting from the index `slot` if specified.
60+
slot: Option<u32>,
61+
/// Number of slots to allocate.
62+
size: u32,
63+
},
64+
}
65+
66+
impl ResourceConstraint {
67+
/// Create a new PIO address constraint object with default configuration.
68+
pub fn new_pio(size: u16) -> Self {
69+
ResourceConstraint::PioAddress {
70+
range: None,
71+
align: 0x1,
72+
size,
73+
}
74+
}
75+
76+
/// Create a new PIO address constraint object.
77+
pub fn pio_with_constraints(size: u16, range: Option<(u16, u16)>, align: u16) -> Self {
78+
ResourceConstraint::PioAddress { range, align, size }
79+
}
80+
81+
/// Create a new MMIO address constraint object with default configuration.
82+
pub fn new_mmio(size: u64) -> Self {
83+
ResourceConstraint::MmioAddress {
84+
range: None,
85+
align: 0x1000,
86+
size,
87+
}
88+
}
89+
90+
/// Create a new MMIO address constraint object.
91+
pub fn mmio_with_constraints(size: u64, range: Option<(u64, u64)>, align: u64) -> Self {
92+
ResourceConstraint::MmioAddress { range, align, size }
93+
}
94+
95+
/// Create a new legacy IRQ constraint object.
96+
///
97+
/// Allocating the pre-allocated legacy Irq `irq` if specified.
98+
pub fn new_legacy_irq(irq: Option<u32>) -> Self {
99+
ResourceConstraint::LegacyIrq { irq }
100+
}
101+
102+
/// Create a new KVM memory slot constraint object.
103+
///
104+
/// Allocating kvm memory slots starting from the index `slot` if specified.
105+
pub fn new_kvm_mem_slot(size: u32, slot: Option<u32>) -> Self {
106+
ResourceConstraint::KvmMemSlot { slot, size }
107+
}
108+
}
5109

6110
/// Type of Message Singaled Interrupt
7111
#[derive(Copy, Clone, PartialEq)]
@@ -140,3 +244,174 @@ impl DeviceResources {
140244
&self.0
141245
}
142246
}
247+
248+
#[cfg(test)]
249+
mod tests {
250+
use super::*;
251+
252+
const PIO_ADDRESS_SIZE: u16 = 5;
253+
const PIO_ADDRESS_BASE: u16 = 0;
254+
const MMIO_ADDRESS_SIZE: u64 = 0x8765_4321;
255+
const MMIO_ADDRESS_BASE: u64 = 0x1234_5678;
256+
const LEGACY_IRQ: u32 = 0x168;
257+
const PCI_MSI_IRQ_SIZE: u32 = 0x8888;
258+
const PCI_MSI_IRQ_BASE: u32 = 0x6666;
259+
const PCI_MSIX_IRQ_SIZE: u32 = 0x16666;
260+
const PCI_MSIX_IRQ_BASE: u32 = 0x8888;
261+
const GENERIC_MSI_IRQS_SIZE: u32 = 0x16888;
262+
const GENERIC_MSI_IRQS_BASE: u32 = 0x16688;
263+
const MAC_ADDRESS: &str = "00:08:63:66:86:88";
264+
const KVM_SLOT_ID: u32 = 0x0100;
265+
266+
fn get_device_resource() -> DeviceResources {
267+
let entry = Resource::PioAddressRange {
268+
base: PIO_ADDRESS_BASE,
269+
size: PIO_ADDRESS_SIZE,
270+
};
271+
let mut resource = DeviceResources::new();
272+
resource.append(entry);
273+
let entry = Resource::MmioAddressRange {
274+
base: MMIO_ADDRESS_BASE,
275+
size: MMIO_ADDRESS_SIZE,
276+
};
277+
resource.append(entry);
278+
let entry = Resource::LegacyIrq(LEGACY_IRQ);
279+
resource.append(entry);
280+
let entry = Resource::MsiIrq {
281+
ty: MsiIrqType::PciMsi,
282+
base: PCI_MSI_IRQ_BASE,
283+
size: PCI_MSI_IRQ_SIZE,
284+
};
285+
resource.append(entry);
286+
let entry = Resource::MsiIrq {
287+
ty: MsiIrqType::PciMsix,
288+
base: PCI_MSIX_IRQ_BASE,
289+
size: PCI_MSIX_IRQ_SIZE,
290+
};
291+
resource.append(entry);
292+
let entry = Resource::MsiIrq {
293+
ty: MsiIrqType::GenericMsi,
294+
base: GENERIC_MSI_IRQS_BASE,
295+
size: GENERIC_MSI_IRQS_SIZE,
296+
};
297+
resource.append(entry);
298+
let entry = Resource::MacAddresss(MAC_ADDRESS.to_string());
299+
resource.append(entry);
300+
301+
resource.append(Resource::KvmMemSlot(KVM_SLOT_ID));
302+
303+
resource
304+
}
305+
306+
#[test]
307+
fn get_pio_address_ranges() {
308+
let resources = get_device_resource();
309+
assert!(
310+
resources.get_pio_address_ranges()[0].0 == PIO_ADDRESS_BASE
311+
&& resources.get_pio_address_ranges()[0].1 == PIO_ADDRESS_SIZE
312+
);
313+
}
314+
315+
#[test]
316+
fn test_get_mmio_address_ranges() {
317+
let resources = get_device_resource();
318+
assert!(
319+
resources.get_mmio_address_ranges()[0].0 == MMIO_ADDRESS_BASE
320+
&& resources.get_mmio_address_ranges()[0].1 == MMIO_ADDRESS_SIZE
321+
);
322+
}
323+
324+
#[test]
325+
fn test_get_legacy_irq() {
326+
let resources = get_device_resource();
327+
assert!(resources.get_legacy_irq().unwrap() == LEGACY_IRQ);
328+
}
329+
330+
#[test]
331+
fn test_get_pci_msi_irqs() {
332+
let resources = get_device_resource();
333+
assert!(
334+
resources.get_pci_msi_irqs().unwrap().0 == PCI_MSI_IRQ_BASE
335+
&& resources.get_pci_msi_irqs().unwrap().1 == PCI_MSI_IRQ_SIZE
336+
);
337+
}
338+
339+
#[test]
340+
fn test_pci_msix_irqs() {
341+
let resources = get_device_resource();
342+
assert!(
343+
resources.get_pci_msix_irqs().unwrap().0 == PCI_MSIX_IRQ_BASE
344+
&& resources.get_pci_msix_irqs().unwrap().1 == PCI_MSIX_IRQ_SIZE
345+
);
346+
}
347+
348+
#[test]
349+
fn test_get_generic_msi_irqs() {
350+
let resources = get_device_resource();
351+
assert!(
352+
resources.get_generic_msi_irqs().unwrap().0 == GENERIC_MSI_IRQS_BASE
353+
&& resources.get_generic_msi_irqs().unwrap().1 == GENERIC_MSI_IRQS_SIZE
354+
);
355+
}
356+
357+
#[test]
358+
fn test_get_mac_address() {
359+
let resources = get_device_resource();
360+
assert_eq!(resources.get_mac_address().unwrap(), MAC_ADDRESS);
361+
}
362+
363+
#[test]
364+
fn test_get_kvm_slot() {
365+
let resources = get_device_resource();
366+
assert_eq!(resources.get_kvm_mem_slots(), vec![KVM_SLOT_ID]);
367+
}
368+
369+
#[test]
370+
fn test_get_all_resources() {
371+
let resources = get_device_resource();
372+
assert_eq!(resources.get_all_resources().len(), 8);
373+
}
374+
375+
#[test]
376+
fn test_resource_constraint() {
377+
if let ResourceConstraint::PioAddress { range, align, size } =
378+
ResourceConstraint::new_pio(2)
379+
{
380+
assert_eq!(range, None);
381+
assert_eq!(align, 1);
382+
assert_eq!(size, 2);
383+
} else {
384+
panic!("Pio resource constraint is invalid.");
385+
}
386+
387+
if let ResourceConstraint::PioAddress { range, align, size } =
388+
ResourceConstraint::pio_with_constraints(2, Some((15, 16)), 2)
389+
{
390+
assert_eq!(range, Some((15, 16)));
391+
assert_eq!(align, 2);
392+
assert_eq!(size, 2);
393+
} else {
394+
panic!("Pio resource constraint is invalid.");
395+
}
396+
397+
if let ResourceConstraint::MmioAddress { range, align, size } =
398+
ResourceConstraint::new_mmio(0x2000)
399+
{
400+
assert_eq!(range, None);
401+
assert_eq!(align, 0x1000);
402+
assert_eq!(size, 0x2000);
403+
} else {
404+
panic!("Pio resource constraint is invalid.");
405+
}
406+
407+
if let ResourceConstraint::MmioAddress { range, align, size } =
408+
ResourceConstraint::mmio_with_constraints(0x2000, Some((0x0, 0x2000)), 0x2000)
409+
{
410+
assert_eq!(range, Some((0x0, 0x2000)));
411+
assert_eq!(align, 0x2000);
412+
assert_eq!(size, 0x2000);
413+
} else {
414+
panic!("Pio resource constraint is invalid.");
415+
}
416+
}
417+
}

0 commit comments

Comments
 (0)