Skip to content

Commit 06f250b

Browse files
author
Jing Liu
committed
Add device manager support
Based on interrupt management and resources definition, this adds device manager to manage all devices registering and unregistering. Signed-off-by: Jing Liu <jing2.liu@linux.intel.com>
1 parent e0424b5 commit 06f250b

File tree

3 files changed

+179
-0
lines changed

3 files changed

+179
-0
lines changed

src/device_manager.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// Copyright © 2019 Intel Corporation. All Rights Reserved.
2+
// SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause)
3+
4+
//! System level device management.
5+
//!
6+
//! [DeviceManager](struct.DeviceManager.html) responds to manage all devices
7+
//! of virtual machine, parent bus, register IO resources callback,
8+
//! unregister devices and help VM IO exit handling.
9+
//!
10+
//!VMM would take responsible for getting device resource request, ask
11+
//! vm_allocator to allocate the resources, ask vm_device to register the
12+
//! devices, and finally set resources to virtual device.
13+
14+
use crate::resources::Resource;
15+
use crate::DeviceIo;
16+
17+
use std::collections::btree_map::BTreeMap;
18+
use std::collections::HashMap;
19+
use std::result;
20+
use std::sync::Arc;
21+
22+
/// Error type for `DeviceManager` usage.
23+
#[derive(Debug)]
24+
pub enum Error {
25+
/// The insertion failed because the new device overlapped with an old device.
26+
DeviceOverlap,
27+
/// The insertion failed because device already exists.
28+
DeviceExist,
29+
/// The removing fails because the device doesn't exist.
30+
DeviceNotExist,
31+
}
32+
33+
/// Simplify the `Result` type.
34+
pub type Result<T> = result::Result<T, Error>;
35+
36+
/// Storing Device information and for topology managing.
37+
pub struct DeviceDescriptor {
38+
/// The device to describe.
39+
pub device: Arc<dyn DeviceIo>,
40+
/// Instance id of device.
41+
pub id: u16,
42+
/// The parent bus of this device.
43+
pub parent_bus: Option<Arc<dyn DeviceIo>>,
44+
}
45+
46+
/// System device manager serving for all devices management and VM exit handling.
47+
pub struct DeviceManager {
48+
/// Devices information mapped by instance id.
49+
devices: HashMap<u16, DeviceDescriptor>,
50+
/// Range mapping for VM exit pio operations.
51+
pio_bus: BTreeMap<(u16, u16), Arc<dyn DeviceIo>>,
52+
/// Range mapping for VM exit mmio operations.
53+
mmio_bus: BTreeMap<(u64, u64), Arc<dyn DeviceIo>>,
54+
}
55+
56+
impl DeviceManager {
57+
/// Create a new `DeviceManager`.
58+
pub fn new() -> Self {
59+
DeviceManager {
60+
devices: HashMap::new(),
61+
mmio_bus: BTreeMap::new(),
62+
pio_bus: BTreeMap::new(),
63+
}
64+
}
65+
66+
fn insert(&mut self, des: DeviceDescriptor, id: u16) -> Result<()> {
67+
// Insert if the key is non-present, else report error.
68+
if self.devices.contains_key(&id) {
69+
return Err(Error::DeviceExist);
70+
}
71+
self.devices.insert(id, des);
72+
Ok(())
73+
}
74+
75+
fn remove(&mut self, id: u16) -> Option<DeviceDescriptor> {
76+
self.devices.remove(&id)
77+
}
78+
79+
fn register_resources(
80+
&mut self,
81+
device: Arc<dyn DeviceIo>,
82+
resources: &[Resource],
83+
instance_id: &mut u16,
84+
) -> Result<()> {
85+
// Register and mark device resources
86+
// The resources addresses being registered are sucessfully allocated before.
87+
for (idx, res) in resources.iter().enumerate() {
88+
match *res {
89+
Resource::PioAddressRange { base, size } => {
90+
if self.pio_bus.insert((base, size), device.clone()).is_some() {
91+
// Unregister and let VMM free resources.
92+
if idx > 0 {
93+
self.unregister_resources(&resources[0..idx]);
94+
}
95+
return Err(Error::DeviceOverlap);
96+
}
97+
}
98+
Resource::MmioAddressRange { base, size } => {
99+
if self.mmio_bus.insert((base, size), device.clone()).is_some() {
100+
// Unregister and let VMM free resources.
101+
if idx > 0 {
102+
self.unregister_resources(&resources[0..idx]);
103+
}
104+
return Err(Error::DeviceOverlap);
105+
}
106+
}
107+
Resource::InstanceId(id) => *instance_id = id,
108+
_ => continue,
109+
}
110+
}
111+
Ok(())
112+
}
113+
114+
/// Register a new device with its parent bus and allocated resources.
115+
/// VMM is responsible for providing the allocated resources to virtual device.
116+
///
117+
/// # Arguements
118+
///
119+
/// * `device`: device instance object to be registered
120+
/// * `parent_bus`: parent bus of the device
121+
/// * `resources`: resources that this device owns, might include
122+
/// port I/O and memory-mapped I/O ranges, irq number, etc.
123+
pub fn register_device(
124+
&mut self,
125+
device: Arc<dyn DeviceIo>,
126+
parent_bus: Option<Arc<dyn DeviceIo>>,
127+
resources: &[Resource],
128+
) -> Result<()> {
129+
let mut id = 0;
130+
131+
// Register the IO resource
132+
self.register_resources(device.clone(), resources, &mut id)?;
133+
134+
// Insert bus/device with parent bus
135+
let descriptor = DeviceDescriptor {
136+
device,
137+
id,
138+
parent_bus,
139+
};
140+
self.insert(descriptor, id)
141+
}
142+
143+
// Unregister resources with all entries addresses valid.
144+
fn unregister_resources(&mut self, resources: &[Resource]) {
145+
for res in resources.iter() {
146+
match *res {
147+
Resource::PioAddressRange { base, size } => {
148+
self.pio_bus.remove(&(base, size));
149+
}
150+
Resource::MmioAddressRange { base, size } => {
151+
self.mmio_bus.remove(&(base, size));
152+
}
153+
_ => continue,
154+
}
155+
}
156+
}
157+
158+
/// Unregister a device from `DeviceManager`, e.g. users specified removing.
159+
/// VMM pre-fetches the resources e.g. dev.get_assigned_resources()
160+
/// VMM is responsible for freeing the resources.
161+
///
162+
/// # Arguements
163+
///
164+
/// * `id`: device instance id to be unregistered
165+
/// * `resources`: resources that this device owns, might include
166+
/// port I/O and memory-mapped I/O ranges, irq number, etc.
167+
pub fn unregister_device(&mut self, id: u16, resources: &[Resource]) -> Result<()> {
168+
if let Some(_) = self.remove(id) {
169+
// Unregister resources
170+
self.unregister_resources(resources);
171+
Ok(())
172+
} else {
173+
Err(Error::DeviceNotExist)
174+
}
175+
}
176+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ extern crate vm_memory;
99

1010
use vm_memory::GuestAddress;
1111

12+
pub mod device_manager;
1213
pub mod interrupt;
1314
pub mod resources;
1415

src/resources.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ pub enum Resource {
133133
MacAddresss(String),
134134
/// KVM memslot index.
135135
KvmMemSlot(u32),
136+
/// Instance ID.
137+
InstanceId(u16),
136138
}
137139

138140
/// Newtype to store a set of device resources.

0 commit comments

Comments
 (0)