summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--aarch64/src/fdt.rs2
-rw-r--r--devices/src/usb/xhci/event_ring.rs2
-rw-r--r--devices/src/virtio/net.rs4
-rw-r--r--devices/src/virtio/p9.rs4
-rw-r--r--kernel_loader/src/lib.rs2
-rw-r--r--kvm/tests/real_run_adder.rs2
-rw-r--r--sys_util/src/guest_memory.rs113
-rw-r--r--sys_util/src/lib.rs2
8 files changed, 102 insertions, 29 deletions
diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs
index 8690111..e6cfa0d 100644
--- a/aarch64/src/fdt.rs
+++ b/aarch64/src/fdt.rs
@@ -547,7 +547,7 @@ pub fn create_fdt(
     }
     let fdt_address = GuestAddress(AARCH64_PHYS_MEM_START + fdt_load_offset);
     let written = guest_mem
-        .write_slice_at_addr(fdt_final.as_slice(), fdt_address)
+        .write_at_addr(fdt_final.as_slice(), fdt_address)
         .map_err(|_| Error::FdtGuestMemoryWriteError)?;
     if written < fdt_max_size {
         return Err(Box::new(Error::FdtGuestMemoryWriteError));
diff --git a/devices/src/usb/xhci/event_ring.rs b/devices/src/usb/xhci/event_ring.rs
index f7f2645..b508e5a 100644
--- a/devices/src/usb/xhci/event_ring.rs
+++ b/devices/src/usb/xhci/event_ring.rs
@@ -80,7 +80,7 @@ impl EventRing {
                 .checked_add(CYCLE_STATE_OFFSET as u64)
                 .expect("unexpected address in event ring");
             self.mem
-                .write_slice_at_addr(cycle_bit_dword, address)
+                .write_at_addr(cycle_bit_dword, address)
                 .expect("Fail to write Guest Memory");
         }
 
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index dd8afd9..84249ab 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -103,7 +103,7 @@ where
                     }
                     let limit = cmp::min(write_count + desc.len as usize, self.rx_count);
                     let source_slice = &self.rx_buf[write_count..limit];
-                    let write_result = self.mem.write_slice_at_addr(source_slice, desc.addr);
+                    let write_result = self.mem.write_at_addr(source_slice, desc.addr);
 
                     match write_result {
                         Ok(sz) => {
@@ -182,7 +182,7 @@ where
                 let limit = cmp::min(read_count + desc.len as usize, frame.len());
                 let read_result = self
                     .mem
-                    .read_slice_at_addr(&mut frame[read_count..limit as usize], desc.addr);
+                    .read_at_addr(&mut frame[read_count..limit as usize], desc.addr);
                 match read_result {
                     Ok(sz) => {
                         read_count += sz;
diff --git a/devices/src/virtio/p9.rs b/devices/src/virtio/p9.rs
index e9bdbb7..50ceedb 100644
--- a/devices/src/virtio/p9.rs
+++ b/devices/src/virtio/p9.rs
@@ -135,7 +135,7 @@ where
             let len = min(buf.len(), (current.len - self.offset) as usize);
             let count = self
                 .mem
-                .read_slice_at_addr(&mut buf[..len], addr)
+                .read_at_addr(&mut buf[..len], addr)
                 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
 
             // |count| has to fit into a u32 because it must be less than or equal to
@@ -191,7 +191,7 @@ where
             let len = min(buf.len(), (current.len - self.offset) as usize);
             let count = self
                 .mem
-                .write_slice_at_addr(&buf[..len], addr)
+                .write_at_addr(&buf[..len], addr)
                 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
 
             // |count| has to fit into a u32 because it must be less than or equal to
diff --git a/kernel_loader/src/lib.rs b/kernel_loader/src/lib.rs
index 42b43de..13ada13 100644
--- a/kernel_loader/src/lib.rs
+++ b/kernel_loader/src/lib.rs
@@ -163,7 +163,7 @@ pub fn load_cmdline(
     }
 
     guest_mem
-        .write_slice_at_addr(cmdline.to_bytes_with_nul(), guest_addr)
+        .write_at_addr(cmdline.to_bytes_with_nul(), guest_addr)
         .map_err(|_| Error::CommandLineCopy)?;
 
     Ok(())
diff --git a/kvm/tests/real_run_adder.rs b/kvm/tests/real_run_adder.rs
index 0ca695f..5a7b536 100644
--- a/kvm/tests/real_run_adder.rs
+++ b/kvm/tests/real_run_adder.rs
@@ -35,7 +35,7 @@ fn test_run() {
     let vcpu = Vcpu::new(0, &kvm, &vm).expect("new vcpu failed");
 
     vm.get_memory()
-        .write_slice_at_addr(&code, load_addr)
+        .write_at_addr(&code, load_addr)
         .expect("Writing code to memory failed.");
 
     let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs
index 157800c..99902ba 100644
--- a/sys_util/src/guest_memory.rs
+++ b/sys_util/src/guest_memory.rs
@@ -4,7 +4,6 @@
 
 //! Track memory regions that are mapped to the guest VM.
 
-use std::error::{self, Error as GuestMemoryError};
 use std::fmt::{self, Display};
 use std::io::{Read, Write};
 use std::result;
@@ -21,23 +20,38 @@ pub enum Error {
     MemoryAccess(GuestAddress, mmap::Error),
     MemoryMappingFailed(mmap::Error),
     MemoryRegionOverlap,
+    ShortWrite { expected: usize, completed: usize },
+    ShortRead { expected: usize, completed: usize },
 }
 pub type Result<T> = result::Result<T, Error>;
 
-impl error::Error for Error {
-    fn description(&self) -> &str {
-        match self {
-            Error::InvalidGuestAddress(_) => "Invalid Guest Address",
-            Error::MemoryAccess(_, _) => "Invalid Guest Memory Access",
-            Error::MemoryMappingFailed(_) => "Failed to map guest memory",
-            Error::MemoryRegionOverlap => "Memory regions overlap",
-        }
-    }
-}
+impl std::error::Error for Error {}
 
 impl Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Guest memory error: {}", Error::description(self))
+        write!(f, "Guest memory error: ")?;
+        match self {
+            Error::InvalidGuestAddress(_) => write!(f, "Invalid Guest Address"),
+            Error::MemoryAccess(_, _) => write!(f, "Invalid Guest Memory Access"),
+            Error::MemoryMappingFailed(_) => write!(f, "Failed to map guest memory"),
+            Error::MemoryRegionOverlap => write!(f, "Memory regions overlap"),
+            Error::ShortWrite {
+                expected,
+                completed,
+            } => write!(
+                f,
+                "incomplete write of {} instead of {} bytes",
+                completed, expected,
+            ),
+            Error::ShortRead {
+                expected,
+                completed,
+            } => write!(
+                f,
+                "incomplete read of {} instead of {} bytes",
+                completed, expected,
+            ),
+        }
     }
 }
 
@@ -156,6 +170,7 @@ impl GuestMemory {
         }
         Ok(())
     }
+
     /// Writes a slice to guest memory at the specified guest address.
     /// Returns the number of bytes written.  The number of bytes written can
     /// be less than the length of the slice if there isn't enough room in the
@@ -169,12 +184,12 @@ impl GuestMemory {
     /// # fn test_write_u64() -> Result<(), ()> {
     /// #   let start_addr = GuestAddress(0x1000);
     /// #   let mut gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
-    ///     let res = gm.write_slice_at_addr(&[1,2,3,4,5], GuestAddress(0x200)).map_err(|_| ())?;
+    ///     let res = gm.write_at_addr(&[1,2,3,4,5], GuestAddress(0x200)).map_err(|_| ())?;
     ///     assert_eq!(5, res);
     ///     Ok(())
     /// # }
     /// ```
-    pub fn write_slice_at_addr(&self, buf: &[u8], guest_addr: GuestAddress) -> Result<usize> {
+    pub fn write_at_addr(&self, buf: &[u8], guest_addr: GuestAddress) -> Result<usize> {
         self.do_in_region(guest_addr, move |mapping, offset| {
             mapping
                 .write_slice(buf, offset)
@@ -182,6 +197,37 @@ impl GuestMemory {
         })
     }
 
+    /// Writes the entire contents of a slice to guest memory at the specified
+    /// guest address.
+    ///
+    /// Returns an error if there isn't enough room in the memory region to
+    /// complete the entire write. Part of the data may have been written
+    /// nevertheless.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use sys_util::{guest_memory, GuestAddress, GuestMemory};
+    ///
+    /// fn test_write_all() -> guest_memory::Result<()> {
+    ///     let ranges = &[(GuestAddress(0x1000), 0x400)];
+    ///     let gm = GuestMemory::new(ranges)?;
+    ///     gm.write_all_at_addr(b"zyxwvut", GuestAddress(0x1200))
+    /// }
+    /// ```
+    pub fn write_all_at_addr(&self, buf: &[u8], guest_addr: GuestAddress) -> Result<()> {
+        let expected = buf.len();
+        let completed = self.write_at_addr(buf, guest_addr)?;
+        if expected == completed {
+            Ok(())
+        } else {
+            Err(Error::ShortWrite {
+                expected,
+                completed,
+            })
+        }
+    }
+
     /// Reads to a slice from guest memory at the specified guest address.
     /// Returns the number of bytes read.  The number of bytes read can
     /// be less than the length of the slice if there isn't enough room in the
@@ -196,16 +242,12 @@ impl GuestMemory {
     /// #   let start_addr = GuestAddress(0x1000);
     /// #   let mut gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
     ///     let buf = &mut [0u8; 16];
-    ///     let res = gm.read_slice_at_addr(buf, GuestAddress(0x200)).map_err(|_| ())?;
+    ///     let res = gm.read_at_addr(buf, GuestAddress(0x200)).map_err(|_| ())?;
     ///     assert_eq!(16, res);
     ///     Ok(())
     /// # }
     /// ```
-    pub fn read_slice_at_addr(
-        &self,
-        mut buf: &mut [u8],
-        guest_addr: GuestAddress,
-    ) -> Result<usize> {
+    pub fn read_at_addr(&self, mut buf: &mut [u8], guest_addr: GuestAddress) -> Result<usize> {
         self.do_in_region(guest_addr, move |mapping, offset| {
             mapping
                 .read_slice(buf, offset)
@@ -213,6 +255,37 @@ impl GuestMemory {
         })
     }
 
+    /// Reads from guest memory at the specified address to fill the entire
+    /// buffer.
+    ///
+    /// Returns an error if there isn't enough room in the memory region to fill
+    /// the entire buffer. Part of the buffer may have been filled nevertheless.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use sys_util::{guest_memory, GuestAddress, GuestMemory, MemoryMapping};
+    ///
+    /// fn test_read_exact() -> guest_memory::Result<()> {
+    ///     let ranges = &[(GuestAddress(0x1000), 0x400)];
+    ///     let gm = GuestMemory::new(ranges)?;
+    ///     let mut buffer = [0u8; 0x200];
+    ///     gm.read_exact_at_addr(&mut buffer, GuestAddress(0x1200))
+    /// }
+    /// ```
+    pub fn read_exact_at_addr(&self, buf: &mut [u8], guest_addr: GuestAddress) -> Result<()> {
+        let expected = buf.len();
+        let completed = self.read_at_addr(buf, guest_addr)?;
+        if expected == completed {
+            Ok(())
+        } else {
+            Err(Error::ShortRead {
+                expected,
+                completed,
+            })
+        }
+    }
+
     /// Reads an object from guest memory at the given guest address.
     /// Reading from a volatile area isn't strictly safe as it could change
     /// mid-read.  However, as long as the type T is plain old data and can
diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs
index a0c53a3..62cfc9e 100644
--- a/sys_util/src/lib.rs
+++ b/sys_util/src/lib.rs
@@ -24,7 +24,7 @@ mod file_flags;
 mod file_traits;
 mod fork;
 mod guest_address;
-mod guest_memory;
+pub mod guest_memory;
 mod mmap;
 pub mod net;
 mod passwd;