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