@@ -52,7 +52,9 @@ use std::sync::Arc;
5252use crate :: address:: { Address , AddressValue } ;
5353use crate :: bitmap:: { Bitmap , BS , MS } ;
5454use crate :: bytes:: { AtomicAccess , Bytes } ;
55+ use crate :: io:: { ReadVolatile , WriteVolatile } ;
5556use crate :: volatile_memory:: { self , VolatileSlice } ;
57+ use crate :: GuestMemoryError ;
5658
5759static MAX_ACCESS_CHUNK : usize = 4096 ;
5860
@@ -665,6 +667,146 @@ pub trait GuestMemory {
665667 }
666668 }
667669
670+ /// Reads up to `count` bytes from an object and writes them into guest memory at `addr`.
671+ ///
672+ /// Returns the number of bytes written into guest memory.
673+ ///
674+ /// # Arguments
675+ /// * `addr` - Begin writing at this address.
676+ /// * `src` - Copy from `src` into the container.
677+ /// * `count` - Copy `count` bytes from `src` into the container.
678+ ///
679+ /// # Examples
680+ ///
681+ /// * Read bytes from /dev/urandom (uses the `backend-mmap` feature)
682+ ///
683+ /// ```
684+ /// # #[cfg(feature = "backend-mmap")]
685+ /// # {
686+ /// # use vm_memory::{Address, GuestMemory, Bytes, GuestAddress, GuestMemoryMmap};
687+ /// # use std::fs::File;
688+ /// # use std::path::Path;
689+ /// #
690+ /// # let start_addr = GuestAddress(0x1000);
691+ /// # let gm = GuestMemoryMmap::<()>::from_ranges(&vec![(start_addr, 0x400)])
692+ /// # .expect("Could not create guest memory");
693+ /// # let addr = GuestAddress(0x1010);
694+ /// # let mut file = if cfg!(unix) {
695+ /// let mut file = File::open(Path::new("/dev/urandom")).expect("Could not open /dev/urandom");
696+ /// # file
697+ /// # } else {
698+ /// # File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe"))
699+ /// # .expect("Could not open c:\\Windows\\system32\\ntoskrnl.exe")
700+ /// # };
701+ ///
702+ /// gm.read_volatile_from(addr, &mut file, 128)
703+ /// .expect("Could not read from /dev/urandom into guest memory");
704+ ///
705+ /// let read_addr = addr.checked_add(8).expect("Could not compute read address");
706+ /// let rand_val: u32 = gm
707+ /// .read_obj(read_addr)
708+ /// .expect("Could not read u32 val from /dev/urandom");
709+ /// # }
710+ /// ```
711+ fn read_volatile_from < F > ( & self , addr : GuestAddress , src : & mut F , count : usize ) -> Result < usize >
712+ where
713+ F : ReadVolatile ,
714+ {
715+ self . try_access ( count, addr, |offset, len, caddr, region| -> Result < usize > {
716+ // Check if something bad happened before doing unsafe things.
717+ assert ! ( offset <= count) ;
718+
719+ let len = std:: cmp:: min ( len, MAX_ACCESS_CHUNK ) ;
720+
721+ let mut vslice = region. get_slice ( caddr, len) ?;
722+
723+ src. read_volatile ( & mut vslice)
724+ . map_err ( GuestMemoryError :: from)
725+ } )
726+ }
727+
728+ /// Reads up to `count` bytes from the container at `addr` and writes them it into guest memory.
729+ ///
730+ /// Returns the number of bytes written into guest memory.
731+ ///
732+ /// # Arguments
733+ /// * `addr` - Begin reading from this address.
734+ /// * `dst` - Copy from guest memory to `dst`.
735+ /// * `count` - Copy `count` bytes from guest memory to `dst`.
736+ fn write_volatile_to < F > ( & self , addr : GuestAddress , dst : & mut F , count : usize ) -> Result < usize >
737+ where
738+ F : WriteVolatile ,
739+ {
740+ self . try_access ( count, addr, |offset, len, caddr, region| -> Result < usize > {
741+ // Check if something bad happened before doing unsafe things.
742+ assert ! ( offset <= count) ;
743+
744+ let len = std:: cmp:: min ( len, MAX_ACCESS_CHUNK ) ;
745+ let vslice = region. get_slice ( caddr, len) ?;
746+
747+ // For a non-RAM region, reading could have side effects, so we
748+ // must use write_all().
749+ dst. write_all_volatile ( & vslice) ?;
750+
751+ Ok ( len)
752+ } )
753+ }
754+
755+ /// Reads exactly `count` bytes from an object and writes them into guest memory at `addr`.
756+ ///
757+ /// # Errors
758+ ///
759+ /// Returns an error if `count` bytes couldn't have been copied from `src` to guest memory.
760+ /// Part of the data may have been copied nevertheless.
761+ ///
762+ /// # Arguments
763+ /// * `addr` - Begin writing at this address.
764+ /// * `src` - Copy from `src` into guest memory.
765+ /// * `count` - Copy exactly `count` bytes from `src` into guest memory.
766+ fn read_exact_volatile_from < F > (
767+ & self ,
768+ addr : GuestAddress ,
769+ src : & mut F ,
770+ count : usize ,
771+ ) -> Result < ( ) >
772+ where
773+ F : ReadVolatile ,
774+ {
775+ let res = self . read_volatile_from ( addr, src, count) ?;
776+ if res != count {
777+ return Err ( Error :: PartialBuffer {
778+ expected : count,
779+ completed : res,
780+ } ) ;
781+ }
782+ Ok ( ( ) )
783+ }
784+
785+ /// Reads exactly `count` bytes from the container at `addr` and writes them into guest memory.
786+ ///
787+ /// # Errors
788+ ///
789+ /// Returns an error if `count` bytes couldn't have been copied from guest memory to `dst`.
790+ /// Part of the data may have been copied nevertheless.
791+ ///
792+ /// # Arguments
793+ /// * `addr` - Begin reading from this address.
794+ /// * `dst` - Copy from guest memory to `dst`.
795+ /// * `count` - Copy exactly `count` bytes from guest memory to `dst`.
796+ fn write_all_volatile_to < F > ( & self , addr : GuestAddress , dst : & mut F , count : usize ) -> Result < ( ) >
797+ where
798+ F : WriteVolatile ,
799+ {
800+ let res = self . write_volatile_to ( addr, dst, count) ?;
801+ if res != count {
802+ return Err ( Error :: PartialBuffer {
803+ expected : count,
804+ completed : res,
805+ } ) ;
806+ }
807+ Ok ( ( ) )
808+ }
809+
668810 /// Get the host virtual address corresponding to the guest address.
669811 ///
670812 /// Some [`GuestMemory`](trait.GuestMemory.html) implementations, like `GuestMemoryMmap`,
@@ -985,8 +1127,6 @@ mod tests {
9851127 #[ cfg( feature = "backend-mmap" ) ]
9861128 use crate :: GuestAddress ;
9871129 #[ cfg( feature = "backend-mmap" ) ]
988- use std:: io:: Cursor ;
989- #[ cfg( feature = "backend-mmap" ) ]
9901130 use std:: time:: { Duration , Instant } ;
9911131
9921132 use vmm_sys_util:: tempfile:: TempFile ;
@@ -1026,7 +1166,7 @@ mod tests {
10261166 let count: usize = 0x20 ;
10271167 assert_eq ! (
10281168 0x20_usize ,
1029- mem. read_from ( offset, & mut Cursor :: new ( & image) , count)
1169+ mem. read_volatile_from ( offset, & mut image. as_slice ( ) , count)
10301170 . unwrap( )
10311171 ) ;
10321172 }
@@ -1181,19 +1321,24 @@ mod tests {
11811321 assert ! ( mem. write_obj( obj, addr) . is_ok( ) ) ;
11821322 assert ! ( mem. read_obj:: <ZeroSizedStruct >( addr) . is_ok( ) ) ;
11831323
1184- assert_eq ! ( mem. read_from( addr, & mut Cursor :: new( & image) , 0 ) . unwrap( ) , 0 ) ;
1324+ assert_eq ! (
1325+ mem. read_volatile_from( addr, & mut image. as_slice( ) , 0 )
1326+ . unwrap( ) ,
1327+ 0
1328+ ) ;
11851329
11861330 assert ! ( mem
1187- . read_exact_from ( addr, & mut Cursor :: new ( & image) , 0 )
1331+ . read_exact_volatile_from ( addr, & mut image. as_slice ( ) , 0 )
11881332 . is_ok( ) ) ;
11891333
11901334 assert_eq ! (
1191- mem. write_to( addr, & mut Cursor :: new( & mut image) , 0 ) . unwrap( ) ,
1335+ mem. write_volatile_to( addr, & mut image. as_mut_slice( ) , 0 )
1336+ . unwrap( ) ,
11921337 0
11931338 ) ;
11941339
11951340 assert ! ( mem
1196- . write_all_to ( addr, & mut Cursor :: new ( & mut image) , 0 )
1341+ . write_all_volatile_to ( addr, & mut image. as_mut_slice ( ) , 0 )
11971342 . is_ok( ) ) ;
11981343 }
11991344
0 commit comments