Skip to content

Commit 372bedf

Browse files
Jing Liujiangliu
Jing Liu
authored andcommitted
Add read and write operations handling
IO manager is responsible for handling IO operation when VMExit. It works out the specific device according to the address range and hand over to DeviceIo trait. Signed-off-by: Jing Liu <[email protected]>
1 parent ef21cf1 commit 372bedf

File tree

2 files changed

+187
-7
lines changed

2 files changed

+187
-7
lines changed

src/device_manager.rs

+135-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
//! devices IO ranges, and finally set resources to virtual device.
1313
1414
use crate::resources::Resource;
15-
use crate::DeviceIo;
15+
use crate::{DeviceIo, IoAddress, IoSize};
1616

17+
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
1718
use std::collections::btree_map::BTreeMap;
1819
use std::result;
1920
use std::sync::Arc;
@@ -23,18 +24,62 @@ use std::sync::Arc;
2324
pub enum Error {
2425
/// The inserting device overlaps with a current device.
2526
DeviceOverlap,
27+
/// The device doesn't exist.
28+
NoDevice,
2629
}
2730

2831
/// Simplify the `Result` type.
2932
pub type Result<T> = result::Result<T, Error>;
3033

34+
// Structure describing an IO range.
35+
#[derive(Debug, Copy, Clone)]
36+
struct IoRange {
37+
base: IoAddress,
38+
size: IoSize,
39+
}
40+
41+
impl IoRange {
42+
fn new_pio_range(base: u16, size: u16) -> Self {
43+
IoRange {
44+
base: IoAddress::Pio(base),
45+
size: IoSize::Pio(size),
46+
}
47+
}
48+
fn new_mmio_range(base: u64, size: u64) -> Self {
49+
IoRange {
50+
base: IoAddress::Mmio(base),
51+
size: IoSize::Mmio(size),
52+
}
53+
}
54+
}
55+
56+
impl Eq for IoRange {}
57+
58+
impl PartialEq for IoRange {
59+
fn eq(&self, other: &IoRange) -> bool {
60+
self.base == other.base
61+
}
62+
}
63+
64+
impl Ord for IoRange {
65+
fn cmp(&self, other: &IoRange) -> Ordering {
66+
self.base.cmp(&other.base)
67+
}
68+
}
69+
70+
impl PartialOrd for IoRange {
71+
fn partial_cmp(&self, other: &IoRange) -> Option<Ordering> {
72+
self.base.partial_cmp(&other.base)
73+
}
74+
}
75+
3176
/// System IO manager serving for all devices management and VM exit handling.
3277
#[derive(Default)]
3378
pub struct IoManager {
3479
/// Range mapping for VM exit pio operations.
35-
pio_bus: BTreeMap<(u16, u16), Arc<dyn DeviceIo>>,
80+
pio_bus: BTreeMap<IoRange, Arc<dyn DeviceIo>>,
3681
/// Range mapping for VM exit mmio operations.
37-
mmio_bus: BTreeMap<(u64, u64), Arc<dyn DeviceIo>>,
82+
mmio_bus: BTreeMap<IoRange, Arc<dyn DeviceIo>>,
3883
}
3984

4085
impl IoManager {
@@ -60,7 +105,11 @@ impl IoManager {
60105
for (idx, res) in resources.iter().enumerate() {
61106
match *res {
62107
Resource::PioAddressRange { base, size } => {
63-
if self.pio_bus.insert((base, size), device.clone()).is_some() {
108+
if self
109+
.pio_bus
110+
.insert(IoRange::new_pio_range(base, size), device.clone())
111+
.is_some()
112+
{
64113
// Unregister registered resources.
65114
self.unregister_device_io(&resources[0..idx])
66115
.expect("failed to unregister devices");
@@ -69,7 +118,11 @@ impl IoManager {
69118
}
70119
}
71120
Resource::MmioAddressRange { base, size } => {
72-
if self.mmio_bus.insert((base, size), device.clone()).is_some() {
121+
if self
122+
.mmio_bus
123+
.insert(IoRange::new_mmio_range(base, size), device.clone())
124+
.is_some()
125+
{
73126
// Unregister registered resources.
74127
self.unregister_device_io(&resources[0..idx])
75128
.expect("failed to unregister devices");
@@ -95,14 +148,89 @@ impl IoManager {
95148
for res in resources.iter() {
96149
match *res {
97150
Resource::PioAddressRange { base, size } => {
98-
self.pio_bus.remove(&(base, size));
151+
self.pio_bus.remove(&IoRange::new_pio_range(base, size));
99152
}
100153
Resource::MmioAddressRange { base, size } => {
101-
self.mmio_bus.remove(&(base, size));
154+
self.mmio_bus.remove(&IoRange::new_mmio_range(base, size));
102155
}
103156
_ => continue,
104157
}
105158
}
106159
Ok(())
107160
}
161+
162+
fn get_entry(&self, addr: IoAddress) -> Option<(&IoRange, &Arc<dyn DeviceIo>)> {
163+
match addr {
164+
IoAddress::Pio(a) => self
165+
.pio_bus
166+
.range(..=&IoRange::new_pio_range(a, 0))
167+
.nth_back(0),
168+
IoAddress::Mmio(a) => self
169+
.mmio_bus
170+
.range(..=&IoRange::new_mmio_range(a, 0))
171+
.nth_back(0),
172+
}
173+
}
174+
175+
// Return the Device mapped `addr` and the base address.
176+
fn get_device(&self, addr: IoAddress) -> Option<(&Arc<dyn DeviceIo>, IoAddress)> {
177+
if let Some((range, dev)) = self.get_entry(addr) {
178+
if (addr.raw_value() - range.base.raw_value()) < range.size.raw_value() {
179+
return Some((dev, range.base));
180+
}
181+
}
182+
None
183+
}
184+
185+
/// A helper function handling PIO read command during VM exit.
186+
/// The virtual device itself provides mutable ability and thead-safe protection.
187+
///
188+
/// Return error if failed to get the device.
189+
pub fn pio_read(&self, addr: u16, data: &mut [u8]) -> Result<()> {
190+
if let Some((device, base)) = self.get_device(IoAddress::Pio(addr)) {
191+
device.read(base, IoAddress::Pio(addr - (base.raw_value() as u16)), data);
192+
Ok(())
193+
} else {
194+
Err(Error::NoDevice)
195+
}
196+
}
197+
198+
/// A helper function handling PIO write command during VM exit.
199+
/// The virtual device itself provides mutable ability and thead-safe protection.
200+
///
201+
/// Return error if failed to get the device.
202+
pub fn pio_write(&self, addr: u16, data: &[u8]) -> Result<()> {
203+
if let Some((device, base)) = self.get_device(IoAddress::Pio(addr)) {
204+
device.write(base, IoAddress::Pio(addr - (base.raw_value() as u16)), data);
205+
Ok(())
206+
} else {
207+
Err(Error::NoDevice)
208+
}
209+
}
210+
211+
/// A helper function handling MMIO read command during VM exit.
212+
/// The virtual device itself provides mutable ability and thead-safe protection.
213+
///
214+
/// Return error if failed to get the device.
215+
pub fn mmio_read(&self, addr: u64, data: &mut [u8]) -> Result<()> {
216+
if let Some((device, base)) = self.get_device(IoAddress::Mmio(addr)) {
217+
device.read(base, IoAddress::Mmio(addr - base.raw_value()), data);
218+
Ok(())
219+
} else {
220+
Err(Error::NoDevice)
221+
}
222+
}
223+
224+
/// A helper function handling MMIO write command during VM exit.
225+
/// The virtual device itself provides mutable ability and thead-safe protection.
226+
///
227+
/// Return error if failed to get the device.
228+
pub fn mmio_write(&self, addr: u64, data: &[u8]) -> Result<()> {
229+
if let Some((device, base)) = self.get_device(IoAddress::Mmio(addr)) {
230+
device.write(base, IoAddress::Mmio(addr - base.raw_value()), data);
231+
Ok(())
232+
} else {
233+
Err(Error::NoDevice)
234+
}
235+
}
108236
}

src/lib.rs

+52
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,31 @@
33

44
//! rust-vmm device model.
55
6+
use std::cmp::{Ord, Ordering, PartialOrd};
7+
68
pub mod device_manager;
79
pub mod resources;
810

11+
// IO Size.
12+
#[derive(Debug, Copy, Clone)]
13+
enum IoSize {
14+
// Port I/O size.
15+
Pio(u16),
16+
17+
// Memory mapped I/O size.
18+
Mmio(u64),
19+
}
20+
21+
impl IoSize {
22+
// Get the raw value as u64 to make operation simple.
23+
fn raw_value(&self) -> u64 {
24+
match *self {
25+
IoSize::Pio(p) => u64::from(p),
26+
IoSize::Mmio(m) => m,
27+
}
28+
}
29+
}
30+
931
/// IO Addresses.
1032
#[derive(Debug, Copy, Clone)]
1133
pub enum IoAddress {
@@ -16,6 +38,36 @@ pub enum IoAddress {
1638
Mmio(u64),
1739
}
1840

41+
impl IoAddress {
42+
// Get the raw value of IO Address to make operation simple.
43+
fn raw_value(&self) -> u64 {
44+
match *self {
45+
IoAddress::Pio(p) => u64::from(p),
46+
IoAddress::Mmio(m) => m,
47+
}
48+
}
49+
}
50+
51+
impl Eq for IoAddress {}
52+
53+
impl PartialEq for IoAddress {
54+
fn eq(&self, other: &IoAddress) -> bool {
55+
self.raw_value() == other.raw_value()
56+
}
57+
}
58+
59+
impl Ord for IoAddress {
60+
fn cmp(&self, other: &IoAddress) -> Ordering {
61+
self.raw_value().cmp(&other.raw_value())
62+
}
63+
}
64+
65+
impl PartialOrd for IoAddress {
66+
fn partial_cmp(&self, other: &IoAddress) -> Option<Ordering> {
67+
self.raw_value().partial_cmp(&other.raw_value())
68+
}
69+
}
70+
1971
/// Device IO trait.
2072
/// A device supporting memory based I/O should implement this trait, then
2173
/// register itself against the different IO type ranges it handles.

0 commit comments

Comments
 (0)