88//! Track memory regions that are mapped to the guest microVM.
99
1010use std:: io:: { Read , Write } ;
11- use std:: result;
1211use std:: sync:: Arc ;
12+ use std:: { mem, result} ;
1313
1414use guest_address:: GuestAddress ;
1515use mmap:: { self , MemoryMapping } ;
@@ -20,6 +20,8 @@ use DataInit;
2020pub enum Error {
2121 /// Failure in finding a guest address in any memory regions mapped by this guest.
2222 InvalidGuestAddress ( GuestAddress ) ,
23+ /// Failure in finding a guest address range in any memory regions mapped by this guest.
24+ InvalidGuestAddressRange ( GuestAddress , usize ) ,
2325 /// Failure in accessing the memory located at some address.
2426 MemoryAccess ( GuestAddress , mmap:: Error ) ,
2527 /// Failure in creating an anonymous shared mapping.
@@ -156,6 +158,7 @@ impl GuestMemory {
156158 }
157159 Ok ( ( ) )
158160 }
161+
159162 /// Writes a slice to guest memory at the specified guest address.
160163 /// Returns the number of bytes written. The number of bytes written can
161164 /// be less than the length of the slice if there isn't enough room in the
@@ -175,7 +178,7 @@ impl GuestMemory {
175178 /// # }
176179 /// ```
177180 pub fn write_slice_at_addr ( & self , buf : & [ u8 ] , guest_addr : GuestAddress ) -> Result < usize > {
178- self . do_in_region ( guest_addr, move |mapping, offset| {
181+ self . do_in_region_partial ( guest_addr, move |mapping, offset| {
179182 mapping
180183 . write_slice ( buf, offset)
181184 . map_err ( |e| Error :: MemoryAccess ( guest_addr, e) )
@@ -206,7 +209,7 @@ impl GuestMemory {
206209 mut buf : & mut [ u8 ] ,
207210 guest_addr : GuestAddress ,
208211 ) -> Result < usize > {
209- self . do_in_region ( guest_addr, move |mapping, offset| {
212+ self . do_in_region_partial ( guest_addr, move |mapping, offset| {
210213 mapping
211214 . read_slice ( buf, offset)
212215 . map_err ( |e| Error :: MemoryAccess ( guest_addr, e) )
@@ -218,6 +221,9 @@ impl GuestMemory {
218221 /// mid-read. However, as long as the type T is plain old data and can
219222 /// handle random initialization, everything will be OK.
220223 ///
224+ /// Caller needs to guarantee that the object does not cross MemoryRegion
225+ /// boundary, otherwise it fails.
226+ ///
221227 /// # Examples
222228 /// * Read a u64 from two areas of guest memory backed by separate mappings.
223229 ///
@@ -234,7 +240,7 @@ impl GuestMemory {
234240 /// # }
235241 /// ```
236242 pub fn read_obj_from_addr < T : DataInit > ( & self , guest_addr : GuestAddress ) -> Result < T > {
237- self . do_in_region ( guest_addr, |mapping, offset| {
243+ self . do_in_region ( guest_addr, mem :: size_of :: < T > ( ) , |mapping, offset| {
238244 mapping
239245 . read_obj ( offset)
240246 . map_err ( |e| Error :: MemoryAccess ( guest_addr, e) )
@@ -244,6 +250,9 @@ impl GuestMemory {
244250 /// Writes an object to the memory region at the specified guest address.
245251 /// Returns Ok(()) if the object fits, or Err if it extends past the end.
246252 ///
253+ /// Caller needs to guarantee that the object does not cross MemoryRegion
254+ /// boundary, otherwise it fails.
255+ ///
247256 /// # Examples
248257 /// * Write a u64 at guest address 0x1100.
249258 ///
@@ -257,7 +266,7 @@ impl GuestMemory {
257266 /// # }
258267 /// ```
259268 pub fn write_obj_at_addr < T : DataInit > ( & self , val : T , guest_addr : GuestAddress ) -> Result < ( ) > {
260- self . do_in_region ( guest_addr, move |mapping, offset| {
269+ self . do_in_region ( guest_addr, mem :: size_of :: < T > ( ) , move |mapping, offset| {
261270 mapping
262271 . write_obj ( val, offset)
263272 . map_err ( |e| Error :: MemoryAccess ( guest_addr, e) )
@@ -299,7 +308,7 @@ impl GuestMemory {
299308 where
300309 F : Read ,
301310 {
302- self . do_in_region ( guest_addr, move |mapping, offset| {
311+ self . do_in_region ( guest_addr, count , move |mapping, offset| {
303312 mapping
304313 . read_to_memory ( offset, src, count)
305314 . map_err ( |e| Error :: MemoryAccess ( guest_addr, e) )
@@ -339,7 +348,7 @@ impl GuestMemory {
339348 where
340349 F : Write ,
341350 {
342- self . do_in_region ( guest_addr, move |mapping, offset| {
351+ self . do_in_region ( guest_addr, count , move |mapping, offset| {
343352 mapping
344353 . write_from_memory ( offset, dst, count)
345354 . map_err ( |e| Error :: MemoryAccess ( guest_addr, e) )
@@ -367,7 +376,7 @@ impl GuestMemory {
367376 /// # }
368377 /// ```
369378 pub fn get_host_address ( & self , guest_addr : GuestAddress ) -> Result < * const u8 > {
370- self . do_in_region ( guest_addr, |mapping, offset| {
379+ self . do_in_region ( guest_addr, 1 , |mapping, offset| {
371380 // This is safe; `do_in_region` already checks that offset is in
372381 // bounds.
373382 Ok ( unsafe { mapping. as_ptr ( ) . offset ( offset as isize ) } as * const u8 )
@@ -413,9 +422,27 @@ impl GuestMemory {
413422 self . regions . iter ( ) . enumerate ( ) . map ( mapf) . fold ( init, foldf)
414423 }
415424
416- fn do_in_region < F , T > ( & self , guest_addr : GuestAddress , cb : F ) -> Result < T >
425+ /// Read the whole object from a single MemoryRegion
426+ fn do_in_region < F , T > ( & self , guest_addr : GuestAddress , size : usize , cb : F ) -> Result < T >
417427 where
418428 F : FnOnce ( & MemoryMapping , usize ) -> Result < T > ,
429+ {
430+ for region in self . regions . iter ( ) {
431+ if guest_addr >= region. guest_base && guest_addr < region_end ( region) {
432+ let offset = guest_addr. offset_from ( region. guest_base ) ;
433+ if size <= region. mapping . size ( ) - offset {
434+ return cb ( & region. mapping , offset) ;
435+ }
436+ break ;
437+ }
438+ }
439+ Err ( Error :: InvalidGuestAddressRange ( guest_addr, size) )
440+ }
441+
442+ /// Read the whole or partial content from a single MemoryRegion
443+ fn do_in_region_partial < F > ( & self , guest_addr : GuestAddress , cb : F ) -> Result < usize >
444+ where
445+ F : FnOnce ( & MemoryMapping , usize ) -> Result < usize > ,
419446 {
420447 for region in self . regions . iter ( ) {
421448 if guest_addr >= region. guest_base && guest_addr < region_end ( region) {
@@ -471,14 +498,27 @@ mod tests {
471498 let start_addr1 = GuestAddress ( 0x0 ) ;
472499 let start_addr2 = GuestAddress ( 0x1000 ) ;
473500 let bad_addr = GuestAddress ( 0x2001 ) ;
501+ let bad_addr2 = GuestAddress ( 0x1ffc ) ;
474502
475503 let gm = GuestMemory :: new ( & vec ! [ ( start_addr1, 0x1000 ) , ( start_addr2, 0x1000 ) ] ) . unwrap ( ) ;
476504
477505 let val1: u64 = 0xaa55aa55aa55aa55 ;
478506 let val2: u64 = 0x55aa55aa55aa55aa ;
479507 assert_eq ! (
480508 format!( "{:?}" , gm. write_obj_at_addr( val1, bad_addr) . err( ) . unwrap( ) ) ,
481- format!( "InvalidGuestAddress({:?})" , bad_addr)
509+ format!(
510+ "InvalidGuestAddressRange({:?}, {:?})" ,
511+ bad_addr,
512+ std:: mem:: size_of:: <u64 >( )
513+ )
514+ ) ;
515+ assert_eq ! (
516+ format!( "{:?}" , gm. write_obj_at_addr( val1, bad_addr2) . err( ) . unwrap( ) ) ,
517+ format!(
518+ "InvalidGuestAddressRange({:?}, {:?})" ,
519+ bad_addr2,
520+ std:: mem:: size_of:: <u64 >( )
521+ )
482522 ) ;
483523
484524 gm. write_obj_at_addr ( val1, GuestAddress ( 0x500 ) ) . unwrap ( ) ;
@@ -492,7 +532,7 @@ mod tests {
492532
493533 #[ test]
494534 fn write_and_read_slice ( ) {
495- let start_addr = GuestAddress ( 0x1000 ) ;
535+ let mut start_addr = GuestAddress ( 0x1000 ) ;
496536 let gm = GuestMemory :: new ( & vec ! [ ( start_addr, 0x400 ) ] ) . unwrap ( ) ;
497537 let sample_buf = & [ 1 , 2 , 3 , 4 , 5 ] ;
498538
@@ -501,6 +541,11 @@ mod tests {
501541 let buf = & mut [ 0u8 ; 5 ] ;
502542 assert_eq ! ( gm. read_slice_at_addr( buf, start_addr) . unwrap( ) , 5 ) ;
503543 assert_eq ! ( buf, sample_buf) ;
544+
545+ start_addr = GuestAddress ( 0x13ff ) ;
546+ assert_eq ! ( gm. write_slice_at_addr( sample_buf, start_addr) . unwrap( ) , 1 ) ;
547+ assert_eq ! ( gm. read_slice_at_addr( buf, start_addr) . unwrap( ) , 1 ) ;
548+ assert_eq ! ( buf[ 0 ] , sample_buf[ 0 ] ) ;
504549 }
505550
506551 #[ test]
@@ -551,7 +596,7 @@ mod tests {
551596
552597 // Get the base address of the mapping for a GuestAddress.
553598 fn get_mapping ( mem : & GuestMemory , addr : GuestAddress ) -> Result < * const u8 > {
554- mem. do_in_region ( addr, |mapping, _| Ok ( mapping. as_ptr ( ) as * const u8 ) )
599+ mem. do_in_region ( addr, 1 , |mapping, _| Ok ( mapping. as_ptr ( ) as * const u8 ) )
555600 }
556601
557602 #[ test]
0 commit comments