1#![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#[derive(Debug)]
26pub struct Mapping {
27 buffer: SharedBuffer,
28 vmar: zx::Vmar,
29}
30
31impl Deref for Mapping {
32 type Target = SharedBuffer;
33 fn deref(&self) -> &Self::Target {
34 &self.buffer
35 }
36}
37
38impl DerefMut for Mapping {
39 fn deref_mut(&mut self) -> &mut Self::Target {
40 &mut self.buffer
41 }
42}
43
44impl Mapping {
45 pub fn allocate(size: usize) -> Result<(Self, zx::Vmo), zx::Status> {
50 let vmo = zx::Vmo::create(size as u64)?;
51 let flags = zx::VmarFlags::PERM_READ
52 | zx::VmarFlags::PERM_WRITE
53 | zx::VmarFlags::MAP_RANGE
54 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
55 let mapping = Self::create_from_vmo(&vmo, size, flags)?;
56 Ok((mapping, vmo))
57 }
58
59 pub fn allocate_with_name(size: usize, name: &str) -> Result<(Self, zx::Vmo), zx::Status> {
64 let name = zx::Name::new(name)?;
65 let vmo = zx::Vmo::create(size as u64)?;
66 vmo.set_name(&name)?;
67 let flags = zx::VmarFlags::PERM_READ
68 | zx::VmarFlags::PERM_WRITE
69 | zx::VmarFlags::MAP_RANGE
70 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
71 let mapping = Self::create_from_vmo(&vmo, size, flags)?;
72 Ok((mapping, vmo))
73 }
74
75 pub fn create_from_vmo(
80 vmo: &zx::Vmo,
81 size: usize,
82 flags: zx::VmarFlags,
83 ) -> Result<Self, zx::Status> {
84 Self::create_from_vmo_with_vmar_and_offset(vmo, &vmar_root_self(), 0, size, flags)
85 }
86
87 pub fn create_from_vmo_with_offset(
92 vmo: &zx::Vmo,
93 vmo_offset: u64,
94 size: usize,
95 flags: zx::VmarFlags,
96 ) -> Result<Self, zx::Status> {
97 Self::create_from_vmo_with_vmar_and_offset(vmo, &vmar_root_self(), vmo_offset, size, flags)
98 }
99
100 pub fn create_from_vmo_with_vmar(
105 vmo: &zx::Vmo,
106 vmar: &zx::Vmar,
107 size: usize,
108 flags: zx::VmarFlags,
109 ) -> Result<Self, zx::Status> {
110 Self::create_from_vmo_with_vmar_and_offset(vmo, vmar, 0, size, flags)
111 }
112
113 pub fn create_from_vmo_with_vmar_and_offset(
118 vmo: &zx::Vmo,
119 vmar: &zx::Vmar,
120 vmo_offset: u64,
121 size: usize,
122 flags: zx::VmarFlags,
123 ) -> Result<Self, zx::Status> {
124 let vmar = vmar.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
125 let flags = flags | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
126 let addr = vmar.map(0, vmo, vmo_offset, size, flags)?;
127
128 let buffer = unsafe { SharedBuffer::new(addr as *mut u8, size) };
139 Ok(Mapping { buffer, vmar })
140 }
141
142 pub fn len(&self) -> usize {
144 self.buffer.len()
145 }
146}
147
148impl Drop for Mapping {
149 fn drop(&mut self) {
150 let (addr, size): (*mut u8, usize) = self.buffer.as_ptr_len();
151 let addr = addr as usize;
152
153 unsafe {
160 let _ = self.vmar.unmap(addr, size);
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 const PAGE_SIZE: usize = 4096;
170
171 #[test]
172 fn test_create() {
173 let size = PAGE_SIZE;
174 let (mapping, _vmo) = Mapping::allocate(size).unwrap();
175 assert_eq!(size, mapping.len());
176 }
177
178 #[test]
179 fn test_create_from_vmo() {
180 let size = PAGE_SIZE;
181 let flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
182 {
183 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size as u64).unwrap();
185 let status = Mapping::create_from_vmo(&vmo, size, flags).unwrap_err();
186 assert_eq!(status, zx::Status::NOT_SUPPORTED);
187 }
188 {
189 let vmo = zx::Vmo::create(size as u64).unwrap();
190 let mapping = Mapping::create_from_vmo(&vmo, size, flags).unwrap();
191 assert_eq!(size, mapping.len());
192 }
193 }
194
195 #[test]
196 fn test_create_from_vmo_with_vmar() {
197 let size = PAGE_SIZE;
198 let flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
199 let (child_vmar, _base) = vmar_root_self()
200 .allocate(
201 0,
202 size,
203 zx::VmarFlags::CAN_MAP_READ
204 | zx::VmarFlags::CAN_MAP_WRITE
205 | zx::VmarFlags::CAN_MAP_SPECIFIC,
206 )
207 .unwrap();
208 let vmo = zx::Vmo::create(size as u64).unwrap();
209 let mapping = Mapping::create_from_vmo_with_vmar(&vmo, &child_vmar, size, flags).unwrap();
210 assert_eq!(size, mapping.len());
211
212 let s = b"Hello custom VMAR";
213 mapping.write(s);
214 let mut buf = [0u8; 17];
215 vmo.read(&mut buf, 0).unwrap();
216 assert_eq!(s, &buf);
217 }
218
219 #[test]
220 fn test_create_from_vmo_with_offset() {
221 let flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
222 let vmo = zx::Vmo::create((PAGE_SIZE * 2) as u64).unwrap();
223 let s = b"Hello non-zero VMO offset";
224 vmo.write(s, PAGE_SIZE as u64).unwrap();
225
226 let mapping =
227 Mapping::create_from_vmo_with_offset(&vmo, PAGE_SIZE as u64, PAGE_SIZE, flags).unwrap();
228 assert_eq!(PAGE_SIZE, mapping.len());
229
230 let mut buf = [0u8; 25];
231 mapping.read(&mut buf);
232 assert_eq!(s, &buf);
233
234 let unaligned_err =
235 Mapping::create_from_vmo_with_offset(&vmo, 1, PAGE_SIZE, flags).unwrap_err();
236 assert_eq!(zx::Status::INVALID_ARGS, unaligned_err);
237 }
238
239 #[test]
240 fn test_create_with_name() {
241 let size = PAGE_SIZE;
242 let (mapping, vmo) = Mapping::allocate_with_name(size, "TestName").unwrap();
243 assert_eq!(size, mapping.len());
244 assert_eq!("TestName", vmo.get_name().expect("Has name"));
245 let res = Mapping::allocate_with_name(size, "Invalid\0TestName");
246 assert_eq!(zx::Status::INVALID_ARGS, res.unwrap_err());
247 }
248
249 #[test]
250 fn test_mapping_read_write() {
251 let size = PAGE_SIZE;
252 let (mapping, vmo) = Mapping::allocate(size).unwrap();
253
254 let mut buf = [0; 128];
255
256 let s = b"Hello world";
258 vmo.write(s, 0).unwrap();
259 let slice = &mut buf[0..s.len()];
260 mapping.read(slice);
261 assert_eq!(s, slice);
262
263 let s = b"Goodbye world";
265 mapping.write(s);
266 let slice = &mut buf[0..s.len()];
267 vmo.read(slice, 0).unwrap();
268 assert_eq!(s, slice);
269 }
270}