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. 
2528DeviceOverlap , 
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  { 
@@ -56,15 +103,23 @@ impl IoManager {
56103        for  ( idx,  res)  in  resources. iter ( ) . enumerate ( )  { 
57104            match  * res { 
58105                Resource :: PioAddressRange  {  base,  size }  => { 
59-                     if  self . pio_bus . insert ( ( base,  size) ,  device. clone ( ) ) . is_some ( )  { 
106+                     if  self 
107+                         . pio_bus 
108+                         . insert ( IoRange :: new_pio_range ( base,  size) ,  device. clone ( ) ) 
109+                         . is_some ( ) 
110+                     { 
60111                        // Unregister registered resources. 
61112                        self . unregister_device_io ( & resources[ 0 ..idx] ) ?; 
62113
63114                        return  Err ( Error :: DeviceOverlap ) ; 
64115                    } 
65116                } 
66117                Resource :: MmioAddressRange  {  base,  size }  => { 
67-                     if  self . mmio_bus . insert ( ( base,  size) ,  device. clone ( ) ) . is_some ( )  { 
118+                     if  self 
119+                         . mmio_bus 
120+                         . insert ( IoRange :: new_mmio_range ( base,  size) ,  device. clone ( ) ) 
121+                         . is_some ( ) 
122+                     { 
68123                        // Unregister registered resources. 
69124                        self . unregister_device_io ( & resources[ 0 ..idx] ) ?; 
70125
@@ -89,14 +144,97 @@ impl IoManager {
89144        for  res in  resources. iter ( )  { 
90145            match  * res { 
91146                Resource :: PioAddressRange  {  base,  size }  => { 
92-                     self . pio_bus . remove ( & ( base,  size) ) ; 
147+                     self . pio_bus . remove ( & IoRange :: new_pio_range ( base,  size) ) ; 
93148                } 
94149                Resource :: MmioAddressRange  {  base,  size }  => { 
95-                     self . mmio_bus . remove ( & ( base,  size) ) ; 
150+                     self . mmio_bus . remove ( & IoRange :: new_mmio_range ( base,  size) ) ; 
96151                } 
97152                _ => continue , 
98153            } 
99154        } 
100155        Ok ( ( ) ) 
101156    } 
157+ 
158+     fn  first_before ( 
159+         & self , 
160+         addr :  IoAddress , 
161+         map :  BTreeMap < IoRange ,  Arc < dyn  DeviceIo > > , 
162+     )  -> Option < ( IoRange ,  Arc < dyn  DeviceIo > ) >  { 
163+         for  ( range,  dev)  in  map. iter ( ) . rev ( )  { 
164+             if  range. base  <= addr { 
165+                 return  Some ( ( * range,  dev. clone ( ) ) ) ; 
166+             } 
167+         } 
168+         None 
169+     } 
170+ 
171+     // Return the Device mapped the address. 
172+     fn  get_device ( 
173+         & self , 
174+         addr :  IoAddress , 
175+         map :  BTreeMap < IoRange ,  Arc < dyn  DeviceIo > > , 
176+     )  -> Option < Arc < dyn  DeviceIo > >  { 
177+         if  let  Some ( ( range,  dev) )  = self . first_before ( addr,  map)  { 
178+             if  ( addr. raw_value ( )  - range. base . raw_value ( ) )  < range. size . raw_value ( )  { 
179+                 return  Some ( dev) ; 
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)  = self . get_device ( IoAddress :: Pio ( addr) ,  self . pio_bus . clone ( ) )  { 
191+             device. read ( IoAddress :: Pio ( addr) ,  data) ; 
192+             Ok ( ( ) ) 
193+         }  else  { 
194+             Err ( Error :: DeviceNotExist ) 
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)  = self . get_device ( IoAddress :: Pio ( addr) ,  self . pio_bus . clone ( ) )  { 
204+             device. write ( IoAddress :: Pio ( addr) ,  data) ; 
205+             Ok ( ( ) ) 
206+         }  else  { 
207+             Err ( Error :: DeviceNotExist ) 
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)  =
217+             self . get_device ( IoAddress :: Mmio ( GuestAddress ( addr) ) ,  self . mmio_bus . clone ( ) ) 
218+         { 
219+             device. read ( IoAddress :: Mmio ( GuestAddress ( addr) ) ,  data) ; 
220+             Ok ( ( ) ) 
221+         }  else  { 
222+             Err ( Error :: DeviceNotExist ) 
223+         } 
224+     } 
225+ 
226+     /// A helper function handling MMIO write command during VM exit. 
227+ /// The virtual device itself provides mutable ability and thead-safe protection. 
228+ /// 
229+ /// Return error if failed to get the device. 
230+ pub  fn  mmio_write ( & self ,  addr :  u64 ,  data :  & [ u8 ] )  -> Result < ( ) >  { 
231+         if  let  Some ( device)  =
232+             self . get_device ( IoAddress :: Mmio ( GuestAddress ( addr) ) ,  self . mmio_bus . clone ( ) ) 
233+         { 
234+             device. write ( IoAddress :: Mmio ( GuestAddress ( addr) ) ,  data) ; 
235+             Ok ( ( ) ) 
236+         }  else  { 
237+             Err ( Error :: DeviceNotExist ) 
238+         } 
239+     } 
102240} 
0 commit comments