44//! rust-vmm device model. 
55
66use  std:: cmp:: { Ord ,  Ordering ,  PartialOrd } ; 
7+ use  std:: sync:: Mutex ; 
78
89pub  mod  device_manager; 
910pub  mod  resources; 
@@ -68,13 +69,16 @@ impl PartialOrd for IoAddress {
6869    } 
6970} 
7071
71- /// Device IO trait. 
72+ /// Device IO trait adopting interior mutability pattern. 
73+ /// 
7274/// A device supporting memory based I/O should implement this trait, then 
7375/// register itself against the different IO type ranges it handles. 
7476/// The VMM will then dispatch IO (PIO or MMIO) VM exits by calling into the 
7577/// registered devices read or write method from this trait. 
76- /// The DeviceIo trait adopts the interior mutability pattern 
77- /// so we can get a real multiple threads handling. 
78+ /// 
79+ /// The DeviceIo trait adopts the interior mutability pattern so we can get a real concurrent 
80+ /// multiple threads handling. For device backend drivers not focusing on high performance, 
81+ /// they may use the Mutex<T: DeviceIoMut> adapter to simplify implementation. 
7882pub  trait  DeviceIo :  Send  { 
7983    /// Read from the guest physical address `base`, starting at `offset`. 
8084/// Result is placed in `data`. 
@@ -83,3 +87,66 @@ pub trait DeviceIo: Send {
8387    /// Write `data` to the guest physical address `base`, starting from `offset`. 
8488fn  write ( & self ,  base :  IoAddress ,  offset :  IoAddress ,  data :  & [ u8 ] ) ; 
8589} 
90+ 
91+ /// Device IO trait without interior mutability. 
92+ /// 
93+ /// Many device backend drivers will mutate itself when handling IO requests. The DeviceIo trait 
94+ /// assumes interior mutability, but it's a little complex to support interior mutability. So 
95+ /// the Mutex<T: DeviceIoMut> adapter may be used to ease device backend driver implementations. 
96+ /// The Mutex<T: DeviceIoMut> adapter is an zero overhead abstraction without performance penalty. 
97+ pub  trait  DeviceIoMut :  Send  { 
98+     /// Read from the guest physical address `base`, starting at `offset`. 
99+ /// Result is placed in `data`. 
100+ fn  read ( & mut  self ,  base :  IoAddress ,  offset :  IoAddress ,  data :  & mut  [ u8 ] ) ; 
101+ 
102+     /// Write `data` to the guest physical address `base`, starting from `offset`. 
103+ fn  write ( & mut  self ,  base :  IoAddress ,  offset :  IoAddress ,  data :  & [ u8 ] ) ; 
104+ } 
105+ 
106+ impl < T :  DeviceIoMut >  DeviceIo  for  Mutex < T >  { 
107+     fn  read ( & self ,  base :  IoAddress ,  offset :  IoAddress ,  data :  & mut  [ u8 ] )  { 
108+         // Safe to unwrap() because we don't expect poisoned lock here. 
109+         self . lock ( ) . unwrap ( ) . read ( base,  offset,  data) 
110+     } 
111+ 
112+     fn  write ( & self ,  base :  IoAddress ,  offset :  IoAddress ,  data :  & [ u8 ] )  { 
113+         // Safe to unwrap() because we don't expect poisoned lock here. 
114+         self . lock ( ) . unwrap ( ) . write ( base,  offset,  data) 
115+     } 
116+ } 
117+ 
118+ #[ cfg( test) ]  
119+ mod  tests { 
120+     use  super :: * ; 
121+     use  std:: sync:: Arc ; 
122+ 
123+     #[ derive( Default ) ]  
124+     struct  MockDevice  { 
125+         data :  u8 , 
126+     } 
127+ 
128+     impl  DeviceIoMut  for  MockDevice  { 
129+         fn  read ( & mut  self ,  _base :  IoAddress ,  _offset :  IoAddress ,  data :  & mut  [ u8 ] )  { 
130+             data[ 0 ]  = self . data ; 
131+         } 
132+ 
133+         fn  write ( & mut  self ,  _base :  IoAddress ,  _offset :  IoAddress ,  data :  & [ u8 ] )  { 
134+             self . data  = data[ 0 ] ; 
135+         } 
136+     } 
137+ 
138+     fn  register_device ( device :  Arc < dyn  DeviceIo > )  { 
139+         device. write ( IoAddress :: Mmio ( 0 ) ,  IoAddress :: Mmio ( 0 ) ,  & [ 0x10u8 ] ) ; 
140+         let  mut  buf = [ 0x0u8 ] ; 
141+         device. read ( IoAddress :: Mmio ( 0 ) ,  IoAddress :: Mmio ( 0 ) ,  & mut  buf) ; 
142+         assert_eq ! ( buf[ 0 ] ,  0x10 ) ; 
143+     } 
144+ 
145+     #[ test]  
146+     fn  test_device_io_mut_adapter ( )  { 
147+         let  device_mut = Arc :: new ( Mutex :: new ( MockDevice :: default ( ) ) ) ; 
148+ 
149+         register_device ( device_mut. clone ( ) ) ; 
150+         assert_eq ! ( device_mut. lock( ) . unwrap( ) . data,  0x010 ) ; 
151+     } 
152+ } 
0 commit comments