Skip to main content

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