1#![deny(missing_docs)]
8
9use fuchsia_runtime::vmar_root_self;
10use shared_buffer::SharedBuffer;
11use std::ops::{Deref, DerefMut};
12use zx::{self as zx, AsHandleRef};
13
14mod immutable;
15pub use immutable::{Error as ImmutableMappingError, ImmutableMapping};
16
17#[derive(Debug)]
24pub struct Mapping {
25 buffer: SharedBuffer,
26}
27
28impl Deref for Mapping {
29 type Target = SharedBuffer;
30 fn deref(&self) -> &Self::Target {
31 &self.buffer
32 }
33}
34
35impl DerefMut for Mapping {
36 fn deref_mut(&mut self) -> &mut Self::Target {
37 &mut self.buffer
38 }
39}
40
41impl Mapping {
42 pub fn allocate(size: usize) -> Result<(Self, zx::Vmo), zx::Status> {
47 let vmo = zx::Vmo::create(size as u64)?;
48 let flags = zx::VmarFlags::PERM_READ
49 | zx::VmarFlags::PERM_WRITE
50 | zx::VmarFlags::MAP_RANGE
51 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
52 let mapping = Self::create_from_vmo(&vmo, size, flags)?;
53 Ok((mapping, vmo))
54 }
55
56 pub fn allocate_with_name(size: usize, name: &str) -> Result<(Self, zx::Vmo), zx::Status> {
61 let name = zx::Name::new(name)?;
62 let vmo = zx::Vmo::create(size as u64)?;
63 vmo.set_name(&name)?;
64 let flags = zx::VmarFlags::PERM_READ
65 | zx::VmarFlags::PERM_WRITE
66 | zx::VmarFlags::MAP_RANGE
67 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
68 let mapping = Self::create_from_vmo(&vmo, size, flags)?;
69 Ok((mapping, vmo))
70 }
71
72 pub fn create_from_vmo(
77 vmo: &zx::Vmo,
78 size: usize,
79 flags: zx::VmarFlags,
80 ) -> Result<Self, zx::Status> {
81 let flags = flags | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
82 let addr = vmar_root_self().map(0, &vmo, 0, size, flags)?;
83
84 let buffer = unsafe { SharedBuffer::new(addr as *mut u8, size) };
95 Ok(Mapping { buffer })
96 }
97
98 pub fn len(&self) -> usize {
100 self.buffer.len()
101 }
102}
103
104impl Drop for Mapping {
105 fn drop(&mut self) {
106 let (addr, size): (*mut u8, usize) = self.buffer.as_ptr_len();
107 let addr = addr as usize;
108
109 unsafe {
116 let _ = vmar_root_self().unmap(addr, size);
117 }
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 const PAGE_SIZE: usize = 4096;
126
127 #[test]
128 fn test_create() {
129 let size = PAGE_SIZE;
130 let (mapping, _vmo) = Mapping::allocate(size).unwrap();
131 assert_eq!(size, mapping.len());
132 }
133
134 #[test]
135 fn test_create_from_vmo() {
136 let size = PAGE_SIZE;
137 let flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
138 {
139 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size as u64).unwrap();
141 let status = Mapping::create_from_vmo(&vmo, size, flags).unwrap_err();
142 assert_eq!(status, zx::Status::NOT_SUPPORTED);
143 }
144 {
145 let vmo = zx::Vmo::create(size as u64).unwrap();
146 let mapping = Mapping::create_from_vmo(&vmo, size, flags).unwrap();
147 assert_eq!(size, mapping.len());
148 }
149 }
150
151 #[test]
152 fn test_create_with_name() {
153 let size = PAGE_SIZE;
154 let (mapping, vmo) = Mapping::allocate_with_name(size, "TestName").unwrap();
155 assert_eq!(size, mapping.len());
156 assert_eq!("TestName", vmo.get_name().expect("Has name"));
157 let res = Mapping::allocate_with_name(size, "Invalid\0TestName");
158 assert_eq!(zx::Status::INVALID_ARGS, res.unwrap_err());
159 }
160
161 #[test]
162 fn test_mapping_read_write() {
163 let size = PAGE_SIZE;
164 let (mapping, vmo) = Mapping::allocate(size).unwrap();
165
166 let mut buf = [0; 128];
167
168 let s = b"Hello world";
170 vmo.write(s, 0).unwrap();
171 let slice = &mut buf[0..s.len()];
172 mapping.read(slice);
173 assert_eq!(s, slice);
174
175 let s = b"Goodbye world";
177 mapping.write(s);
178 let slice = &mut buf[0..s.len()];
179 vmo.read(slice, 0).unwrap();
180 assert_eq!(s, slice);
181 }
182}