crosvm_data_model/sys/
unix.rs

1// Copyright 2020 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::ffi::c_void;
6use std::fmt;
7use std::fmt::Debug;
8use std::marker::PhantomData;
9use std::slice;
10
11use libc::iovec;
12
13/// Cross platform binary compatible iovec.
14pub type IoBuf = iovec;
15
16/// Cross platform stub to create a platform specific IoBuf.
17pub fn create_iobuf(addr: *mut u8, len: usize) -> IoBuf {
18    iovec {
19        iov_base: addr as *mut c_void,
20        iov_len: len,
21    }
22}
23
24/// This type is essentialy `std::io::IoBufMut`, and guaranteed to be ABI-compatible with
25/// `libc::iovec`; however, it does NOT automatically deref to `&mut [u8]`, which is critical
26/// because it can point to guest memory. (Guest memory is implicitly mutably borrowed by the
27/// guest, so another mutable borrow would violate Rust assumptions about references.)
28#[derive(Copy, Clone)]
29#[repr(transparent)]
30pub struct IoBufMut<'a> {
31    iov: iovec,
32    phantom: PhantomData<&'a mut [u8]>,
33}
34
35impl<'a> IoBufMut<'a> {
36    pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {
37        // Safe because buf's memory is of the supplied length, and
38        // guaranteed to exist for the lifetime of the returned value.
39        unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }
40    }
41
42    /// Creates a `IoBufMut` from a pointer and a length.
43    ///
44    /// # Safety
45    ///
46    /// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes
47    /// and should live for the entire duration of lifetime `'a`.
48    pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {
49        IoBufMut {
50            iov: iovec {
51                iov_base: addr as *mut c_void,
52                iov_len: len,
53            },
54            phantom: PhantomData,
55        }
56    }
57
58    /// Creates a `IoBufMut` from an IoBuf.
59    ///
60    /// # Safety
61    ///
62    /// In order to use this method safely, `iobuf` must be valid for reads and writes through its
63    /// length and should live for the entire duration of lifetime `'a`.
64    pub unsafe fn from_iobuf(iobuf: IoBuf) -> IoBufMut<'a> {
65        IoBufMut {
66            iov: iobuf,
67            phantom: PhantomData,
68        }
69    }
70
71    /// Advance the internal position of the buffer.
72    ///
73    /// Panics if `count > self.len()`.
74    pub fn advance(&mut self, count: usize) {
75        assert!(count <= self.len());
76
77        self.iov.iov_len -= count;
78        // Safe because we've checked that `count <= self.len()` so both the starting and resulting
79        // pointer are within the bounds of the allocation.
80        self.iov.iov_base = unsafe { self.iov.iov_base.add(count) };
81    }
82
83    /// Shorten the length of the buffer.
84    ///
85    /// Has no effect if `len > self.len()`.
86    pub fn truncate(&mut self, len: usize) {
87        if len < self.len() {
88            self.iov.iov_len = len;
89        }
90    }
91
92    #[inline]
93    pub fn len(&self) -> usize {
94        self.iov.iov_len as usize
95    }
96
97    #[inline]
98    pub fn is_empty(&self) -> bool {
99        self.iov.iov_len == 0
100    }
101
102    /// Gets a const pointer to this slice's memory.
103    #[inline]
104    pub fn as_ptr(&self) -> *const u8 {
105        self.iov.iov_base as *const u8
106    }
107
108    /// Gets a mutable pointer to this slice's memory.
109    #[inline]
110    pub fn as_mut_ptr(&self) -> *mut u8 {
111        self.iov.iov_base as *mut u8
112    }
113
114    /// Converts a slice of `IoBufMut`s into a slice of `iovec`s.
115    #[allow(clippy::wrong_self_convention)]
116    #[inline]
117    pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [iovec] {
118        // Safe because `IoBufMut` is ABI-compatible with `iovec`.
119        unsafe { slice::from_raw_parts(iovs.as_ptr() as *const libc::iovec, iovs.len()) }
120    }
121}
122
123impl<'a> AsRef<libc::iovec> for IoBufMut<'a> {
124    fn as_ref(&self) -> &libc::iovec {
125        &self.iov
126    }
127}
128
129impl<'a> AsMut<libc::iovec> for IoBufMut<'a> {
130    fn as_mut(&mut self) -> &mut libc::iovec {
131        &mut self.iov
132    }
133}
134
135// It's safe to implement Send + Sync for this type for the same reason that `std::io::IoBufMut`
136// is Send + Sync. Internally, it contains a pointer and a length. The integer length is safely Send
137// + Sync.  There's nothing wrong with sending a pointer between threads and de-referencing the
138// pointer requires an unsafe block anyway. See also https://github.com/rust-lang/rust/pull/70342.
139unsafe impl<'a> Send for IoBufMut<'a> {}
140unsafe impl<'a> Sync for IoBufMut<'a> {}
141
142struct DebugIovec(iovec);
143impl Debug for DebugIovec {
144    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145        f.debug_struct("iovec")
146            .field("iov_base", &self.0.iov_base)
147            .field("iov_len", &self.0.iov_len)
148            .finish()
149    }
150}
151
152impl<'a> Debug for IoBufMut<'a> {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        f.debug_struct("IoBufMut")
155            .field("iov", &DebugIovec(self.iov))
156            .field("phantom", &self.phantom)
157            .finish()
158    }
159}