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