diff options
-rw-r--r-- | aarch64/src/fdt.rs | 2 | ||||
-rw-r--r-- | devices/src/usb/xhci/event_ring.rs | 2 | ||||
-rw-r--r-- | devices/src/virtio/net.rs | 4 | ||||
-rw-r--r-- | devices/src/virtio/p9.rs | 4 | ||||
-rw-r--r-- | kernel_loader/src/lib.rs | 2 | ||||
-rw-r--r-- | kvm/tests/real_run_adder.rs | 2 | ||||
-rw-r--r-- | sys_util/src/guest_memory.rs | 113 | ||||
-rw-r--r-- | sys_util/src/lib.rs | 2 |
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; |