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