1 // Copyright 2020 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::fmt::{self, Display}; 6 7 use data_model::VolatileSlice; 8 9 #[derive(Debug)] 10 pub enum Error { 11 /// Invalid offset or length given for an iovec in backing memory. 12 InvalidOffset(u64, usize), 13 } 14 pub type Result<T> = std::result::Result<T, Error>; 15 16 impl Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result17 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 18 use self::Error::*; 19 20 match self { 21 InvalidOffset(base, len) => write!( 22 f, 23 "Invalid offset/len for getting a slice from {} with len {}.", 24 base, len 25 ), 26 } 27 } 28 } 29 impl std::error::Error for Error {} 30 31 /// Used to index subslices of backing memory. Like an iovec, but relative to the start of the 32 /// memory region instead of an absolute pointer. 33 /// The backing memory referenced by the region can be an array, an mmapped file, or guest memory. 34 /// The offset is a u64 to allow having file or guest offsets >4GB when run on a 32bit host. 35 #[derive(Copy, Clone, Debug)] 36 pub struct MemRegion { 37 pub offset: u64, 38 pub len: usize, 39 } 40 41 /// Trait for memory that can yeild both iovecs in to the backing memory. 42 /// Must be OK to modify the backing memory without owning a mut able reference. For example, 43 /// this is safe for GuestMemory and VolatileSlices in crosvm as those types guarantee they are 44 /// dealt with as volatile. 45 pub unsafe trait BackingMemory { 46 /// Returns VolatileSlice pointing to the backing memory. This is most commonly unsafe. 47 /// To implement this safely the implementor must guarantee that the backing memory can be 48 /// modified out of band without affecting safety guarantees. get_volatile_slice(&self, mem_range: MemRegion) -> Result<VolatileSlice>49 fn get_volatile_slice(&self, mem_range: MemRegion) -> Result<VolatileSlice>; 50 } 51 52 /// Wrapper to be used for passing a Vec in as backing memory for asynchronous operations. The 53 /// wrapper owns a Vec according to the borrow checker. It is loaning this vec out to the kernel(or 54 /// other modifiers) through the `BackingMemory` trait. This allows multiple modifiers of the array 55 /// in the `Vec` while this struct is alive. The data in the Vec is loaned to the kernel not the 56 /// data structure itself, the length, capacity, and pointer to memory cannot be modified. 57 /// To ensure that those operations can be done safely, no access is allowed to the `Vec`'s memory 58 /// starting at the time that `VecIoWrapper` is constructed until the time it is turned back in to a 59 /// `Vec` using `to_inner`. The returned `Vec` is guaranteed to be valid as any combination of bits 60 /// in a `Vec` of `u8` is valid. 61 pub(crate) struct VecIoWrapper { 62 inner: Box<[u8]>, 63 } 64 65 impl From<Vec<u8>> for VecIoWrapper { from(vec: Vec<u8>) -> Self66 fn from(vec: Vec<u8>) -> Self { 67 VecIoWrapper { inner: vec.into() } 68 } 69 } 70 71 impl Into<Vec<u8>> for VecIoWrapper { into(self) -> Vec<u8>72 fn into(self) -> Vec<u8> { 73 self.inner.into() 74 } 75 } 76 77 impl VecIoWrapper { 78 /// Get the length of the Vec that is wrapped. len(&self) -> usize79 pub fn len(&self) -> usize { 80 self.inner.len() 81 } 82 83 // Check that the offsets are all valid in the backing vec. check_addrs(&self, mem_range: &MemRegion) -> Result<()>84 fn check_addrs(&self, mem_range: &MemRegion) -> Result<()> { 85 let end = mem_range 86 .offset 87 .checked_add(mem_range.len as u64) 88 .ok_or(Error::InvalidOffset(mem_range.offset, mem_range.len))?; 89 if end > self.inner.len() as u64 { 90 return Err(Error::InvalidOffset(mem_range.offset, mem_range.len)); 91 } 92 Ok(()) 93 } 94 } 95 96 // Safe to implement BackingMemory as the vec is only accessible inside the wrapper and these iovecs 97 // are the only thing allowed to modify it. Nothing else can get a reference to the vec until all 98 // iovecs are dropped because they borrow Self. Nothing can borrow the owned inner vec until self 99 // is consumed by `into`, which can't happen if there are outstanding mut borrows. 100 unsafe impl BackingMemory for VecIoWrapper { get_volatile_slice(&self, mem_range: MemRegion) -> Result<VolatileSlice<'_>>101 fn get_volatile_slice(&self, mem_range: MemRegion) -> Result<VolatileSlice<'_>> { 102 self.check_addrs(&mem_range)?; 103 // Safe because the mem_range range is valid in the backing memory as checked above. 104 unsafe { 105 Ok(VolatileSlice::from_raw_parts( 106 self.inner.as_ptr().add(mem_range.offset as usize) as *mut _, 107 mem_range.len, 108 )) 109 } 110 } 111 } 112