blob: 97b83ad6371edcb16748b98d675263ef1bfe7ee9 [file] [log] [blame]
// 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 vmars.
#![deny(warnings)]
#![deny(missing_docs)]
use fuchsia_zircon::{self as zx, VmarFlags};
/// An object representing a mapping into an address space.
#[derive(Debug)]
pub struct Mapping {
addr: usize,
size: usize,
}
impl Mapping {
/// Create a Mapping and map it in the root address space.
pub fn create(size: usize, flags: VmarFlags) -> Result<Self, zx::Status> {
let vmo = zx::Vmo::create(size as u64)?;
let addr = zx::Vmar::root_self().map(0, &vmo, 0, size, flags)?;
Ok(Mapping {
addr,
size,
})
}
/// Create a Mapping from an existing Vmo and map it in the root
/// address space.
pub fn create_from_vmo(vmo: &zx::Vmo, size: usize, flags: VmarFlags) ->
Result<Self, zx::Status> {
let addr = zx::Vmar::root_self().map(0, vmo, 0, size, flags)?;
Ok(Mapping {
addr,
size,
})
}
/// Return the size of the mapping.
pub fn size(&self) -> usize {
self.size
}
/// Return a raw pointer to the mapping.
pub fn as_ptr(&self) -> *const u8 {
self.addr as *const u8
}
/// Return a raw mutable pointer to the mapping.
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.addr as *mut u8
}
// Internal helper to release the current mapping.
//
// Should be used with caution, as "addr" and "size"
// will effectively have no meaning after this function
// completes.
unsafe fn release(&mut self) {
zx::Vmar::root_self().unmap(self.addr, self.size as usize).ok();
}
}
impl Drop for Mapping {
fn drop(&mut self) {
unsafe {
self.release()
}
}
}
/// An object representing a Vmo mapped into an address space.
#[derive(Debug)]
pub struct MappedVmo {
vmo: zx::Vmo,
mapping: Mapping,
}
impl MappedVmo {
/// Create a MappedVmo and map it in the root address space.
pub fn create(size: usize, flags: VmarFlags) -> Result<Self, zx::Status> {
let vmo = zx::Vmo::create(size as u64)?;
let mapping = Mapping::create_from_vmo(&vmo, size, flags)?;
Ok(MappedVmo {
vmo,
mapping,
})
}
/// Create a MappedVmo from an existing Vmo and map it in the root
/// address space.
pub fn create_from_vmo(vmo: zx::Vmo, size: usize, flags: VmarFlags) ->
Result<Self, zx::Status> {
let mapping = Mapping::create_from_vmo(&vmo, size, flags)?;
Ok(MappedVmo {
vmo,
mapping,
})
}
/// Resizes the Vmo and initializes a new mapping.
///
/// This invalidates all raw pointers previously returned
/// from the MappedVmo.
pub fn resize(&mut self, size: usize, flags: VmarFlags) -> Result<(), zx::Status> {
self.vmo.set_size(size as u64)?;
let addr = zx::Vmar::root_self().map(0, &self.vmo, 0, size, flags)?;
unsafe {
self.mapping.release();
}
self.mapping.addr = addr;
self.mapping.size = size;
Ok(())
}
/// Return the size of the mapping.
pub fn size(&self) -> usize {
self.mapping.size
}
/// Return an immutable reference to the underlying Vmo.
pub fn vmo(&self) -> &zx::Vmo {
&self.vmo
}
/// Return a raw pointer to the mapping.
pub fn as_ptr(&self) -> *const u8 {
self.mapping.as_ptr()
}
/// Return a raw mutable pointer to the mapping.
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.mapping.as_mut_ptr()
}
}
#[cfg(test)]
mod tests {
use super::*;
use {
fuchsia_zircon as zx,
std::slice,
};
const PAGE_SIZE: usize = 4096;
#[test]
fn test_create() {
let size = PAGE_SIZE;
let flags = VmarFlags::PERM_READ | VmarFlags::PERM_WRITE;
let mapping = Mapping::create(size, flags).unwrap();
assert_eq!(size, mapping.size());
}
#[test]
fn test_create_from_vmo() {
let size = PAGE_SIZE;
let flags = VmarFlags::PERM_READ | VmarFlags::PERM_WRITE;
let vmo = zx::Vmo::create(size as u64).unwrap();
let mapping = Mapping::create_from_vmo(&vmo, size, flags).unwrap();
assert_eq!(size, mapping.size());
}
#[test]
fn test_mapping_read_write() {
let size = PAGE_SIZE;
let flags = VmarFlags::PERM_READ | VmarFlags::PERM_WRITE;
let vmo = zx::Vmo::create(size as u64).unwrap();
let mut mapping = Mapping::create_from_vmo(&vmo, size, flags).unwrap();
// We can write to the Vmo, and see the results in the mapping.
let s = String::from("Hello world");
vmo.write(s.as_bytes(), 0).unwrap();
let output = unsafe { slice::from_raw_parts(mapping.as_ptr(), s.len()) };
assert_eq!(s.as_bytes(), output);
// We can write to the mapping, and see the results in the Vmo.
let s = String::from("Goodbye world");
unsafe { mapping.as_mut_ptr().copy_from(s.as_ptr(), s.len()) };
let mut output = vec![0; s.len()];
vmo.read(output.as_mut_slice(), 0).unwrap();
assert_eq!(s.as_bytes(), output.as_slice());
}
#[test]
fn test_mapped_vmo() {
let size = PAGE_SIZE;
let flags = VmarFlags::PERM_READ | VmarFlags::PERM_WRITE;
let vmo = zx::Vmo::create(size as u64).unwrap();
let mut mvmo = MappedVmo::create_from_vmo(vmo, size, flags).unwrap();
// We can write to the Vmo, and see the results in the mapping.
let s = String::from("Hello world");
mvmo.vmo().write(s.as_bytes(), 0).unwrap();
let output = unsafe { slice::from_raw_parts(mvmo.as_ptr(), s.len()) };
assert_eq!(s.as_bytes(), output);
// We should still be able to read from the mapping after resizing.
mvmo.resize(size * 2, flags).unwrap();
let output = unsafe { slice::from_raw_parts(mvmo.as_ptr(), s.len()) };
assert_eq!(s.as_bytes(), output);
// We can write to the mapping, and see the results in the Vmo.
let s = String::from("Goodbye world");
unsafe { mvmo.as_mut_ptr().copy_from(s.as_ptr(), s.len()) };
let mut output = vec![0; s.len()];
mvmo.vmo().read(output.as_mut_slice(), 0).unwrap();
assert_eq!(s.as_bytes(), output.as_slice());
// We should still be able to read from the Vmo after resizing.
mvmo.resize(size, flags).unwrap();
mvmo.vmo().read(output.as_mut_slice(), 0).unwrap();
assert_eq!(s.as_bytes(), output.as_slice());
}
}