1use zx_status::Status;
6
7pub trait Storage {
9 const SUPPORTS_GROW: bool = false;
11
12 fn allocate(&mut self, size: usize) -> Result<(), Status>;
14
15 fn get_data(&self) -> &[usize];
17
18 fn get_data_mut(&mut self) -> &mut [usize];
20
21 fn grow(&mut self, _size: usize) -> Result<(), Status> {
23 Err(Status::NO_RESOURCES)
24 }
25}
26
27pub struct DefaultStorage {
28 storage: kalloc::Box<[usize]>,
29}
30
31impl core::fmt::Debug for DefaultStorage {
32 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33 f.debug_struct("DefaultStorage").field("storage", &self.storage.as_ref()).finish()
34 }
35}
36
37impl Default for DefaultStorage {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl DefaultStorage {
44 pub const fn new() -> Self {
46 Self { storage: kalloc::Box::<[usize]>::empty_slice() }
47 }
48}
49
50impl Storage for DefaultStorage {
51 fn allocate(&mut self, size: usize) -> Result<(), Status> {
52 let usize_size = core::mem::size_of::<usize>();
53 let num_elements = (size + usize_size - 1) / usize_size;
54 let new_storage = kalloc::Box::<[usize]>::try_new_zeroed_slice(num_elements)
55 .map_err(|_| Status::NO_MEMORY)?;
56 self.storage = new_storage;
57 Ok(())
58 }
59
60 fn get_data(&self) -> &[usize] {
61 &self.storage
62 }
63
64 fn get_data_mut(&mut self) -> &mut [usize] {
65 &mut self.storage
66 }
67}
68
69#[derive(Debug)]
73pub struct FixedStorage<const N: usize> {
74 storage: [usize; N],
75}
76
77impl<const N: usize> Default for FixedStorage<N> {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl<const N: usize> FixedStorage<N> {
84 pub const fn new() -> Self {
86 Self { storage: [0; N] }
87 }
88}
89
90impl<const N: usize> Storage for FixedStorage<N> {
91 fn allocate(&mut self, size: usize) -> Result<(), Status> {
92 let usize_size = core::mem::size_of::<usize>();
93 let required_elements = (size + usize_size - 1) / usize_size;
94 if required_elements > N {
95 return Err(Status::INVALID_ARGS);
96 }
97 Ok(())
98 }
99
100 fn get_data(&self) -> &[usize] {
101 &self.storage
102 }
103
104 fn get_data_mut(&mut self) -> &mut [usize] {
105 &mut self.storage
106 }
107}
108
109#[cfg(all(not(is_kernel), target_os = "fuchsia"))]
110mod userspace {
111 use super::*;
112 use fuchsia_runtime;
113
114 fn map_vmo(vmar: &zx::Vmar, vmo: &zx::Vmo, size: usize) -> Result<usize, Status> {
116 vmar.map(0, vmo, 0, size, zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE)
117 }
118
119 #[derive(Default, Debug)]
121 pub struct VmoStorage {
122 vmo: Option<zx::Vmo>,
123 mapped_addr: usize,
124 size: usize,
125 }
126
127 impl VmoStorage {
128 pub const fn new() -> Self {
130 Self { vmo: None, mapped_addr: 0, size: 0 }
131 }
132
133 fn release(&mut self) {
134 if self.mapped_addr != 0 {
135 let vmar = fuchsia_runtime::vmar_root_self();
136 unsafe {
138 let _ = vmar.unmap(self.mapped_addr, self.size);
139 }
140 }
141 self.mapped_addr = 0;
142 self.size = 0;
143 self.vmo = None;
144 }
145
146 pub fn get_vmo(&self) -> Option<&zx::Vmo> {
148 self.vmo.as_ref()
149 }
150 }
151
152 impl Drop for VmoStorage {
153 fn drop(&mut self) {
154 self.release();
155 }
156 }
157
158 impl Storage for VmoStorage {
159 const SUPPORTS_GROW: bool = true;
160
161 fn allocate(&mut self, size: usize) -> Result<(), Status> {
162 self.release();
163 let page_size = zx::system_get_page_size() as usize;
164 let rounded_size = (size + page_size - 1) & !(page_size - 1);
165 let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, rounded_size as u64)?;
166 let _ = vmo.set_name(&zx::Name::new_lossy("vmo-backed-bitmap"));
167
168 let vmar = fuchsia_runtime::vmar_root_self();
169 let mapped_addr = map_vmo(&vmar, &vmo, rounded_size)?;
170
171 self.vmo = Some(vmo);
172 self.mapped_addr = mapped_addr;
173 self.size = rounded_size;
174 Ok(())
175 }
176
177 fn get_data(&self) -> &[usize] {
178 if self.mapped_addr == 0 {
179 &[]
180 } else {
181 unsafe {
187 let ptr = core::ptr::with_exposed_provenance::<usize>(self.mapped_addr);
188 core::slice::from_raw_parts(ptr, self.size / core::mem::size_of::<usize>())
189 }
190 }
191 }
192
193 fn get_data_mut(&mut self) -> &mut [usize] {
194 if self.mapped_addr == 0 {
195 &mut []
196 } else {
197 unsafe {
203 let ptr = core::ptr::with_exposed_provenance_mut::<usize>(self.mapped_addr);
204 core::slice::from_raw_parts_mut(ptr, self.size / core::mem::size_of::<usize>())
205 }
206 }
207 }
208
209 fn grow(&mut self, size: usize) -> Result<(), Status> {
210 if size <= self.size {
211 return Ok(());
212 }
213 let page_size = zx::system_get_page_size() as usize;
214 let rounded_size = (size + page_size - 1) & !(page_size - 1);
215 let vmo = self.vmo.as_ref().ok_or(Status::BAD_STATE)?;
216 vmo.set_size(rounded_size as u64)?;
217
218 let vmar = fuchsia_runtime::vmar_root_self();
219 let vmar_info = vmar.info()?;
220 let extend_offset = self.mapped_addr + self.size - vmar_info.base;
221 let extend_size = rounded_size - self.size;
222 let map_result = vmar.map(
223 extend_offset,
224 vmo,
225 self.size as u64,
226 extend_size,
227 zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE | zx::VmarFlags::SPECIFIC,
228 );
229 if map_result.is_ok() {
230 self.size = rounded_size;
231 return Ok(());
232 }
233
234 let new_addr = map_vmo(&vmar, vmo, rounded_size)?;
235 unsafe {
237 let _ = vmar.unmap(self.mapped_addr, self.size);
238 }
239 self.mapped_addr = new_addr;
240 self.size = rounded_size;
241 Ok(())
242 }
243 }
244}
245
246#[cfg(all(not(is_kernel), target_os = "fuchsia"))]
247pub use userspace::VmoStorage;