12
12
//! devices IO ranges, and finally set resources to virtual device.
13
13
14
14
use crate :: resources:: Resource ;
15
- use crate :: DeviceIo ;
15
+ use crate :: { DeviceIo , IoAddress , IoSize } ;
16
16
17
+ use std:: cmp:: { Ord , Ordering , PartialEq , PartialOrd } ;
17
18
use std:: collections:: btree_map:: BTreeMap ;
18
19
use std:: result;
19
20
use std:: sync:: Arc ;
@@ -23,18 +24,62 @@ use std::sync::Arc;
23
24
pub enum Error {
24
25
/// The inserting device overlaps with a current device.
25
26
DeviceOverlap ,
27
+ /// The device doesn't exist.
28
+ NoDevice ,
26
29
}
27
30
28
31
/// Simplify the `Result` type.
29
32
pub type Result < T > = result:: Result < T , Error > ;
30
33
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
+
31
76
/// System IO manager serving for all devices management and VM exit handling.
32
77
#[ derive( Default ) ]
33
78
pub struct IoManager {
34
79
/// Range mapping for VM exit pio operations.
35
- pio_bus : BTreeMap < ( u16 , u16 ) , Arc < dyn DeviceIo > > ,
80
+ pio_bus : BTreeMap < IoRange , Arc < dyn DeviceIo > > ,
36
81
/// Range mapping for VM exit mmio operations.
37
- mmio_bus : BTreeMap < ( u64 , u64 ) , Arc < dyn DeviceIo > > ,
82
+ mmio_bus : BTreeMap < IoRange , Arc < dyn DeviceIo > > ,
38
83
}
39
84
40
85
impl IoManager {
@@ -60,7 +105,11 @@ impl IoManager {
60
105
for ( idx, res) in resources. iter ( ) . enumerate ( ) {
61
106
match * res {
62
107
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
+ {
64
113
// Unregister registered resources.
65
114
self . unregister_device_io ( & resources[ 0 ..idx] )
66
115
. expect ( "failed to unregister devices" ) ;
@@ -69,7 +118,11 @@ impl IoManager {
69
118
}
70
119
}
71
120
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
+ {
73
126
// Unregister registered resources.
74
127
self . unregister_device_io ( & resources[ 0 ..idx] )
75
128
. expect ( "failed to unregister devices" ) ;
@@ -95,14 +148,89 @@ impl IoManager {
95
148
for res in resources. iter ( ) {
96
149
match * res {
97
150
Resource :: PioAddressRange { base, size } => {
98
- self . pio_bus . remove ( & ( base, size) ) ;
151
+ self . pio_bus . remove ( & IoRange :: new_pio_range ( base, size) ) ;
99
152
}
100
153
Resource :: MmioAddressRange { base, size } => {
101
- self . mmio_bus . remove ( & ( base, size) ) ;
154
+ self . mmio_bus . remove ( & IoRange :: new_mmio_range ( base, size) ) ;
102
155
}
103
156
_ => continue ,
104
157
}
105
158
}
106
159
Ok ( ( ) )
107
160
}
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
+ }
108
236
}
0 commit comments