1use crate::{
8 object_get_info_single, object_get_property, object_set_property, ok, sys, AsHandleRef, Bti,
9 Handle, HandleBased, HandleRef, Koid, Name, ObjectQuery, Property, PropertyQuery, Resource,
10 Rights, Status, Topic,
11};
12use bitflags::bitflags;
13use std::mem::MaybeUninit;
14use std::ptr;
15use zerocopy::{FromBytes, Immutable};
16use zx_sys::PadByte;
17
18#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
23#[repr(transparent)]
24pub struct Vmo(Handle);
25impl_handle_based!(Vmo);
26
27static_assert_align!(
28 #[doc="Ergonomic equivalent of [sys::zx_info_vmo_t]. Must be ABI-compatible with it."]
29 #[repr(C)]
30 #[derive(Debug, Copy, Clone, Eq, PartialEq, FromBytes, Immutable)]
31 <sys::zx_info_vmo_t> pub struct VmoInfo {
32 pub koid <koid>: Koid,
33 pub name <name>: Name,
34 pub size_bytes <size_bytes>: u64,
35 pub parent_koid <parent_koid>: Koid,
36 pub num_children <num_children>: usize,
37 pub num_mappings <num_mappings>: usize,
38 pub share_count <share_count>: usize,
39 pub flags <flags>: VmoInfoFlags,
40 padding1: [PadByte; 4],
41 pub committed_bytes <committed_bytes>: u64,
42 pub handle_rights <handle_rights>: Rights,
43 cache_policy <cache_policy>: u32,
44 pub metadata_bytes <metadata_bytes>: u64,
45 pub committed_change_events <committed_change_events>: u64,
46 pub populated_bytes <populated_bytes>: u64,
47 pub committed_private_bytes <committed_private_bytes>: u64,
48 pub populated_private_bytes <populated_private_bytes>: u64,
49 pub committed_scaled_bytes <committed_scaled_bytes>: u64,
50 pub populated_scaled_bytes <populated_scaled_bytes>: u64,
51 pub committed_fractional_scaled_bytes <committed_fractional_scaled_bytes>: u64,
52 pub populated_fractional_scaled_bytes <populated_fractional_scaled_bytes>: u64,
53 }
54);
55
56impl VmoInfo {
57 pub fn cache_policy(&self) -> CachePolicy {
58 CachePolicy::from(self.cache_policy)
59 }
60}
61
62impl Default for VmoInfo {
63 fn default() -> VmoInfo {
64 Self::from(sys::zx_info_vmo_t::default())
65 }
66}
67
68impl From<sys::zx_info_vmo_t> for VmoInfo {
69 fn from(info: sys::zx_info_vmo_t) -> VmoInfo {
70 zerocopy::transmute!(info)
71 }
72}
73
74struct VmoInfoQuery;
75unsafe impl ObjectQuery for VmoInfoQuery {
76 const TOPIC: Topic = Topic::VMO;
77 type InfoTy = sys::zx_info_vmo_t;
78}
79
80impl Vmo {
81 pub fn create(size: u64) -> Result<Vmo, Status> {
89 Vmo::create_with_opts(VmoOptions::from_bits_truncate(0), size)
90 }
91
92 pub fn create_with_opts(opts: VmoOptions, size: u64) -> Result<Vmo, Status> {
98 let mut handle = 0;
99 let status = unsafe { sys::zx_vmo_create(size, opts.bits(), &mut handle) };
100 ok(status)?;
101 unsafe { Ok(Vmo::from(Handle::from_raw(handle))) }
102 }
103
104 pub fn create_contiguous(bti: &Bti, size: usize, alignment_log2: u32) -> Result<Vmo, Status> {
109 let mut vmo_handle = sys::zx_handle_t::default();
110 let status = unsafe {
111 sys::zx_vmo_create_contiguous(bti.raw_handle(), size, alignment_log2, &mut vmo_handle)
113 };
114 ok(status)?;
115 unsafe {
116 Ok(Vmo::from(Handle::from_raw(vmo_handle)))
119 }
120 }
121
122 pub fn read(&self, data: &mut [u8], offset: u64) -> Result<(), Status> {
126 unsafe {
127 let status = sys::zx_vmo_read(self.raw_handle(), data.as_mut_ptr(), offset, data.len());
128 ok(status)
129 }
130 }
131
132 pub unsafe fn read_raw(
138 &self,
139 buffer: *mut u8,
140 buffer_length: usize,
141 offset: u64,
142 ) -> Result<(), Status> {
143 let status = sys::zx_vmo_read(self.raw_handle(), buffer, offset, buffer_length);
144 ok(status)
145 }
146
147 pub fn read_uninit<'a>(
150 &self,
151 data: &'a mut [MaybeUninit<u8>],
152 offset: u64,
153 ) -> Result<&'a mut [u8], Status> {
154 unsafe {
157 self.read_raw(
158 data.as_mut_ptr().cast::<u8>(),
160 data.len(),
161 offset,
162 )?
163 }
164 Ok(
166 unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr().cast::<u8>(), data.len()) },
172 )
173 }
174
175 pub fn read_to_vec(&self, offset: u64, length: u64) -> Result<Vec<u8>, Status> {
177 let len = length.try_into().map_err(|_| Status::INVALID_ARGS)?;
178 let mut buffer = Vec::with_capacity(len);
179 self.read_uninit(buffer.spare_capacity_mut(), offset)?;
180 unsafe {
181 buffer.set_len(len);
184 }
185 Ok(buffer)
186 }
187
188 pub fn read_to_array<T: FromBytes, const N: usize>(
190 &self,
191 offset: u64,
192 ) -> Result<[T; N], Status> {
193 let array: MaybeUninit<[MaybeUninit<T>; N]> = MaybeUninit::uninit();
195 let mut array = unsafe { array.assume_init() };
199
200 let buffer = unsafe {
206 std::slice::from_raw_parts_mut(
207 array.as_mut_ptr().cast::<MaybeUninit<u8>>(),
208 N * std::mem::size_of::<T>(),
209 )
210 };
211
212 self.read_uninit(buffer, offset)?;
213 let buffer = array.map(|a| unsafe { a.assume_init() });
218 Ok(buffer)
219 }
220
221 pub fn read_to_object<T: FromBytes>(&self, offset: u64) -> Result<T, Status> {
223 let mut object = MaybeUninit::<T>::uninit();
224 let buffer = unsafe {
230 std::slice::from_raw_parts_mut(
231 object.as_mut_ptr().cast::<MaybeUninit<u8>>(),
232 std::mem::size_of::<T>(),
233 )
234 };
235 self.read_uninit(buffer, offset)?;
236
237 let object = unsafe { object.assume_init() };
240 Ok(object)
241 }
242
243 pub fn write(&self, data: &[u8], offset: u64) -> Result<(), Status> {
247 unsafe {
248 let status = sys::zx_vmo_write(self.raw_handle(), data.as_ptr(), offset, data.len());
249 ok(status)
250 }
251 }
252
253 pub fn transfer_data(
255 &self,
256 options: TransferDataOptions,
257 offset: u64,
258 length: u64,
259 src_vmo: &Vmo,
260 src_offset: u64,
261 ) -> Result<(), Status> {
262 let status = unsafe {
263 sys::zx_vmo_transfer_data(
264 self.raw_handle(),
265 options.bits(),
266 offset,
267 length,
268 src_vmo.raw_handle(),
269 src_offset,
270 )
271 };
272 ok(status)
273 }
274
275 pub fn get_size(&self) -> Result<u64, Status> {
279 let mut size = 0;
280 let status = unsafe { sys::zx_vmo_get_size(self.raw_handle(), &mut size) };
281 ok(status).map(|()| size)
282 }
283
284 pub fn set_size(&self, size: u64) -> Result<(), Status> {
288 let status = unsafe { sys::zx_vmo_set_size(self.raw_handle(), size) };
289 ok(status)
290 }
291
292 pub fn get_stream_size(&self) -> Result<u64, Status> {
296 let mut size = 0;
297 let status = unsafe { sys::zx_vmo_get_stream_size(self.raw_handle(), &mut size) };
298 ok(status).map(|()| size)
299 }
300
301 pub fn set_stream_size(&self, size: u64) -> Result<(), Status> {
305 let status = unsafe { sys::zx_vmo_set_stream_size(self.raw_handle(), size) };
306 ok(status)
307 }
308
309 pub fn set_cache_policy(&self, cache_policy: CachePolicy) -> Result<(), Status> {
313 let status =
314 unsafe { sys::zx_vmo_set_cache_policy(self.raw_handle(), cache_policy as u32) };
315 ok(status)
316 }
317
318 pub fn op_range(&self, op: VmoOp, offset: u64, size: u64) -> Result<(), Status> {
324 let status = unsafe {
325 sys::zx_vmo_op_range(self.raw_handle(), op.into_raw(), offset, size, ptr::null_mut(), 0)
326 };
327 ok(status)
328 }
329
330 pub fn info(&self) -> Result<VmoInfo, Status> {
333 Ok(VmoInfo::from(object_get_info_single::<VmoInfoQuery>(self.as_handle_ref())?))
334 }
335
336 pub fn create_child(
342 &self,
343 opts: VmoChildOptions,
344 offset: u64,
345 size: u64,
346 ) -> Result<Vmo, Status> {
347 let mut out = 0;
348 let status = unsafe {
349 sys::zx_vmo_create_child(self.raw_handle(), opts.bits(), offset, size, &mut out)
350 };
351 ok(status)?;
352 unsafe { Ok(Vmo::from(Handle::from_raw(out))) }
353 }
354
355 pub fn replace_as_executable(self, vmex: &Resource) -> Result<Vmo, Status> {
361 let mut out = 0;
362 let status = unsafe {
363 sys::zx_vmo_replace_as_executable(self.raw_handle(), vmex.raw_handle(), &mut out)
364 };
365 std::mem::forget(self);
369 ok(status)?;
370 unsafe { Ok(Vmo::from(Handle::from_raw(out))) }
371 }
372}
373
374bitflags! {
375 #[repr(transparent)]
377 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
378 pub struct VmoOptions: u32 {
379 const RESIZABLE = sys::ZX_VMO_RESIZABLE;
380 const TRAP_DIRTY = sys::ZX_VMO_TRAP_DIRTY;
381 const UNBOUNDED = sys::ZX_VMO_UNBOUNDED;
382 }
383}
384
385#[repr(transparent)]
387#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, FromBytes, Immutable)]
388pub struct VmoInfoFlags(u32);
389
390bitflags! {
391 impl VmoInfoFlags : u32 {
392 const PAGED = sys::ZX_INFO_VMO_TYPE_PAGED;
393 const RESIZABLE = sys::ZX_INFO_VMO_RESIZABLE;
394 const IS_COW_CLONE = sys::ZX_INFO_VMO_IS_COW_CLONE;
395 const VIA_HANDLE = sys::ZX_INFO_VMO_VIA_HANDLE;
396 const VIA_MAPPING = sys::ZX_INFO_VMO_VIA_MAPPING;
397 const PAGER_BACKED = sys::ZX_INFO_VMO_PAGER_BACKED;
398 const CONTIGUOUS = sys::ZX_INFO_VMO_CONTIGUOUS;
399 const DISCARDABLE = sys::ZX_INFO_VMO_DISCARDABLE;
400 const IMMUTABLE = sys::ZX_INFO_VMO_IMMUTABLE;
401 const VIA_IOB_HANDLE = sys::ZX_INFO_VMO_VIA_IOB_HANDLE;
402 }
403}
404
405impl std::fmt::Debug for VmoInfoFlags {
406 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
407 bitflags::parser::to_writer(self, f)
408 }
409}
410
411bitflags! {
412 #[repr(transparent)]
414 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
415 pub struct VmoChildOptions: u32 {
416 const SNAPSHOT = sys::ZX_VMO_CHILD_SNAPSHOT;
417 const SNAPSHOT_AT_LEAST_ON_WRITE = sys::ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE;
418 const RESIZABLE = sys::ZX_VMO_CHILD_RESIZABLE;
419 const SLICE = sys::ZX_VMO_CHILD_SLICE;
420 const NO_WRITE = sys::ZX_VMO_CHILD_NO_WRITE;
421 const REFERENCE = sys::ZX_VMO_CHILD_REFERENCE;
422 const SNAPSHOT_MODIFIED = sys::ZX_VMO_CHILD_SNAPSHOT_MODIFIED;
423 }
424}
425
426bitflags! {
427 #[repr(transparent)]
429 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
430 pub struct TransferDataOptions: u32 {
431 }
432}
433
434#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
436#[repr(transparent)]
437pub struct VmoOp(u32);
438impl VmoOp {
439 pub fn from_raw(raw: u32) -> VmoOp {
440 VmoOp(raw)
441 }
442 pub fn into_raw(self) -> u32 {
443 self.0
444 }
445}
446
447#[derive(Debug, Copy, Clone, Eq, PartialEq)]
449#[repr(u32)]
450pub enum CachePolicy {
451 Cached = sys::ZX_CACHE_POLICY_CACHED,
452 UnCached = sys::ZX_CACHE_POLICY_UNCACHED,
453 UnCachedDevice = sys::ZX_CACHE_POLICY_UNCACHED_DEVICE,
454 WriteCombining = sys::ZX_CACHE_POLICY_WRITE_COMBINING,
455 Unknown = u32::MAX,
456}
457
458impl From<u32> for CachePolicy {
459 fn from(v: u32) -> Self {
460 match v {
461 sys::ZX_CACHE_POLICY_CACHED => CachePolicy::Cached,
462 sys::ZX_CACHE_POLICY_UNCACHED => CachePolicy::UnCached,
463 sys::ZX_CACHE_POLICY_UNCACHED_DEVICE => CachePolicy::UnCachedDevice,
464 sys::ZX_CACHE_POLICY_WRITE_COMBINING => CachePolicy::WriteCombining,
465 _ => CachePolicy::Unknown,
466 }
467 }
468}
469
470impl Into<u32> for CachePolicy {
471 fn into(self) -> u32 {
472 match self {
473 CachePolicy::Cached => sys::ZX_CACHE_POLICY_CACHED,
474 CachePolicy::UnCached => sys::ZX_CACHE_POLICY_UNCACHED,
475 CachePolicy::UnCachedDevice => sys::ZX_CACHE_POLICY_UNCACHED_DEVICE,
476 CachePolicy::WriteCombining => sys::ZX_CACHE_POLICY_WRITE_COMBINING,
477 CachePolicy::Unknown => u32::MAX,
478 }
479 }
480}
481
482assoc_values!(VmoOp, [
483 COMMIT = sys::ZX_VMO_OP_COMMIT;
484 DECOMMIT = sys::ZX_VMO_OP_DECOMMIT;
485 LOCK = sys::ZX_VMO_OP_LOCK;
486 UNLOCK = sys::ZX_VMO_OP_UNLOCK;
487 CACHE_SYNC = sys::ZX_VMO_OP_CACHE_SYNC;
488 CACHE_INVALIDATE = sys::ZX_VMO_OP_CACHE_INVALIDATE;
489 CACHE_CLEAN = sys::ZX_VMO_OP_CACHE_CLEAN;
490 CACHE_CLEAN_INVALIDATE = sys::ZX_VMO_OP_CACHE_CLEAN_INVALIDATE;
491 ZERO = sys::ZX_VMO_OP_ZERO;
492 TRY_LOCK = sys::ZX_VMO_OP_TRY_LOCK;
493 DONT_NEED = sys::ZX_VMO_OP_DONT_NEED;
494 ALWAYS_NEED = sys::ZX_VMO_OP_ALWAYS_NEED;
495 PREFETCH = sys::ZX_VMO_OP_PREFETCH;
496]);
497
498unsafe_handle_properties!(object: Vmo,
499 props: [
500 {query_ty: VMO_CONTENT_SIZE, tag: VmoContentSizeTag, prop_ty: u64, get:get_content_size, set: set_content_size},
501 ]
502);
503
504#[cfg(test)]
505mod tests {
506 use super::*;
507 use crate::{Iommu, IommuDescDummy, ObjectType};
508 use fidl_fuchsia_kernel as fkernel;
509 use fuchsia_component::client::connect_channel_to_protocol;
510 use test_case::test_case;
511 use zerocopy::KnownLayout;
512
513 #[test]
514 fn vmo_create_contiguous_invalid_handle() {
515 let status = Vmo::create_contiguous(&Bti::from(Handle::invalid()), 4096, 0);
516 assert_eq!(status, Err(Status::BAD_HANDLE));
517 }
518
519 #[test]
520 fn vmo_create_contiguous() {
521 use zx::{Channel, HandleBased, MonotonicInstant};
522 let (client_end, server_end) = Channel::create();
523 connect_channel_to_protocol::<fkernel::IommuResourceMarker>(server_end).unwrap();
524 let service = fkernel::IommuResourceSynchronousProxy::new(client_end);
525 let resource =
526 service.get(MonotonicInstant::INFINITE).expect("couldn't get iommu resource");
527 let resource = unsafe { Resource::from(Handle::from_raw(resource.into_raw())) };
531 let iommu = Iommu::create_dummy(&resource, IommuDescDummy::default()).unwrap();
532 let bti = Bti::create(&iommu, 0).unwrap();
533
534 let vmo = Vmo::create_contiguous(&bti, 8192, 0).unwrap();
535 let info = vmo.as_handle_ref().basic_info().unwrap();
536 assert_eq!(info.object_type, ObjectType::VMO);
537
538 let vmo_info = vmo.info().unwrap();
539 assert!(vmo_info.flags.contains(VmoInfoFlags::CONTIGUOUS));
540 }
541
542 #[test]
543 fn vmo_get_size() {
544 let size = 16 * 1024 * 1024;
545 let vmo = Vmo::create(size).unwrap();
546 assert_eq!(size, vmo.get_size().unwrap());
547 }
548
549 #[test]
550 fn vmo_set_size() {
551 let start_size = 4096;
553 let vmo = Vmo::create_with_opts(VmoOptions::RESIZABLE, start_size).unwrap();
554 assert_eq!(start_size, vmo.get_size().unwrap());
555
556 let new_size = 8192;
558 assert!(vmo.set_size(new_size).is_ok());
559 assert_eq!(new_size, vmo.get_size().unwrap());
560 }
561
562 #[test]
563 fn vmo_get_info_default() {
564 let size = 4096;
565 let vmo = Vmo::create(size).unwrap();
566 let info = vmo.info().unwrap();
567 assert!(!info.flags.contains(VmoInfoFlags::PAGER_BACKED));
568 assert!(info.flags.contains(VmoInfoFlags::PAGED));
569 }
570
571 #[test]
572 fn vmo_get_child_info() {
573 let size = 4096;
574 let vmo = Vmo::create(size).unwrap();
575 let info = vmo.info().unwrap();
576 assert!(!info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
577
578 let child = vmo.create_child(VmoChildOptions::SNAPSHOT, 0, 512).unwrap();
579 let info = child.info().unwrap();
580 assert!(info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
581
582 let child = vmo.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, 512).unwrap();
583 let info = child.info().unwrap();
584 assert!(info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
585
586 let child = vmo.create_child(VmoChildOptions::SLICE, 0, 512).unwrap();
587 let info = child.info().unwrap();
588 assert!(!info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
589 }
590
591 #[test]
592 fn vmo_set_size_fails_on_non_resizable() {
593 let size = 4096;
594 let vmo = Vmo::create(size).unwrap();
595 assert_eq!(size, vmo.get_size().unwrap());
596
597 let new_size = 8192;
598 assert_eq!(Err(Status::UNAVAILABLE), vmo.set_size(new_size));
599 assert_eq!(size, vmo.get_size().unwrap());
600 }
601
602 #[test_case(0)]
603 #[test_case(1)]
604 fn vmo_read_to_array(read_offset: usize) {
605 const ACTUAL_SIZE: usize = 5;
606 const ACTUAL: [u8; ACTUAL_SIZE] = [1, 2, 3, 4, 5];
607 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
608 vmo.write(&ACTUAL, 0).unwrap();
609 let read_len = ACTUAL_SIZE - read_offset;
610 assert_eq!(
611 &vmo.read_to_array::<u8, ACTUAL_SIZE>(read_offset as u64).unwrap()[..read_len],
612 &ACTUAL[read_offset..]
613 );
614 }
615
616 #[test_case(0)]
617 #[test_case(1)]
618 fn vmo_read_to_vec(read_offset: usize) {
619 const ACTUAL_SIZE: usize = 4;
620 const ACTUAL: [u8; ACTUAL_SIZE] = [6, 7, 8, 9];
621 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
622 vmo.write(&ACTUAL, 0).unwrap();
623 let read_len = ACTUAL_SIZE - read_offset;
624 assert_eq!(
625 &vmo.read_to_vec(read_offset as u64, read_len as u64).unwrap(),
626 &ACTUAL[read_offset..]
627 );
628 }
629
630 #[test_case(0)]
631 #[test_case(1)]
632 fn vmo_read_to_object(read_offset: usize) {
633 #[repr(C)]
634 #[derive(Debug, Eq, KnownLayout, FromBytes, PartialEq)]
635 struct Object {
636 a: u8,
637 b: u8,
638 }
639
640 const ACTUAL_SIZE: usize = std::mem::size_of::<Object>();
641 const ACTUAL: [u8; ACTUAL_SIZE + 1] = [10, 11, 12];
642 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
643 vmo.write(&ACTUAL, 0).unwrap();
644 assert_eq!(
645 vmo.read_to_object::<Object>(read_offset as u64).unwrap(),
646 Object { a: ACTUAL[read_offset], b: ACTUAL[1 + read_offset] }
647 );
648 }
649
650 #[test]
651 fn vmo_read_write() {
652 let mut vec1 = vec![0; 16];
653 let vmo = Vmo::create(4096 as u64).unwrap();
654 assert!(vmo.write(b"abcdef", 0).is_ok());
655 assert!(vmo.read(&mut vec1, 0).is_ok());
656 assert_eq!(b"abcdef", &vec1[0..6]);
657 assert!(vmo.write(b"123", 2).is_ok());
658 assert!(vmo.read(&mut vec1, 0).is_ok());
659 assert_eq!(b"ab123f", &vec1[0..6]);
660
661 assert!(vmo.read(&mut vec1, 1).is_ok());
663 assert_eq!(b"b123f", &vec1[0..5]);
664
665 assert_eq!(&vmo.read_to_vec(0, 6).expect("read_to_vec failed"), b"ab123f");
666 }
667
668 #[test]
669 fn vmo_child_snapshot() {
670 let size = 4096 * 2;
671 let vmo = Vmo::create(size).unwrap();
672
673 vmo.write(&[1; 4096], 0).unwrap();
674 vmo.write(&[2; 4096], 4096).unwrap();
675
676 let child = vmo.create_child(VmoChildOptions::SNAPSHOT, 0, size).unwrap();
677
678 child.write(&[3; 4096], 0).unwrap();
679
680 vmo.write(&[4; 4096], 0).unwrap();
681 vmo.write(&[5; 4096], 4096).unwrap();
682
683 let mut page = [0; 4096];
684
685 child.read(&mut page[..], 0).unwrap();
687 assert_eq!(&page[..], &[3; 4096][..]);
688 child.read(&mut page[..], 4096).unwrap();
689 assert_eq!(&page[..], &[2; 4096][..]);
690 }
691
692 #[test]
693 fn vmo_child_snapshot_at_least_on_write() {
694 let size = 4096 * 2;
695 let vmo = Vmo::create(size).unwrap();
696
697 vmo.write(&[1; 4096], 0).unwrap();
698 vmo.write(&[2; 4096], 4096).unwrap();
699
700 let child = vmo.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, size).unwrap();
701
702 child.write(&[3; 4096], 0).unwrap();
703
704 vmo.write(&[4; 4096], 0).unwrap();
705 vmo.write(&[5; 4096], 4096).unwrap();
706
707 let mut page = [0; 4096];
708
709 child.read(&mut page[..], 0).unwrap();
712 assert_eq!(&page[..], &[3; 4096][..]);
713 child.read(&mut page[..], 4096).unwrap();
714 assert!(
715 &page[..] == &[2; 4096][..] || &page[..] == &[5; 4096][..],
716 "expected page of 2 or 5, got {:?}",
717 &page[..]
718 );
719 }
720
721 #[test]
722 fn vmo_child_no_write() {
723 let size = 4096;
724 let vmo = Vmo::create(size).unwrap();
725 vmo.write(&[1; 4096], 0).unwrap();
726
727 let child =
728 vmo.create_child(VmoChildOptions::SLICE | VmoChildOptions::NO_WRITE, 0, size).unwrap();
729 assert_eq!(child.write(&[3; 4096], 0), Err(Status::ACCESS_DENIED));
730 }
731
732 #[test]
733 fn vmo_op_range_unsupported() {
734 let vmo = Vmo::create(12).unwrap();
735 assert_eq!(vmo.op_range(VmoOp::LOCK, 0, 1), Err(Status::NOT_SUPPORTED));
736 assert_eq!(vmo.op_range(VmoOp::UNLOCK, 0, 1), Err(Status::NOT_SUPPORTED));
737 }
738
739 #[test]
740 fn vmo_cache() {
741 let vmo = Vmo::create(12).unwrap();
742
743 assert_eq!(vmo.op_range(VmoOp::CACHE_SYNC, 0, 12), Ok(()));
745 assert_eq!(vmo.op_range(VmoOp::CACHE_INVALIDATE, 0, 12), Ok(()));
746 assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN, 0, 12), Ok(()));
747 assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN_INVALIDATE, 0, 12), Ok(()));
748 }
749
750 #[test]
751 fn vmo_create_child() {
752 let original = Vmo::create(16).unwrap();
753 assert!(original.write(b"one", 0).is_ok());
754
755 let clone =
757 original.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, 16).unwrap();
758 let mut read_buffer = vec![0; 16];
759 assert!(clone.read(&mut read_buffer, 0).is_ok());
760 assert_eq!(&read_buffer[0..3], b"one");
761
762 assert!(original.write(b"two", 0).is_ok());
764 assert!(original.read(&mut read_buffer, 0).is_ok());
765 assert_eq!(&read_buffer[0..3], b"two");
766 assert!(clone.read(&mut read_buffer, 0).is_ok());
767 assert_eq!(&read_buffer[0..3], b"one");
768
769 assert!(clone.write(b"three", 0).is_ok());
771 assert!(original.read(&mut read_buffer, 0).is_ok());
772 assert_eq!(&read_buffer[0..3], b"two");
773 assert!(clone.read(&mut read_buffer, 0).is_ok());
774 assert_eq!(&read_buffer[0..5], b"three");
775 }
776
777 #[test]
778 fn vmo_replace_as_executeable() {
779 use zx::{Channel, HandleBased, MonotonicInstant};
780
781 let vmo = Vmo::create(16).unwrap();
782
783 let info = vmo.as_handle_ref().basic_info().unwrap();
784 assert!(!info.rights.contains(Rights::EXECUTE));
785
786 let (client_end, server_end) = Channel::create();
787 connect_channel_to_protocol::<fkernel::VmexResourceMarker>(server_end).unwrap();
788 let service = fkernel::VmexResourceSynchronousProxy::new(client_end);
789 let resource = service.get(MonotonicInstant::INFINITE).expect("couldn't get vmex resource");
790 let resource = unsafe { crate::Resource::from(Handle::from_raw(resource.into_raw())) };
791
792 let exec_vmo = vmo.replace_as_executable(&resource).unwrap();
793 let info = exec_vmo.as_handle_ref().basic_info().unwrap();
794 assert!(info.rights.contains(Rights::EXECUTE));
795 }
796
797 #[test]
798 fn vmo_content_size() {
799 let start_size = 1024;
800 let vmo = Vmo::create_with_opts(VmoOptions::RESIZABLE, start_size).unwrap();
801 assert_eq!(vmo.get_content_size().unwrap(), start_size);
802 vmo.set_content_size(&0).unwrap();
803 assert_eq!(vmo.get_content_size().unwrap(), 0);
804
805 let content = b"abcdef";
807 assert!(vmo.write(content, 0).is_ok());
808 assert_eq!(vmo.get_content_size().unwrap(), 0);
809 }
810
811 #[test]
812 fn vmo_zero() {
813 let vmo = Vmo::create(16).unwrap();
814 let content = b"0123456789abcdef";
815 assert!(vmo.write(content, 0).is_ok());
816 let mut buf = vec![0u8; 16];
817 assert!(vmo.read(&mut buf[..], 0).is_ok());
818 assert_eq!(&buf[..], content);
819
820 assert!(vmo.op_range(VmoOp::ZERO, 0, 16).is_ok());
821 assert!(vmo.read(&mut buf[..], 0).is_ok());
822 assert_eq!(&buf[..], &[0u8; 16]);
823 }
824
825 #[test]
826 fn vmo_stream_size() {
827 let start_size = 1300;
828 let vmo = Vmo::create_with_opts(VmoOptions::UNBOUNDED, start_size).unwrap();
829 assert_eq!(vmo.get_stream_size().unwrap(), start_size);
830 vmo.set_stream_size(0).unwrap();
831 assert_eq!(vmo.get_stream_size().unwrap(), 0);
832
833 let content = b"abcdef";
835 assert!(vmo.write(content, 0).is_ok());
836 assert_eq!(vmo.get_stream_size().unwrap(), 0);
837
838 let mut buf = vec![1; 6];
840 vmo.set_stream_size(6).unwrap();
841 assert!(vmo.read(&mut buf, 0).is_ok());
842 assert_eq!(buf, vec![0; 6]);
844 }
845}