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