1212//! devices IO ranges, and finally set resources to virtual device. 
1313
1414use  crate :: resources:: Resource ; 
15+ #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
16+ use  crate :: PioAddress ; 
1517use  crate :: { DeviceIo ,  IoAddress ,  IoSize } ; 
1618
1719use  std:: cmp:: { Ord ,  Ordering ,  PartialEq ,  PartialOrd } ; 
@@ -32,29 +34,29 @@ pub enum Error {
3234pub  type  Result < T >  = result:: Result < T ,  Error > ; 
3335
3436/// Structure describing an IO range. 
35- #[ derive( Debug ,  Copy ,  Clone ) ]  
37+ #[ derive( Debug ,  Copy ,  Clone ,   Eq ) ]  
3638pub  struct  IoRange  { 
3739    base :  IoAddress , 
3840    size :  IoSize , 
3941} 
4042
4143impl  IoRange  { 
44+     #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
4245    fn  new_pio_range ( base :  u16 ,  size :  u16 )  -> Self  { 
4346        IoRange  { 
44-             base :  IoAddress :: Pio ( base) , 
45-             size :  IoSize :: Pio ( size) , 
47+             base :  IoAddress ( base  as   u64 ) , 
48+             size :  IoSize ( size  as   u64 ) , 
4649        } 
4750    } 
51+ 
4852    fn  new_mmio_range ( base :  u64 ,  size :  u64 )  -> Self  { 
4953        IoRange  { 
50-             base :  IoAddress :: Mmio ( base) , 
51-             size :  IoSize :: Mmio ( size) , 
54+             base :  IoAddress ( base) , 
55+             size :  IoSize ( size) , 
5256        } 
5357    } 
5458} 
5559
56- impl  Eq  for  IoRange  { } 
57- 
5860impl  PartialEq  for  IoRange  { 
5961    fn  eq ( & self ,  other :  & IoRange )  -> bool  { 
6062        self . base  == other. base 
@@ -76,6 +78,7 @@ impl PartialOrd for IoRange {
7678/// System IO manager serving for all devices management and VM exit handling. 
7779#[ derive( Clone ,  Default ) ]  
7880pub  struct  IoManager  { 
81+     #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
7982    /// Range mapping for VM exit pio operations. 
8083pio_bus :  BTreeMap < IoRange ,  Arc < dyn  DeviceIo > > , 
8184    /// Range mapping for VM exit mmio operations. 
@@ -87,6 +90,7 @@ impl IoManager {
8790pub  fn  new ( )  -> Self  { 
8891        IoManager :: default ( ) 
8992    } 
93+ 
9094    /// Register a new device IO with its allocated resources. 
9195/// VMM is responsible for providing the allocated resources to virtual device. 
9296/// 
@@ -104,6 +108,7 @@ impl IoManager {
104108        // The resources addresses being registered are sucessfully allocated before. 
105109        for  ( idx,  res)  in  resources. iter ( ) . enumerate ( )  { 
106110            match  * res { 
111+                 #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
107112                Resource :: PioAddressRange  {  base,  size }  => { 
108113                    if  self 
109114                        . pio_bus 
@@ -147,6 +152,7 @@ impl IoManager {
147152pub  fn  unregister_device_io ( & mut  self ,  resources :  & [ Resource ] )  -> Result < ( ) >  { 
148153        for  res in  resources. iter ( )  { 
149154            match  * res { 
155+                 #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
150156                Resource :: PioAddressRange  {  base,  size }  => { 
151157                    self . pio_bus . remove ( & IoRange :: new_pio_range ( base,  size) ) ; 
152158                } 
@@ -159,79 +165,69 @@ impl IoManager {
159165        Ok ( ( ) ) 
160166    } 
161167
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-         } 
168+     /// A helper function handling MMIO read command during VM exit. 
169+ /// The virtual device itself provides mutable ability and thead-safe protection. 
170+ /// 
171+ /// Return error if failed to get the device. 
172+ pub  fn  mmio_read ( & self ,  addr :  u64 ,  data :  & mut  [ u8 ] )  -> Result < ( ) >  { 
173+         self . get_device ( IoAddress ( addr) ) 
174+             . map ( |( device,  base) | device. read ( base,  IoAddress ( addr - base. raw_value ( ) ) ,  data) ) 
175+             . ok_or ( Error :: NoDevice ) 
176+     } 
177+ 
178+     /// A helper function handling MMIO write command during VM exit. 
179+ /// The virtual device itself provides mutable ability and thead-safe protection. 
180+ /// 
181+ /// Return error if failed to get the device. 
182+ pub  fn  mmio_write ( & self ,  addr :  u64 ,  data :  & [ u8 ] )  -> Result < ( ) >  { 
183+         self . get_device ( IoAddress ( addr) ) 
184+             . map ( |( device,  base) | device. write ( base,  IoAddress ( addr - base. raw_value ( ) ) ,  data) ) 
185+             . ok_or ( Error :: NoDevice ) 
173186    } 
174187
175188    // Return the Device mapped `addr` and the base address. 
176189    fn  get_device ( & self ,  addr :  IoAddress )  -> Option < ( & Arc < dyn  DeviceIo > ,  IoAddress ) >  { 
177-         if  let  Some ( ( range,  dev) )  = self . get_entry ( addr)  { 
190+         let  range = IoRange :: new_mmio_range ( addr. raw_value ( ) ,  0 ) ; 
191+         if  let  Some ( ( range,  dev) )  = self . mmio_bus . range ( ..=& range) . nth_back ( 0 )  { 
178192            if  ( addr. raw_value ( )  - range. base . raw_value ( ) )  < range. size . raw_value ( )  { 
179193                return  Some ( ( dev,  range. base ) ) ; 
180194            } 
181195        } 
182196        None 
183197    } 
198+ } 
184199
200+ #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
201+ impl  IoManager  { 
185202    /// A helper function handling PIO read command during VM exit. 
186203/// The virtual device itself provides mutable ability and thead-safe protection. 
187204/// 
188205/// Return error if failed to get the device. 
189206pub  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-         } 
207+         self . get_pio_device ( PioAddress ( addr) ) 
208+             . map ( |( device,  base) | device. pio_read ( base,  PioAddress ( addr - base. raw_value ( ) ) ,  data) ) 
209+             . ok_or ( Error :: NoDevice ) 
196210    } 
197211
198212    /// A helper function handling PIO write command during VM exit. 
199213/// The virtual device itself provides mutable ability and thead-safe protection. 
200214/// 
201215/// Return error if failed to get the device. 
202216pub  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-         } 
217+         self . get_pio_device ( PioAddress ( addr) ) 
218+             . map ( |( device,  base) | device. pio_write ( base,  PioAddress ( addr - base. raw_value ( ) ) ,  data) ) 
219+             . ok_or ( Error :: NoDevice ) 
222220    } 
223221
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 ) 
222+     // Return the Device mapped `addr` and the base address. 
223+     fn  get_pio_device ( & self ,  addr :  PioAddress )  -> Option < ( & Arc < dyn  DeviceIo > ,  PioAddress ) >  { 
224+         let  range = IoRange :: new_pio_range ( addr. raw_value ( ) ,  0 ) ; 
225+         if  let  Some ( ( range,  dev) )  = self . pio_bus . range ( ..=& range) . nth_back ( 0 )  { 
226+             if  ( addr. raw_value ( )  as  u64  - range. base . raw_value ( ) )  < range. size . raw_value ( )  { 
227+                 return  Some ( ( dev,  PioAddress ( range. base . 0  as  u16 ) ) ) ; 
228+             } 
234229        } 
230+         None 
235231    } 
236232} 
237233
@@ -240,7 +236,9 @@ mod tests {
240236    use  super :: * ; 
241237    use  std:: sync:: Mutex ; 
242238
239+     #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
243240    const  PIO_ADDRESS_SIZE :  u16  = 4 ; 
241+     #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
244242    const  PIO_ADDRESS_BASE :  u16  = 0x40 ; 
245243    const  MMIO_ADDRESS_SIZE :  u64  = 0x8765_4321 ; 
246244    const  MMIO_ADDRESS_BASE :  u64  = 0x1234_5678 ; 
@@ -274,6 +272,23 @@ mod tests {
274272            let  mut  config = self . config . lock ( ) . expect ( "failed to acquire lock" ) ; 
275273            * config = u32:: from ( data[ 0 ] )  &  0xff ; 
276274        } 
275+ 
276+         #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
277+         fn  pio_read ( & self ,  _base :  PioAddress ,  _offset :  PioAddress ,  data :  & mut  [ u8 ] )  { 
278+             if  data. len ( )  > 4  { 
279+                 return ; 
280+             } 
281+             for  ( idx,  iter)  in  data. iter_mut ( ) . enumerate ( )  { 
282+                 let  config = self . config . lock ( ) . expect ( "failed to acquire lock" ) ; 
283+                 * iter = ( * config >> ( idx *  8 )  &  0xff )  as  u8 ; 
284+             } 
285+         } 
286+ 
287+         #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
288+         fn  pio_write ( & self ,  _base :  PioAddress ,  _offset :  PioAddress ,  data :  & [ u8 ] )  { 
289+             let  mut  config = self . config . lock ( ) . expect ( "failed to acquire lock" ) ; 
290+             * config = u32:: from ( data[ 0 ] )  &  0xff ; 
291+         } 
277292    } 
278293
279294    #[ test]  
@@ -287,32 +302,42 @@ mod tests {
287302            base :  MMIO_ADDRESS_BASE , 
288303            size :  MMIO_ADDRESS_SIZE , 
289304        } ; 
290-         let  pio = Resource :: PioAddressRange  { 
291-             base :  PIO_ADDRESS_BASE , 
292-             size :  PIO_ADDRESS_SIZE , 
293-         } ; 
294305        let  irq = Resource :: LegacyIrq ( LEGACY_IRQ ) ; 
295306
296307        resource. push ( mmio) ; 
297-         resource. push ( pio) ; 
298308        resource. push ( irq) ; 
309+ 
310+         #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
311+         { 
312+             let  pio = Resource :: PioAddressRange  { 
313+                 base :  PIO_ADDRESS_BASE , 
314+                 size :  PIO_ADDRESS_SIZE , 
315+             } ; 
316+             resource. push ( pio) ; 
317+         } 
318+ 
299319        assert ! ( io_mgr. register_device_io( dum. clone( ) ,  & resource) . is_ok( ) ) ; 
300320
301321        let  io_mgr2 = io_mgr. clone ( ) ; 
302-         assert_eq ! ( io_mgr2. pio_bus. len( ) ,  1 ) ; 
303322        assert_eq ! ( io_mgr2. mmio_bus. len( ) ,  1 ) ; 
304323
305-         let  ( dev,  addr)  = io_mgr2
306-             . get_device ( IoAddress :: Mmio ( MMIO_ADDRESS_BASE  + 1 ) ) 
307-             . unwrap ( ) ; 
308-         assert_eq ! ( Arc :: strong_count( dev) ,  5 ) ; 
309-         assert_eq ! ( addr,  IoAddress :: Mmio ( MMIO_ADDRESS_BASE ) ) ; 
324+         #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
325+         { 
326+             assert_eq ! ( io_mgr2. pio_bus. len( ) ,  1 ) ; 
327+ 
328+             let  ( dev,  addr)  = io_mgr2
329+                 . get_device ( IoAddress ( MMIO_ADDRESS_BASE  + 1 ) ) 
330+                 . unwrap ( ) ; 
331+             assert_eq ! ( Arc :: strong_count( dev) ,  5 ) ; 
310332
311-         drop ( io_mgr) ; 
312-         assert_eq ! ( Arc :: strong_count( dev) ,  3 ) ; 
333+             assert_eq ! ( addr,  IoAddress ( MMIO_ADDRESS_BASE ) ) ; 
313334
314-         drop ( io_mgr2) ; 
315-         assert_eq ! ( Arc :: strong_count( & dum) ,  1 ) ; 
335+             drop ( io_mgr) ; 
336+             assert_eq ! ( Arc :: strong_count( dev) ,  3 ) ; 
337+ 
338+             drop ( io_mgr2) ; 
339+             assert_eq ! ( Arc :: strong_count( & dum) ,  1 ) ; 
340+         } 
316341    } 
317342
318343    #[ test]  
@@ -365,6 +390,7 @@ mod tests {
365390            . is_err( ) ) ; 
366391    } 
367392
393+     #[ cfg( any( target_arch = "x86_64" ,  target_arch = "x86" ) ) ]  
368394    #[ test]  
369395    fn  test_pio_read_write ( )  { 
370396        let  mut  io_mgr:  IoManager  = Default :: default ( ) ; 
@@ -394,4 +420,15 @@ mod tests {
394420            . pio_write( PIO_ADDRESS_BASE  + PIO_ADDRESS_SIZE ,  & data) 
395421            . is_err( ) ) ; 
396422    } 
423+ 
424+     #[ test]  
425+     fn  test_device_manager_data_structs ( )  { 
426+         let  range1 = IoRange :: new_mmio_range ( 0x1000 ,  0x1000 ) ; 
427+         let  range2 = IoRange :: new_mmio_range ( 0x1000 ,  0x2000 ) ; 
428+         let  range3 = IoRange :: new_mmio_range ( 0x2000 ,  0x1000 ) ; 
429+ 
430+         assert_eq ! ( range1,  range1. clone( ) ) ; 
431+         assert_eq ! ( range1,  range2) ; 
432+         assert ! ( range1 < range3) ; 
433+     } 
397434} 
0 commit comments