summary refs log tree commit diff
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2017-06-23 20:19:05 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-06-27 10:55:46 -0700
commitb3fba4535c322ebbd4f53c69ec9b7153f9bb04d6 (patch)
tree5ca61d7071d53f5661b78cc799702c9e65d74490
parent34959d42c145cf5bb00bb429fee698df3c06a401 (diff)
downloadcrosvm-b3fba4535c322ebbd4f53c69ec9b7153f9bb04d6.tar
crosvm-b3fba4535c322ebbd4f53c69ec9b7153f9bb04d6.tar.gz
crosvm-b3fba4535c322ebbd4f53c69ec9b7153f9bb04d6.tar.bz2
crosvm-b3fba4535c322ebbd4f53c69ec9b7153f9bb04d6.tar.lz
crosvm-b3fba4535c322ebbd4f53c69ec9b7153f9bb04d6.tar.xz
crosvm-b3fba4535c322ebbd4f53c69ec9b7153f9bb04d6.tar.zst
crosvm-b3fba4535c322ebbd4f53c69ec9b7153f9bb04d6.zip
sys_util: implement VolatileMemory for Mmap and GuestMemory
Mmap and GuestMemory are the intended targets for the VolatileMemory
trait.

TEST=cargo test
BUG=None

Change-Id: Ie228b5daef691a6dcb80841be1c3dddb4b19ffc4
Reviewed-on: https://chromium-review.googlesource.com/547335
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
-rw-r--r--sys_util/src/guest_memory.rs50
-rw-r--r--sys_util/src/mmap.rs57
2 files changed, 106 insertions, 1 deletions
diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs
index f7ad298..ae96ead 100644
--- a/sys_util/src/guest_memory.rs
+++ b/sys_util/src/guest_memory.rs
@@ -9,6 +9,7 @@ use std::result;
 use std::sync::Arc;
 
 use data_model::DataInit;
+use data_model::volatile_memory::*;
 use guest_address::GuestAddress;
 use mmap::MemoryMapping;
 
@@ -56,7 +57,8 @@ impl GuestMemory {
                 }
             }
 
-            let mapping = MemoryMapping::new(range.1).map_err(|_| Error::MemoryMappingFailed)?;
+            let mapping = MemoryMapping::new(range.1)
+                .map_err(|_| Error::MemoryMappingFailed)?;
             regions.push(MemoryRegion {
                              mapping: mapping,
                              guest_base: range.0,
@@ -282,6 +284,19 @@ impl GuestMemory {
     }
 }
 
+impl VolatileMemory for GuestMemory {
+    fn get_slice(&self, offset: usize, count: usize) -> VolatileMemoryResult<VolatileSlice> {
+        for region in self.regions.iter() {
+            if offset >= region.guest_base.0 && offset < region_end(region).0 {
+                return region
+                           .mapping
+                           .get_slice(offset - region.guest_base.0, count);
+            }
+        }
+        Err(VolatileMemoryError::OutOfBounds { addr: offset })
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -316,4 +331,37 @@ mod tests {
         assert_eq!(val1, num1);
         assert_eq!(val2, num2);
     }
+
+    #[test]
+    fn test_ref_load_u64() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        let gm = GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
+
+        let val1: u64 = 0xaa55aa55aa55aa55;
+        let val2: u64 = 0x55aa55aa55aa55aa;
+        gm.write_obj_at_addr(val1, GuestAddress(0x500)).unwrap();
+        gm.write_obj_at_addr(val2, GuestAddress(0x1000 + 32))
+            .unwrap();
+        let num1: u64 = gm.get_ref(0x500).unwrap().load();
+        let num2: u64 = gm.get_ref(0x1000 + 32).unwrap().load();
+        assert_eq!(val1, num1);
+        assert_eq!(val2, num2);
+    }
+
+    #[test]
+    fn test_ref_store_u64() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        let gm = GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
+
+        let val1: u64 = 0xaa55aa55aa55aa55;
+        let val2: u64 = 0x55aa55aa55aa55aa;
+        gm.get_ref(0x500).unwrap().store(val1);
+        gm.get_ref(0x1000 + 32).unwrap().store(val2);
+        let num1: u64 = gm.read_obj_from_addr(GuestAddress(0x500)).unwrap();
+        let num2: u64 = gm.read_obj_from_addr(GuestAddress(0x1000 + 32)).unwrap();
+        assert_eq!(val1, num1);
+        assert_eq!(val2, num2);
+    }
 }
diff --git a/sys_util/src/mmap.rs b/sys_util/src/mmap.rs
index edd2a00..57627f8 100644
--- a/sys_util/src/mmap.rs
+++ b/sys_util/src/mmap.rs
@@ -11,8 +11,10 @@ use std::ptr::null_mut;
 use std::os::unix::io::AsRawFd;
 
 use libc;
+
 use errno;
 
+use data_model::volatile_memory::*;
 use data_model::DataInit;
 
 #[derive(Debug)]
@@ -281,6 +283,19 @@ impl MemoryMapping {
     }
 }
 
+impl VolatileMemory for MemoryMapping {
+    fn get_slice(&self, offset: usize, count: usize) -> VolatileMemoryResult<VolatileSlice> {
+        let mem_end = calc_offset(offset, count)?;
+        if mem_end > self.size {
+            return Err(VolatileMemoryError::OutOfBounds { addr: mem_end });
+        }
+
+        // Safe because we checked that offset + count was within our range and we only ever hand
+        // out volatile accessors.
+        Ok(unsafe { VolatileSlice::new((self.addr as usize + offset) as *mut _, count) })
+    }
+}
+
 impl Drop for MemoryMapping {
     fn drop(&mut self) {
         // This is safe because we mmap the area at addr ourselves, and nobody
@@ -294,6 +309,7 @@ impl Drop for MemoryMapping {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use data_model::{VolatileMemory, VolatileMemoryError};
 
     #[test]
     fn basic_map() {
@@ -308,4 +324,45 @@ mod tests {
         assert!(res.is_ok());
         assert_eq!(res.unwrap(), 5);
     }
+
+    #[test]
+    fn slice_size() {
+        let m = MemoryMapping::new(5).unwrap();
+        let s = m.get_slice(2, 3).unwrap();
+        assert_eq!(s.size(), 3);
+    }
+
+    #[test]
+    fn slice_addr() {
+        let m = MemoryMapping::new(5).unwrap();
+        let s = m.get_slice(2, 3).unwrap();
+        assert_eq!(s.as_ptr(), unsafe { m.as_ptr().offset(2) });
+    }
+
+    #[test]
+    fn slice_store() {
+        let m = MemoryMapping::new(5).unwrap();
+        let r = m.get_ref(2).unwrap();
+        r.store(9u16);
+        assert_eq!(m.read_obj::<u16>(2).unwrap(), 9);
+    }
+
+    #[test]
+    fn slice_overflow_error() {
+        use std::usize;
+        let m = MemoryMapping::new(5).unwrap();
+        let res = m.get_slice(usize::MAX, 3).unwrap_err();
+        assert_eq!(res,
+                   VolatileMemoryError::Overflow {
+                       base: usize::MAX,
+                       offset: 3,
+                   });
+
+    }
+    #[test]
+    fn slice_oob_error() {
+        let m = MemoryMapping::new(5).unwrap();
+        let res = m.get_slice(3, 3).unwrap_err();
+        assert_eq!(res, VolatileMemoryError::OutOfBounds { addr: 6 });
+    }
 }