mapped_vmo/
lib.rs

1// Copyright 2018 The Fuchsia 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//! A convenience crate for Zircon VMO objects mapped into memory.
6
7#![deny(missing_docs)]
8
9use fuchsia_runtime::vmar_root_self;
10use shared_buffer::SharedBuffer;
11use std::ops::{Deref, DerefMut};
12use zx::{self as zx, AsHandleRef};
13
14mod immutable;
15pub use immutable::{Error as ImmutableMappingError, ImmutableMapping};
16
17/// A safe wrapper around a mapped region of memory.
18///
19/// Note: this type implements `Deref`/`DerefMut` to the `SharedBuffer`
20/// type, which allows reading/writing from the underlying memory.
21/// Aside from creation and the `Drop` impl, all of the interesting
22/// functionality of this type is offered via `SharedBuffer`.
23#[derive(Debug)]
24pub struct Mapping {
25    buffer: SharedBuffer,
26}
27
28impl Deref for Mapping {
29    type Target = SharedBuffer;
30    fn deref(&self) -> &Self::Target {
31        &self.buffer
32    }
33}
34
35impl DerefMut for Mapping {
36    fn deref_mut(&mut self) -> &mut Self::Target {
37        &mut self.buffer
38    }
39}
40
41impl Mapping {
42    /// Create a `Mapping` and map it in the root address space.
43    /// Returns the VMO that was mapped.
44    ///
45    /// The resulting VMO will not be resizeable.
46    pub fn allocate(size: usize) -> Result<(Self, zx::Vmo), zx::Status> {
47        let vmo = zx::Vmo::create(size as u64)?;
48        let flags = zx::VmarFlags::PERM_READ
49            | zx::VmarFlags::PERM_WRITE
50            | zx::VmarFlags::MAP_RANGE
51            | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
52        let mapping = Self::create_from_vmo(&vmo, size, flags)?;
53        Ok((mapping, vmo))
54    }
55
56    /// Create a `Mapping` and map it in the root address space.
57    /// Returns the VMO that was mapped.
58    ///
59    /// The resulting VMO will not be resizeable.
60    pub fn allocate_with_name(size: usize, name: &str) -> Result<(Self, zx::Vmo), zx::Status> {
61        let name = zx::Name::new(name)?;
62        let vmo = zx::Vmo::create(size as u64)?;
63        vmo.set_name(&name)?;
64        let flags = zx::VmarFlags::PERM_READ
65            | zx::VmarFlags::PERM_WRITE
66            | zx::VmarFlags::MAP_RANGE
67            | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
68        let mapping = Self::create_from_vmo(&vmo, size, flags)?;
69        Ok((mapping, vmo))
70    }
71
72    /// Create a `Mapping` from an existing VMO.
73    ///
74    /// Requires that the VMO was not created with the `RESIZABLE`
75    /// option, and returns `ZX_ERR_NOT_SUPPORTED` otherwise.
76    pub fn create_from_vmo(
77        vmo: &zx::Vmo,
78        size: usize,
79        flags: zx::VmarFlags,
80    ) -> Result<Self, zx::Status> {
81        let flags = flags | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
82        let addr = vmar_root_self().map(0, &vmo, 0, size, flags)?;
83
84        // Safety:
85        //
86        // The memory behind this `SharedBuffer` is only accessible via
87        // methods on `SharedBuffer`.
88        //
89        // The underlying memory is accessible during any accesses to `SharedBuffer`:
90        // - It is only unmapped on `drop`
91        // - `SharedBuffer` is never exposed in a way that would allow it to live longer than
92        //   the `Mapping` itself
93        // - The underlying VMO is non-resizeable.
94        let buffer = unsafe { SharedBuffer::new(addr as *mut u8, size) };
95        Ok(Mapping { buffer })
96    }
97
98    /// Return the size of the mapping.
99    pub fn len(&self) -> usize {
100        self.buffer.len()
101    }
102}
103
104impl Drop for Mapping {
105    fn drop(&mut self) {
106        let (addr, size): (*mut u8, usize) = self.buffer.as_ptr_len();
107        let addr = addr as usize;
108
109        // Safety:
110        //
111        // The memory behind this `SharedBuffer` is only accessible
112        // via references to the internal `SharedBuffer`, which must
113        // have all been invalidated at this point. The memory is
114        // therefore safe to unmap.
115        unsafe {
116            let _ = vmar_root_self().unmap(addr, size);
117        }
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    const PAGE_SIZE: usize = 4096;
126
127    #[test]
128    fn test_create() {
129        let size = PAGE_SIZE;
130        let (mapping, _vmo) = Mapping::allocate(size).unwrap();
131        assert_eq!(size, mapping.len());
132    }
133
134    #[test]
135    fn test_create_from_vmo() {
136        let size = PAGE_SIZE;
137        let flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
138        {
139            // Mapping::create_from_vmo requires a non-resizable vmo
140            let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size as u64).unwrap();
141            let status = Mapping::create_from_vmo(&vmo, size, flags).unwrap_err();
142            assert_eq!(status, zx::Status::NOT_SUPPORTED);
143        }
144        {
145            let vmo = zx::Vmo::create(size as u64).unwrap();
146            let mapping = Mapping::create_from_vmo(&vmo, size, flags).unwrap();
147            assert_eq!(size, mapping.len());
148        }
149    }
150
151    #[test]
152    fn test_create_with_name() {
153        let size = PAGE_SIZE;
154        let (mapping, vmo) = Mapping::allocate_with_name(size, "TestName").unwrap();
155        assert_eq!(size, mapping.len());
156        assert_eq!("TestName", vmo.get_name().expect("Has name"));
157        let res = Mapping::allocate_with_name(size, "Invalid\0TestName");
158        assert_eq!(zx::Status::INVALID_ARGS, res.unwrap_err());
159    }
160
161    #[test]
162    fn test_mapping_read_write() {
163        let size = PAGE_SIZE;
164        let (mapping, vmo) = Mapping::allocate(size).unwrap();
165
166        let mut buf = [0; 128];
167
168        // We can write to the Vmo, and see the results in the mapping.
169        let s = b"Hello world";
170        vmo.write(s, 0).unwrap();
171        let slice = &mut buf[0..s.len()];
172        mapping.read(slice);
173        assert_eq!(s, slice);
174
175        // We can write to the mapping, and see the results in the Vmo.
176        let s = b"Goodbye world";
177        mapping.write(s);
178        let slice = &mut buf[0..s.len()];
179        vmo.read(slice, 0).unwrap();
180        assert_eq!(s, slice);
181    }
182}