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.
45//! A convenience crate for Zircon VMO objects mapped into memory.
67#![deny(missing_docs)]
89use fuchsia_runtime::vmar_root_self;
10use shared_buffer::SharedBuffer;
11use std::ops::{Deref, DerefMut};
12use zx::{self as zx, AsHandleRef};
1314mod immutable;
15pub use immutable::{Error as ImmutableMappingError, ImmutableMapping};
1617/// 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}
2728impl Deref for Mapping {
29type Target = SharedBuffer;
30fn deref(&self) -> &Self::Target {
31&self.buffer
32 }
33}
3435impl DerefMut for Mapping {
36fn deref_mut(&mut self) -> &mut Self::Target {
37&mut self.buffer
38 }
39}
4041impl 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.
46pub fn allocate(size: usize) -> Result<(Self, zx::Vmo), zx::Status> {
47let vmo = zx::Vmo::create(size as u64)?;
48let flags = zx::VmarFlags::PERM_READ
49 | zx::VmarFlags::PERM_WRITE
50 | zx::VmarFlags::MAP_RANGE
51 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
52let mapping = Self::create_from_vmo(&vmo, size, flags)?;
53Ok((mapping, vmo))
54 }
5556/// 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.
60pub fn allocate_with_name(size: usize, name: &str) -> Result<(Self, zx::Vmo), zx::Status> {
61let name = zx::Name::new(name)?;
62let vmo = zx::Vmo::create(size as u64)?;
63 vmo.set_name(&name)?;
64let flags = zx::VmarFlags::PERM_READ
65 | zx::VmarFlags::PERM_WRITE
66 | zx::VmarFlags::MAP_RANGE
67 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
68let mapping = Self::create_from_vmo(&vmo, size, flags)?;
69Ok((mapping, vmo))
70 }
7172/// 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.
76pub fn create_from_vmo(
77 vmo: &zx::Vmo,
78 size: usize,
79 flags: zx::VmarFlags,
80 ) -> Result<Self, zx::Status> {
81let flags = flags | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
82let addr = vmar_root_self().map(0, &vmo, 0, size, flags)?;
8384// 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.
94let buffer = unsafe { SharedBuffer::new(addr as *mut u8, size) };
95Ok(Mapping { buffer })
96 }
9798/// Return the size of the mapping.
99pub fn len(&self) -> usize {
100self.buffer.len()
101 }
102}
103104impl Drop for Mapping {
105fn drop(&mut self) {
106let (addr, size): (*mut u8, usize) = self.buffer.as_ptr_len();
107let addr = addr as usize;
108109// 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.
115unsafe {
116let _ = vmar_root_self().unmap(addr, size);
117 }
118 }
119}
120121#[cfg(test)]
122mod tests {
123use super::*;
124125const PAGE_SIZE: usize = 4096;
126127#[test]
128fn test_create() {
129let size = PAGE_SIZE;
130let (mapping, _vmo) = Mapping::allocate(size).unwrap();
131assert_eq!(size, mapping.len());
132 }
133134#[test]
135fn test_create_from_vmo() {
136let size = PAGE_SIZE;
137let flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
138 {
139// Mapping::create_from_vmo requires a non-resizable vmo
140let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size as u64).unwrap();
141let status = Mapping::create_from_vmo(&vmo, size, flags).unwrap_err();
142assert_eq!(status, zx::Status::NOT_SUPPORTED);
143 }
144 {
145let vmo = zx::Vmo::create(size as u64).unwrap();
146let mapping = Mapping::create_from_vmo(&vmo, size, flags).unwrap();
147assert_eq!(size, mapping.len());
148 }
149 }
150151#[test]
152fn test_create_with_name() {
153let size = PAGE_SIZE;
154let (mapping, vmo) = Mapping::allocate_with_name(size, "TestName").unwrap();
155assert_eq!(size, mapping.len());
156assert_eq!("TestName", vmo.get_name().expect("Has name"));
157let res = Mapping::allocate_with_name(size, "Invalid\0TestName");
158assert_eq!(zx::Status::INVALID_ARGS, res.unwrap_err());
159 }
160161#[test]
162fn test_mapping_read_write() {
163let size = PAGE_SIZE;
164let (mapping, vmo) = Mapping::allocate(size).unwrap();
165166let mut buf = [0; 128];
167168// We can write to the Vmo, and see the results in the mapping.
169let s = b"Hello world";
170 vmo.write(s, 0).unwrap();
171let slice = &mut buf[0..s.len()];
172 mapping.read(slice);
173assert_eq!(s, slice);
174175// We can write to the mapping, and see the results in the Vmo.
176let s = b"Goodbye world";
177 mapping.write(s);
178let slice = &mut buf[0..s.len()];
179 vmo.read(slice, 0).unwrap();
180assert_eq!(s, slice);
181 }
182}