1use crate::clock::Clock;
8use crate::iob::Iob;
9use crate::{
10 object_get_info, object_get_info_single, object_get_info_vec, ok, sys, AsHandleRef, Handle,
11 HandleBased, HandleRef, Koid, Name, ObjectQuery, Status, Topic, Vmo,
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 = sys::zx_vmar_map(
253 self.0.raw_handle(),
254 flags.bits(),
255 vmar_offset,
256 vmo.raw_handle(),
257 vmo_offset,
258 len,
259 &mut mapped,
260 );
261 ok(status).map(|_| mapped)
262 }
263
264 pub unsafe fn unmap(&self, addr: usize, len: usize) -> Result<(), Status> {
281 ok(unsafe { sys::zx_vmar_unmap(self.0.raw_handle(), addr, len) })
284 }
285
286 pub fn op_range(&self, op: VmarOp, addr: usize, len: usize) -> Result<(), Status> {
292 ok(unsafe {
293 sys::zx_vmar_op_range(
294 self.0.raw_handle(),
295 op.into_raw(),
296 addr,
297 len,
298 std::ptr::null_mut(),
299 0,
300 )
301 })
302 }
303
304 pub unsafe fn protect(&self, addr: usize, len: usize, flags: VmarFlags) -> Result<(), Status> {
317 ok(unsafe { sys::zx_vmar_protect(self.raw_handle(), flags.bits(), addr, len) })
320 }
321
322 pub unsafe fn destroy(&self) -> Result<(), Status> {
330 ok(unsafe { sys::zx_vmar_destroy(self.raw_handle()) })
333 }
334
335 pub fn info(&self) -> Result<VmarInfo, Status> {
339 Ok(object_get_info_single::<VmarInfo>(self.as_handle_ref())?)
340 }
341
342 pub fn info_maps<'a>(
349 &self,
350 buf: &'a mut [MaybeUninit<MapInfo>],
351 ) -> Result<(&'a mut [MapInfo], &'a mut [MaybeUninit<MapInfo>], usize), Status> {
352 object_get_info::<VmarMapsInfo>(self.as_handle_ref(), buf)
353 }
354
355 pub fn info_maps_vec(&self) -> Result<Vec<MapInfo>, Status> {
359 object_get_info_vec::<VmarMapsInfo>(self.as_handle_ref())
360 }
361
362 pub fn map_iob(
365 &self,
366 options: VmarFlags,
367 vmar_offset: usize,
368 iob: &Iob,
369 region_index: u32,
370 region_offset: u64,
371 region_len: usize,
372 ) -> Result<usize, Status> {
373 let mut addr = 0;
374 let status = unsafe {
375 sys::zx_vmar_map_iob(
376 self.raw_handle(),
377 options.bits(),
378 vmar_offset,
379 iob.raw_handle(),
380 region_index,
381 region_offset,
382 region_len,
383 &mut addr,
384 )
385 };
386 ok(status)?;
387 Ok(addr)
388 }
389
390 pub fn map_clock(
393 &self,
394 options: VmarFlags,
395 vmar_offset: usize,
396 clock: &Clock,
397 length: usize,
398 ) -> Result<usize, Status> {
399 let mut addr = 0;
400 let status = unsafe {
401 sys::zx_vmar_map_clock(
402 self.raw_handle(),
403 options.bits(),
404 vmar_offset,
405 clock.raw_handle(),
406 length,
407 &mut addr,
408 )
409 };
410 ok(status)?;
411 Ok(addr)
412 }
413}
414
415#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
417#[repr(transparent)]
418pub struct VmarOp(u32);
419impl VmarOp {
420 pub fn from_raw(raw: u32) -> Self {
421 Self(raw)
422 }
423 pub fn into_raw(self) -> u32 {
424 self.0
425 }
426}
427
428assoc_values!(VmarOp, [
429 COMMIT = sys::ZX_VMAR_OP_COMMIT;
430 DECOMMIT = sys::ZX_VMAR_OP_DECOMMIT;
431 PREFETCH = sys::ZX_VMAR_OP_PREFETCH;
432 MAP_RANGE = sys::ZX_VMAR_OP_MAP_RANGE;
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
504 ALIGN_1KB: ZX_VM_ALIGN_1KB,
506 ALIGN_2KB: ZX_VM_ALIGN_2KB,
507 ALIGN_4KB: ZX_VM_ALIGN_4KB,
508 ALIGN_8KB: ZX_VM_ALIGN_8KB,
509 ALIGN_16KB: ZX_VM_ALIGN_16KB,
510 ALIGN_32KB: ZX_VM_ALIGN_32KB,
511 ALIGN_64KB: ZX_VM_ALIGN_64KB,
512 ALIGN_128KB: ZX_VM_ALIGN_128KB,
513 ALIGN_256KB: ZX_VM_ALIGN_256KB,
514 ALIGN_512KB: ZX_VM_ALIGN_512KB,
515 ALIGN_1MB: ZX_VM_ALIGN_1MB,
516 ALIGN_2MB: ZX_VM_ALIGN_2MB,
517 ALIGN_4MB: ZX_VM_ALIGN_4MB,
518 ALIGN_8MB: ZX_VM_ALIGN_8MB,
519 ALIGN_16MB: ZX_VM_ALIGN_16MB,
520 ALIGN_32MB: ZX_VM_ALIGN_32MB,
521 ALIGN_64MB: ZX_VM_ALIGN_64MB,
522 ALIGN_128MB: ZX_VM_ALIGN_128MB,
523 ALIGN_256MB: ZX_VM_ALIGN_256MB,
524 ALIGN_512MB: ZX_VM_ALIGN_512MB,
525 ALIGN_1GB: ZX_VM_ALIGN_1GB,
526 ALIGN_2GB: ZX_VM_ALIGN_2GB,
527 ALIGN_4GB: ZX_VM_ALIGN_4GB,
528 ],
529 extended: [
530 SPECIFIC_OVERWRITE: ZX_VM_SPECIFIC_OVERWRITE,
531 ],
532}
533
534#[cfg(test)]
535mod tests {
536 use zx::{Status, VmarFlags};
539
540 #[test]
541 fn allocate_and_info() -> Result<(), Status> {
542 let size = usize::pow(2, 20); let root_vmar = fuchsia_runtime::vmar_root_self();
544 let (vmar, base) = root_vmar.allocate(0, size, VmarFlags::empty())?;
545
546 let info = vmar.info()?;
547 assert!(info.base == base);
548 assert!(info.len == size);
549 Ok(())
550 }
551
552 #[test]
553 fn root_vmar_info() -> Result<(), Status> {
554 let root_vmar = fuchsia_runtime::vmar_root_self();
555 let info = root_vmar.info()?;
556 assert!(info.base > 0);
557 assert!(info.len > 0);
558 Ok(())
559 }
560
561 #[test]
562 fn root_vmar_maps() {
563 let root_vmar = fuchsia_runtime::vmar_root_self();
564 let info = root_vmar.info_maps_vec().unwrap();
565 assert!(!info.is_empty());
566 }
567}