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}
29
30impl Deref for Mapping {
31 type Target = SharedBuffer;
32 fn deref(&self) -> &Self::Target {
33 &self.buffer
34 }
35}
36
37impl DerefMut for Mapping {
38 fn deref_mut(&mut self) -> &mut Self::Target {
39 &mut self.buffer
40 }
41}
42
43impl Mapping {
44 pub fn allocate(size: usize) -> Result<(Self, zx::Vmo), zx::Status> {
49 let vmo = zx::Vmo::create(size as u64)?;
50 let flags = zx::VmarFlags::PERM_READ
51 | zx::VmarFlags::PERM_WRITE
52 | zx::VmarFlags::MAP_RANGE
53 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
54 let mapping = Self::create_from_vmo(&vmo, size, flags)?;
55 Ok((mapping, vmo))
56 }
57
58 pub fn allocate_with_name(size: usize, name: &str) -> Result<(Self, zx::Vmo), zx::Status> {
63 let name = zx::Name::new(name)?;
64 let vmo = zx::Vmo::create(size as u64)?;
65 vmo.set_name(&name)?;
66 let flags = zx::VmarFlags::PERM_READ
67 | zx::VmarFlags::PERM_WRITE
68 | zx::VmarFlags::MAP_RANGE
69 | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
70 let mapping = Self::create_from_vmo(&vmo, size, flags)?;
71 Ok((mapping, vmo))
72 }
73
74 pub fn create_from_vmo(
79 vmo: &zx::Vmo,
80 size: usize,
81 flags: zx::VmarFlags,
82 ) -> Result<Self, zx::Status> {
83 let flags = flags | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
84 let addr = vmar_root_self().map(0, &vmo, 0, size, flags)?;
85
86 let buffer = unsafe { SharedBuffer::new(addr as *mut u8, size) };
97 Ok(Mapping { buffer })
98 }
99
100 pub fn len(&self) -> usize {
102 self.buffer.len()
103 }
104}
105
106impl Drop for Mapping {
107 fn drop(&mut self) {
108 let (addr, size): (*mut u8, usize) = self.buffer.as_ptr_len();
109 let addr = addr as usize;
110
111 unsafe {
118 let _ = vmar_root_self().unmap(addr, size);
119 }
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 const PAGE_SIZE: usize = 4096;
128
129 #[test]
130 fn test_create() {
131 let size = PAGE_SIZE;
132 let (mapping, _vmo) = Mapping::allocate(size).unwrap();
133 assert_eq!(size, mapping.len());
134 }
135
136 #[test]
137 fn test_create_from_vmo() {
138 let size = PAGE_SIZE;
139 let flags = zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE;
140 {
141 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size as u64).unwrap();
143 let status = Mapping::create_from_vmo(&vmo, size, flags).unwrap_err();
144 assert_eq!(status, zx::Status::NOT_SUPPORTED);
145 }
146 {
147 let vmo = zx::Vmo::create(size as u64).unwrap();
148 let mapping = Mapping::create_from_vmo(&vmo, size, flags).unwrap();
149 assert_eq!(size, mapping.len());
150 }
151 }
152
153 #[test]
154 fn test_create_with_name() {
155 let size = PAGE_SIZE;
156 let (mapping, vmo) = Mapping::allocate_with_name(size, "TestName").unwrap();
157 assert_eq!(size, mapping.len());
158 assert_eq!("TestName", vmo.get_name().expect("Has name"));
159 let res = Mapping::allocate_with_name(size, "Invalid\0TestName");
160 assert_eq!(zx::Status::INVALID_ARGS, res.unwrap_err());
161 }
162
163 #[test]
164 fn test_mapping_read_write() {
165 let size = PAGE_SIZE;
166 let (mapping, vmo) = Mapping::allocate(size).unwrap();
167
168 let mut buf = [0; 128];
169
170 let s = b"Hello world";
172 vmo.write(s, 0).unwrap();
173 let slice = &mut buf[0..s.len()];
174 mapping.read(slice);
175 assert_eq!(s, slice);
176
177 let s = b"Goodbye world";
179 mapping.write(s);
180 let slice = &mut buf[0..s.len()];
181 vmo.read(slice, 0).unwrap();
182 assert_eq!(s, slice);
183 }
184}