• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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