diff options
Diffstat (limited to 'devices/src/virtio/mod.rs')
-rw-r--r-- | devices/src/virtio/mod.rs | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/devices/src/virtio/mod.rs b/devices/src/virtio/mod.rs index 0970b86..49f4355 100644 --- a/devices/src/virtio/mod.rs +++ b/devices/src/virtio/mod.rs @@ -43,6 +43,9 @@ pub use self::virtio_device::*; pub use self::virtio_pci_device::*; pub use self::wl::*; +use std::cmp; +use std::convert::TryFrom; + const DEVICE_ACKNOWLEDGE: u32 = 0x01; const DEVICE_DRIVER: u32 = 0x02; const DEVICE_DRIVER_OK: u32 = 0x04; @@ -88,3 +91,27 @@ pub fn type_to_str(type_: u32) -> Option<&'static str> { _ => return None, }) } + +/// Copy virtio device configuration data from a subslice of `src` to a subslice of `dst`. +/// Unlike std::slice::copy_from_slice(), this function copies as much as possible within +/// the common subset of the two slices, truncating the requested range instead of +/// panicking if the slices do not match in size. +/// +/// `dst_offset` and `src_offset` specify the starting indexes of the `dst` and `src` +/// slices, respectively; if either index is out of bounds, this function is a no-op +/// rather than panicking. This makes it safe to call with arbitrary user-controlled +/// inputs. +pub fn copy_config(dst: &mut [u8], dst_offset: u64, src: &[u8], src_offset: u64) { + if let Ok(dst_offset) = usize::try_from(dst_offset) { + if let Ok(src_offset) = usize::try_from(src_offset) { + if let Some(dst_slice) = dst.get_mut(dst_offset..) { + if let Some(src_slice) = src.get(src_offset..) { + let len = cmp::min(dst_slice.len(), src_slice.len()); + let dst_subslice = &mut dst_slice[0..len]; + let src_subslice = &src_slice[0..len]; + dst_subslice.copy_from_slice(src_subslice); + } + } + } + } +} |