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