1use crate::clock::Clock;
8use crate::iob::Iob;
9use crate::{Koid, Name, NullableHandle, ObjectQuery, Status, Timeline, Topic, Vmo, ok, sys};
10use bitflags::bitflags;
11use std::mem::MaybeUninit;
12use zerocopy::{FromBytes, Immutable};
13use zx_sys::PadByte;
14
15#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
20#[repr(transparent)]
21pub struct Vmar(NullableHandle);
22impl_handle_based!(Vmar);
23
24sys::zx_info_vmar_t!(VmarInfo);
25
26impl From<sys::zx_info_vmar_t> for VmarInfo {
27 fn from(sys::zx_info_vmar_t { base, len }: sys::zx_info_vmar_t) -> VmarInfo {
28 VmarInfo { base, len }
29 }
30}
31
32unsafe impl ObjectQuery for VmarInfo {
34 const TOPIC: Topic = Topic::VMAR;
35 type InfoTy = VmarInfo;
36}
37
38struct VmarMapsInfo;
39unsafe impl ObjectQuery for VmarMapsInfo {
40 const TOPIC: Topic = Topic::VMAR_MAPS;
41 type InfoTy = MapInfo;
42}
43
44static_assert_align!(
45 #[repr(C)]
47 #[derive(Copy, Clone, FromBytes, Immutable)]
48 <sys::zx_info_maps_t> pub struct MapInfo {
49 pub name <name>: Name,
50 pub base <base>: usize,
51 pub size <size>: usize,
52 pub depth <depth>: usize,
53 r#type <r#type>: sys::zx_info_maps_type_t,
54 u <u>: sys::InfoMapsTypeUnion,
55 }
56);
57
58impl MapInfo {
59 pub fn new(
60 name: Name,
61 base: usize,
62 size: usize,
63 depth: usize,
64 details: MapDetails<'_>,
65 ) -> Result<MapInfo, Status> {
66 let (map_type, map_details_union) = match details {
67 MapDetails::None => (
68 sys::ZX_INFO_MAPS_TYPE_NONE,
69 sys::InfoMapsTypeUnion { mapping: Default::default() },
70 ),
71 MapDetails::AddressSpace => (
72 sys::ZX_INFO_MAPS_TYPE_ASPACE,
73 sys::InfoMapsTypeUnion { mapping: Default::default() },
74 ),
75 MapDetails::Vmar => (
76 sys::ZX_INFO_MAPS_TYPE_VMAR,
77 sys::InfoMapsTypeUnion { mapping: Default::default() },
78 ),
79 MapDetails::Mapping(mapping_details) => (
80 sys::ZX_INFO_MAPS_TYPE_MAPPING,
81 sys::InfoMapsTypeUnion {
82 mapping: {
83 let mut mapping: sys::zx_info_maps_mapping_t = Default::default();
84 mapping.mmu_flags = mapping_details.mmu_flags.bits();
85 mapping.vmo_koid = mapping_details.vmo_koid.raw_koid();
86 mapping.vmo_offset = mapping_details.vmo_offset;
87 mapping.committed_bytes = mapping_details.committed_bytes;
88 mapping.populated_bytes = mapping_details.populated_bytes;
89 mapping.committed_private_bytes = mapping_details.committed_private_bytes;
90 mapping.populated_private_bytes = mapping_details.populated_private_bytes;
91 mapping.committed_scaled_bytes = mapping_details.committed_scaled_bytes;
92 mapping.populated_scaled_bytes = mapping_details.populated_scaled_bytes;
93 mapping.committed_fractional_scaled_bytes =
94 mapping_details.committed_fractional_scaled_bytes;
95 mapping.populated_fractional_scaled_bytes =
96 mapping_details.populated_fractional_scaled_bytes;
97 mapping
98 },
99 },
100 ),
101 MapDetails::Unknown => {
102 return Err(Status::INVALID_ARGS);
103 }
104 };
105 Ok(MapInfo { name, base, size, depth, r#type: map_type, u: map_details_union })
106 }
107
108 pub fn details<'a>(&'a self) -> MapDetails<'a> {
109 match self.r#type {
110 sys::ZX_INFO_MAPS_TYPE_NONE => MapDetails::None,
111 sys::ZX_INFO_MAPS_TYPE_ASPACE => MapDetails::AddressSpace,
112 sys::ZX_INFO_MAPS_TYPE_VMAR => MapDetails::Vmar,
113 sys::ZX_INFO_MAPS_TYPE_MAPPING => {
114 let raw_mapping = unsafe { &self.u.mapping };
117 let mapping_details = zerocopy::transmute_ref!(raw_mapping);
118 MapDetails::Mapping(mapping_details)
119 }
120 _ => MapDetails::Unknown,
121 }
122 }
123}
124
125impl std::cmp::PartialEq for MapInfo {
126 fn eq(&self, other: &Self) -> bool {
127 self.name == other.name
128 && self.base == other.base
129 && self.size == other.size
130 && self.depth == other.depth
131 && self.details() == other.details()
132 }
133}
134impl std::cmp::Eq for MapInfo {}
135
136impl std::fmt::Debug for MapInfo {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 f.debug_struct("MapInfo")
139 .field("name", &self.name)
140 .field("base", &format_args!("{:#x}", self.base))
141 .field("size", &self.size)
142 .field("depth", &self.depth)
143 .field("details", &self.details())
144 .finish()
145 }
146}
147
148#[derive(Copy, Clone, Debug, Eq, PartialEq)]
149pub enum MapDetails<'a> {
150 Unknown,
152 None,
153 AddressSpace,
154 Vmar,
155 Mapping(&'a MappingDetails),
157}
158
159impl<'a> MapDetails<'a> {
160 pub fn as_mapping(&'a self) -> Option<&'a MappingDetails> {
161 match self {
162 Self::Mapping(d) => Some(*d),
163 _ => None,
164 }
165 }
166}
167
168static_assert_align!(
169 #[repr(C)]
170 #[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, PartialEq)]
171 <sys::zx_info_maps_mapping_t> pub struct MappingDetails {
172 pub mmu_flags <mmu_flags>: VmarFlagsExtended,
173 padding1: [PadByte; 4],
174 pub vmo_koid <vmo_koid>: Koid,
175 pub vmo_offset <vmo_offset>: u64,
176 pub committed_bytes <committed_bytes>: usize,
177 pub populated_bytes <populated_bytes>: usize,
178 pub committed_private_bytes <committed_private_bytes>: usize,
179 pub populated_private_bytes <populated_private_bytes>: usize,
180 pub committed_scaled_bytes <committed_scaled_bytes>: usize,
181 pub populated_scaled_bytes <populated_scaled_bytes>: usize,
182 pub committed_fractional_scaled_bytes <committed_fractional_scaled_bytes>: u64,
183 pub populated_fractional_scaled_bytes <populated_fractional_scaled_bytes>: u64,
184 }
185);
186
187impl Default for MappingDetails {
188 fn default() -> MappingDetails {
189 Self::from(sys::zx_info_maps_mapping_t::default())
190 }
191}
192
193impl From<sys::zx_info_maps_mapping_t> for MappingDetails {
194 fn from(info: sys::zx_info_maps_mapping_t) -> MappingDetails {
195 zerocopy::transmute!(info)
196 }
197}
198
199impl Vmar {
200 pub fn allocate(
201 &self,
202 offset: usize,
203 size: usize,
204 flags: VmarFlags,
205 ) -> Result<(Vmar, usize), Status> {
206 let mut mapped = 0;
207 let mut handle = 0;
208 let status = unsafe {
209 sys::zx_vmar_allocate(
210 self.raw_handle(),
211 flags.bits(),
212 offset,
213 size,
214 &mut handle,
215 &mut mapped,
216 )
217 };
218 ok(status)?;
219 unsafe { Ok((Vmar::from(NullableHandle::from_raw(handle)), mapped)) }
220 }
221
222 pub fn map(
223 &self,
224 vmar_offset: usize,
225 vmo: &Vmo,
226 vmo_offset: u64,
227 len: usize,
228 flags: VmarFlags,
229 ) -> Result<usize, Status> {
230 let flags = VmarFlagsExtended::from_bits_truncate(flags.bits());
231 unsafe { self.map_unsafe(vmar_offset, vmo, vmo_offset, len, flags) }
232 }
233
234 pub unsafe fn map_unsafe(
241 &self,
242 vmar_offset: usize,
243 vmo: &Vmo,
244 vmo_offset: u64,
245 len: usize,
246 flags: VmarFlagsExtended,
247 ) -> Result<usize, Status> {
248 let mut mapped = 0;
249 let status = unsafe {
250 sys::zx_vmar_map(
251 self.0.raw_handle(),
252 flags.bits(),
253 vmar_offset,
254 vmo.raw_handle(),
255 vmo_offset,
256 len,
257 &mut mapped,
258 )
259 };
260 ok(status).map(|_| mapped)
261 }
262
263 pub unsafe fn unmap(&self, addr: usize, len: usize) -> Result<(), Status> {
280 ok(unsafe { sys::zx_vmar_unmap(self.0.raw_handle(), addr, len) })
283 }
284
285 pub fn op_range(&self, op: VmarOp, addr: usize, len: usize) -> Result<(), Status> {
291 ok(unsafe {
292 sys::zx_vmar_op_range(
293 self.0.raw_handle(),
294 op.into_raw(),
295 addr,
296 len,
297 std::ptr::null_mut(),
298 0,
299 )
300 })
301 }
302
303 pub unsafe fn protect(&self, addr: usize, len: usize, flags: VmarFlags) -> Result<(), Status> {
316 ok(unsafe { sys::zx_vmar_protect(self.raw_handle(), flags.bits(), addr, len) })
319 }
320
321 pub unsafe fn destroy(&self) -> Result<(), Status> {
329 ok(unsafe { sys::zx_vmar_destroy(self.raw_handle()) })
332 }
333
334 pub fn info(&self) -> Result<VmarInfo, Status> {
338 Ok(self.0.get_info_single::<VmarInfo>()?)
339 }
340
341 pub fn maps<'a>(
348 &self,
349 buf: &'a mut [MaybeUninit<MapInfo>],
350 ) -> Result<(&'a mut [MapInfo], &'a mut [MaybeUninit<MapInfo>], usize), Status> {
351 self.0.get_info::<VmarMapsInfo>(buf)
352 }
353
354 pub fn maps_vec(&self) -> Result<Vec<MapInfo>, Status> {
358 self.0.get_info_vec::<VmarMapsInfo>()
359 }
360
361 pub fn map_iob(
364 &self,
365 options: VmarFlags,
366 vmar_offset: usize,
367 iob: &Iob,
368 region_index: u32,
369 region_offset: u64,
370 region_len: usize,
371 ) -> Result<usize, Status> {
372 let mut addr = 0;
373 let status = unsafe {
374 sys::zx_vmar_map_iob(
375 self.raw_handle(),
376 options.bits(),
377 vmar_offset,
378 iob.raw_handle(),
379 region_index,
380 region_offset,
381 region_len,
382 &mut addr,
383 )
384 };
385 ok(status)?;
386 Ok(addr)
387 }
388
389 pub fn map_clock<I: Timeline, O: Timeline>(
392 &self,
393 options: VmarFlags,
394 vmar_offset: usize,
395 clock: &Clock<I, O>,
396 length: usize,
397 ) -> Result<usize, Status> {
398 let mut addr = 0;
399 let status = unsafe {
400 sys::zx_vmar_map_clock(
401 self.raw_handle(),
402 options.bits(),
403 vmar_offset,
404 clock.raw_handle(),
405 length,
406 &mut addr,
407 )
408 };
409 ok(status)?;
410 Ok(addr)
411 }
412}
413
414#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
416#[repr(transparent)]
417pub struct VmarOp(u32);
418impl VmarOp {
419 pub fn from_raw(raw: u32) -> Self {
420 Self(raw)
421 }
422 pub fn into_raw(self) -> u32 {
423 self.0
424 }
425}
426
427assoc_values!(VmarOp, [
428 COMMIT = sys::ZX_VMAR_OP_COMMIT;
429 DECOMMIT = sys::ZX_VMAR_OP_DECOMMIT;
430 PREFETCH = sys::ZX_VMAR_OP_PREFETCH;
431 MAP_RANGE = sys::ZX_VMAR_OP_MAP_RANGE;
432 ZERO = sys::ZX_VMAR_OP_ZERO;
433 DONT_NEED = sys::ZX_VMAR_OP_DONT_NEED;
434 ALWAYS_NEED = sys::ZX_VMAR_OP_ALWAYS_NEED;
435]);
436
437macro_rules! vmar_flags {
440 (
441 safe: [$($safe_name:ident : $safe_sys_name:ident,)*],
442 extended: [$($ex_name:ident : $ex_sys_name:ident,)*],
443 ) => {
444 #[repr(transparent)]
446 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, FromBytes, Immutable)]
447 pub struct VmarFlags(sys::zx_vm_option_t);
448
449 bitflags! {
450 impl VmarFlags: sys::zx_vm_option_t {
451 $(
452 const $safe_name = sys::$safe_sys_name;
453 )*
454 }
455 }
456
457 impl std::fmt::Debug for VmarFlags {
458 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
459 bitflags::parser::to_writer(self, f)
460 }
461 }
462
463 #[repr(transparent)]
465 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, FromBytes, Immutable, Default)]
466 pub struct VmarFlagsExtended(sys::zx_vm_option_t);
467
468 bitflags! {
469 impl VmarFlagsExtended: sys::zx_vm_option_t {
470 $(
471 const $safe_name = sys::$safe_sys_name;
472 )*
473 $(
474 const $ex_name = sys::$ex_sys_name;
475 )*
476 }
477 }
478
479 impl std::fmt::Debug for VmarFlagsExtended {
480 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
481 bitflags::parser::to_writer(self, f)
482 }
483 }
484 };
485}
486
487vmar_flags! {
488 safe: [
489 PERM_READ: ZX_VM_PERM_READ,
490 PERM_WRITE: ZX_VM_PERM_WRITE,
491 PERM_EXECUTE: ZX_VM_PERM_EXECUTE,
492 COMPACT: ZX_VM_COMPACT,
493 SPECIFIC: ZX_VM_SPECIFIC,
494 CAN_MAP_SPECIFIC: ZX_VM_CAN_MAP_SPECIFIC,
495 CAN_MAP_READ: ZX_VM_CAN_MAP_READ,
496 CAN_MAP_WRITE: ZX_VM_CAN_MAP_WRITE,
497 CAN_MAP_EXECUTE: ZX_VM_CAN_MAP_EXECUTE,
498 MAP_RANGE: ZX_VM_MAP_RANGE,
499 REQUIRE_NON_RESIZABLE: ZX_VM_REQUIRE_NON_RESIZABLE,
500 ALLOW_FAULTS: ZX_VM_ALLOW_FAULTS,
501 OFFSET_IS_UPPER_LIMIT: ZX_VM_OFFSET_IS_UPPER_LIMIT,
502 PERM_READ_IF_XOM_UNSUPPORTED: ZX_VM_PERM_READ_IF_XOM_UNSUPPORTED,
503 FAULT_BEYOND_STREAM_SIZE: ZX_VM_FAULT_BEYOND_STREAM_SIZE,
504
505
506 ALIGN_1KB: ZX_VM_ALIGN_1KB,
508 ALIGN_2KB: ZX_VM_ALIGN_2KB,
509 ALIGN_4KB: ZX_VM_ALIGN_4KB,
510 ALIGN_8KB: ZX_VM_ALIGN_8KB,
511 ALIGN_16KB: ZX_VM_ALIGN_16KB,
512 ALIGN_32KB: ZX_VM_ALIGN_32KB,
513 ALIGN_64KB: ZX_VM_ALIGN_64KB,
514 ALIGN_128KB: ZX_VM_ALIGN_128KB,
515 ALIGN_256KB: ZX_VM_ALIGN_256KB,
516 ALIGN_512KB: ZX_VM_ALIGN_512KB,
517 ALIGN_1MB: ZX_VM_ALIGN_1MB,
518 ALIGN_2MB: ZX_VM_ALIGN_2MB,
519 ALIGN_4MB: ZX_VM_ALIGN_4MB,
520 ALIGN_8MB: ZX_VM_ALIGN_8MB,
521 ALIGN_16MB: ZX_VM_ALIGN_16MB,
522 ALIGN_32MB: ZX_VM_ALIGN_32MB,
523 ALIGN_64MB: ZX_VM_ALIGN_64MB,
524 ALIGN_128MB: ZX_VM_ALIGN_128MB,
525 ALIGN_256MB: ZX_VM_ALIGN_256MB,
526 ALIGN_512MB: ZX_VM_ALIGN_512MB,
527 ALIGN_1GB: ZX_VM_ALIGN_1GB,
528 ALIGN_2GB: ZX_VM_ALIGN_2GB,
529 ALIGN_4GB: ZX_VM_ALIGN_4GB,
530 ],
531 extended: [
532 SPECIFIC_OVERWRITE: ZX_VM_SPECIFIC_OVERWRITE,
533 ],
534}
535
536#[cfg(test)]
537mod tests {
538 use zx::{Status, VmarFlags};
541
542 #[test]
543 fn allocate_and_info() -> Result<(), Status> {
544 let size = usize::pow(2, 20); let root_vmar = fuchsia_runtime::vmar_root_self();
546 let (vmar, base) = root_vmar.allocate(0, size, VmarFlags::empty())?;
547
548 let info = vmar.info()?;
549 assert!(info.base == base);
550 assert!(info.len == size);
551 Ok(())
552 }
553
554 #[test]
555 fn root_vmar_info() -> Result<(), Status> {
556 let root_vmar = fuchsia_runtime::vmar_root_self();
557 let info = root_vmar.info()?;
558 assert!(info.base > 0);
559 assert!(info.len > 0);
560 Ok(())
561 }
562
563 #[test]
564 fn root_vmar_maps() {
565 let root_vmar = fuchsia_runtime::vmar_root_self();
566 let info = root_vmar.maps_vec().unwrap();
567 assert!(!info.is_empty());
568 }
569}