1212//! devices IO windows, and finally set resources to virtual device.
1313
1414use crate :: resources:: Resource ;
15- use crate :: DeviceIo ;
15+ use crate :: { DeviceIo , IoAddress , IoSize } ;
1616
17+ use std:: cmp:: { Ord , Ordering , PartialEq , PartialOrd } ;
1718use std:: collections:: btree_map:: BTreeMap ;
1819use std:: result;
1920use std:: sync:: Arc ;
2021
22+ use vm_memory:: GuestAddress ;
23+
2124/// Error type for `IoManager` usage.
2225#[ derive( Debug ) ]
2326pub enum Error {
2427 /// The inserting device overlaps with a current device.
2528 DeviceOverlap ,
29+ /// The device doesn't exist.
30+ DeviceNotExist ,
2631}
2732
2833/// Simplify the `Result` type.
2934pub type Result < T > = result:: Result < T , Error > ;
3035
36+ // Structure describing an IO range.
37+ #[ derive( Debug , Copy , Clone ) ]
38+ struct IoRange {
39+ base : IoAddress ,
40+ size : IoSize ,
41+ }
42+
43+ impl IoRange {
44+ fn new_pio_range ( base : u16 , size : u16 ) -> Self {
45+ IoRange {
46+ base : IoAddress :: Pio ( base) ,
47+ size : IoSize :: Pio ( size) ,
48+ }
49+ }
50+ fn new_mmio_range ( base : u64 , size : u64 ) -> Self {
51+ IoRange {
52+ base : IoAddress :: Mmio ( GuestAddress ( base) ) ,
53+ size : IoSize :: Mmio ( size) ,
54+ }
55+ }
56+ }
57+
58+ impl Eq for IoRange { }
59+
60+ impl PartialEq for IoRange {
61+ fn eq ( & self , other : & IoRange ) -> bool {
62+ self . base == other. base
63+ }
64+ }
65+
66+ impl Ord for IoRange {
67+ fn cmp ( & self , other : & IoRange ) -> Ordering {
68+ self . base . cmp ( & other. base )
69+ }
70+ }
71+
72+ impl PartialOrd for IoRange {
73+ fn partial_cmp ( & self , other : & IoRange ) -> Option < Ordering > {
74+ self . base . partial_cmp ( & other. base )
75+ }
76+ }
77+
3178/// System IO manager serving for all devices management and VM exit handling.
3279#[ derive( Default ) ]
3380pub struct IoManager {
3481 /// Range mapping for VM exit pio operations.
35- pio_bus : BTreeMap < ( u16 , u16 ) , Arc < dyn DeviceIo > > ,
82+ pio_bus : BTreeMap < IoRange , Arc < dyn DeviceIo > > ,
3683 /// Range mapping for VM exit mmio operations.
37- mmio_bus : BTreeMap < ( u64 , u64 ) , Arc < dyn DeviceIo > > ,
84+ mmio_bus : BTreeMap < IoRange , Arc < dyn DeviceIo > > ,
3885}
3986
4087impl IoManager {
@@ -59,15 +106,23 @@ impl IoManager {
59106 for ( idx, res) in resources. iter ( ) . enumerate ( ) {
60107 match * res {
61108 Resource :: PioAddressRange { base, size } => {
62- if self . pio_bus . insert ( ( base, size) , device. clone ( ) ) . is_some ( ) {
109+ if self
110+ . pio_bus
111+ . insert ( IoRange :: new_pio_range ( base, size) , device. clone ( ) )
112+ . is_some ( )
113+ {
63114 // Unregister registered resources.
64115 self . unregister_device_io ( & resources[ 0 ..idx] ) ?;
65116
66117 return Err ( Error :: DeviceOverlap ) ;
67118 }
68119 }
69120 Resource :: MmioAddressRange { base, size } => {
70- 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+ {
71126 // Unregister registered resources.
72127 self . unregister_device_io ( & resources[ 0 ..idx] ) ?;
73128
@@ -92,14 +147,97 @@ impl IoManager {
92147 for res in resources. iter ( ) {
93148 match * res {
94149 Resource :: PioAddressRange { base, size } => {
95- self . pio_bus . remove ( & ( base, size) ) ;
150+ self . pio_bus . remove ( & IoRange :: new_pio_range ( base, size) ) ;
96151 }
97152 Resource :: MmioAddressRange { base, size } => {
98- self . mmio_bus . remove ( & ( base, size) ) ;
153+ self . mmio_bus . remove ( & IoRange :: new_mmio_range ( base, size) ) ;
99154 }
100155 _ => continue ,
101156 }
102157 }
103158 Ok ( ( ) )
104159 }
160+
161+ fn first_before (
162+ & self ,
163+ addr : IoAddress ,
164+ map : BTreeMap < IoRange , Arc < dyn DeviceIo > > ,
165+ ) -> Option < ( IoRange , Arc < dyn DeviceIo > ) > {
166+ for ( range, dev) in map. iter ( ) . rev ( ) {
167+ if range. base <= addr {
168+ return Some ( ( * range, dev. clone ( ) ) ) ;
169+ }
170+ }
171+ None
172+ }
173+
174+ // Return the Device mapped the address.
175+ fn get_device (
176+ & self ,
177+ addr : IoAddress ,
178+ map : BTreeMap < IoRange , Arc < dyn DeviceIo > > ,
179+ ) -> Option < Arc < dyn DeviceIo > > {
180+ if let Some ( ( range, dev) ) = self . first_before ( addr, map) {
181+ if ( addr. raw_value ( ) - range. base . raw_value ( ) ) < range. size . raw_value ( ) {
182+ return Some ( dev) ;
183+ }
184+ }
185+ None
186+ }
187+
188+ /// A helper function handling PIO read command during VM exit.
189+ /// The virtual device itself provides mutable ability and thead-safe protection.
190+ ///
191+ /// Return error if failed to get the device.
192+ pub fn pio_read ( & self , addr : u16 , data : & mut [ u8 ] ) -> Result < ( ) > {
193+ if let Some ( device) = self . get_device ( IoAddress :: Pio ( addr) , self . pio_bus . clone ( ) ) {
194+ device. read ( IoAddress :: Pio ( addr) , data) ;
195+ Ok ( ( ) )
196+ } else {
197+ Err ( Error :: DeviceNotExist )
198+ }
199+ }
200+
201+ /// A helper function handling PIO write command during VM exit.
202+ /// The virtual device itself provides mutable ability and thead-safe protection.
203+ ///
204+ /// Return error if failed to get the device.
205+ pub fn pio_write ( & self , addr : u16 , data : & [ u8 ] ) -> Result < ( ) > {
206+ if let Some ( device) = self . get_device ( IoAddress :: Pio ( addr) , self . pio_bus . clone ( ) ) {
207+ device. write ( IoAddress :: Pio ( addr) , data) ;
208+ Ok ( ( ) )
209+ } else {
210+ Err ( Error :: DeviceNotExist )
211+ }
212+ }
213+
214+ /// A helper function handling MMIO read command during VM exit.
215+ /// The virtual device itself provides mutable ability and thead-safe protection.
216+ ///
217+ /// Return error if failed to get the device.
218+ pub fn mmio_read ( & self , addr : u64 , data : & mut [ u8 ] ) -> Result < ( ) > {
219+ if let Some ( device) =
220+ self . get_device ( IoAddress :: Mmio ( GuestAddress ( addr) ) , self . mmio_bus . clone ( ) )
221+ {
222+ device. read ( IoAddress :: Mmio ( GuestAddress ( addr) ) , data) ;
223+ Ok ( ( ) )
224+ } else {
225+ Err ( Error :: DeviceNotExist )
226+ }
227+ }
228+
229+ /// A helper function handling MMIO write command during VM exit.
230+ /// The virtual device itself provides mutable ability and thead-safe protection.
231+ ///
232+ /// Return error if failed to get the device.
233+ pub fn mmio_write ( & self , addr : u64 , data : & [ u8 ] ) -> Result < ( ) > {
234+ if let Some ( device) =
235+ self . get_device ( IoAddress :: Mmio ( GuestAddress ( addr) ) , self . mmio_bus . clone ( ) )
236+ {
237+ device. write ( IoAddress :: Mmio ( GuestAddress ( addr) ) , data) ;
238+ Ok ( ( ) )
239+ } else {
240+ Err ( Error :: DeviceNotExist )
241+ }
242+ }
105243}
0 commit comments