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 mut array: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
206
207 let buffer = unsafe {
213 std::slice::from_raw_parts_mut(
214 array.as_mut_ptr().cast::<MaybeUninit<u8>>(),
215 N * std::mem::size_of::<T>(),
216 )
217 };
218
219 self.read_uninit(buffer, offset)?;
220 let buffer = array.map(|a| unsafe { a.assume_init() });
225 Ok(buffer)
226 }
227
228 pub fn read_to_object<T: Copy + FromBytes>(&self, offset: u64) -> Result<T, Status> {
230 let mut object = MaybeUninit::<T>::uninit();
231 let buffer = unsafe {
237 std::slice::from_raw_parts_mut(
238 object.as_mut_ptr().cast::<MaybeUninit<u8>>(),
239 std::mem::size_of::<T>(),
240 )
241 };
242 self.read_uninit(buffer, offset)?;
243
244 let object = unsafe { object.assume_init() };
247 Ok(object)
248 }
249
250 pub fn write(&self, data: &[u8], offset: u64) -> Result<(), Status> {
254 unsafe {
255 let status = sys::zx_vmo_write(self.raw_handle(), data.as_ptr(), offset, data.len());
256 ok(status)
257 }
258 }
259
260 pub fn transfer_data(
262 &self,
263 options: TransferDataOptions,
264 offset: u64,
265 length: u64,
266 src_vmo: &Vmo,
267 src_offset: u64,
268 ) -> Result<(), Status> {
269 let status = unsafe {
270 sys::zx_vmo_transfer_data(
271 self.raw_handle(),
272 options.bits(),
273 offset,
274 length,
275 src_vmo.raw_handle(),
276 src_offset,
277 )
278 };
279 ok(status)
280 }
281
282 pub fn get_size(&self) -> Result<u64, Status> {
286 let mut size = 0;
287 let status = unsafe { sys::zx_vmo_get_size(self.raw_handle(), &mut size) };
288 ok(status).map(|()| size)
289 }
290
291 pub fn set_size(&self, size: u64) -> Result<(), Status> {
295 let status = unsafe { sys::zx_vmo_set_size(self.raw_handle(), size) };
296 ok(status)
297 }
298
299 pub fn get_stream_size(&self) -> Result<u64, Status> {
303 let mut size = 0;
304 let status = unsafe { sys::zx_vmo_get_stream_size(self.raw_handle(), &mut size) };
305 ok(status).map(|()| size)
306 }
307
308 pub fn set_stream_size(&self, size: u64) -> Result<(), Status> {
312 let status = unsafe { sys::zx_vmo_set_stream_size(self.raw_handle(), size) };
313 ok(status)
314 }
315
316 pub fn set_cache_policy(&self, cache_policy: CachePolicy) -> Result<(), Status> {
320 let status =
321 unsafe { sys::zx_vmo_set_cache_policy(self.raw_handle(), cache_policy as u32) };
322 ok(status)
323 }
324
325 pub fn op_range(&self, op: VmoOp, offset: u64, size: u64) -> Result<(), Status> {
331 let status = unsafe {
332 sys::zx_vmo_op_range(self.raw_handle(), op.into_raw(), offset, size, ptr::null_mut(), 0)
333 };
334 ok(status)
335 }
336
337 pub fn info(&self) -> Result<VmoInfo, Status> {
340 Ok(VmoInfo::from(self.0.get_info_single::<VmoInfoQuery>()?))
341 }
342
343 pub fn create_child(
349 &self,
350 opts: VmoChildOptions,
351 offset: u64,
352 size: u64,
353 ) -> Result<Vmo, Status> {
354 let mut out = 0;
355 let status = unsafe {
356 sys::zx_vmo_create_child(self.raw_handle(), opts.bits(), offset, size, &mut out)
357 };
358 ok(status)?;
359 unsafe { Ok(Vmo::from(NullableHandle::from_raw(out))) }
360 }
361
362 pub fn replace_as_executable(self, vmex: &Resource) -> Result<Vmo, Status> {
368 let mut out = 0;
369 let status = unsafe {
370 sys::zx_vmo_replace_as_executable(self.raw_handle(), vmex.raw_handle(), &mut out)
371 };
372 std::mem::forget(self);
376 ok(status)?;
377 unsafe { Ok(Vmo::from(NullableHandle::from_raw(out))) }
378 }
379}
380
381bitflags! {
382 #[repr(transparent)]
384 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
385 pub struct VmoOptions: u32 {
386 const RESIZABLE = sys::ZX_VMO_RESIZABLE;
387 const TRAP_DIRTY = sys::ZX_VMO_TRAP_DIRTY;
388 const UNBOUNDED = sys::ZX_VMO_UNBOUNDED;
389 }
390}
391
392#[repr(transparent)]
394#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, FromBytes, Immutable)]
395pub struct VmoInfoFlags(u32);
396
397bitflags! {
398 impl VmoInfoFlags : u32 {
399 const PAGED = sys::ZX_INFO_VMO_TYPE_PAGED;
400 const RESIZABLE = sys::ZX_INFO_VMO_RESIZABLE;
401 const IS_COW_CLONE = sys::ZX_INFO_VMO_IS_COW_CLONE;
402 const VIA_HANDLE = sys::ZX_INFO_VMO_VIA_HANDLE;
403 const VIA_MAPPING = sys::ZX_INFO_VMO_VIA_MAPPING;
404 const PAGER_BACKED = sys::ZX_INFO_VMO_PAGER_BACKED;
405 const CONTIGUOUS = sys::ZX_INFO_VMO_CONTIGUOUS;
406 const DISCARDABLE = sys::ZX_INFO_VMO_DISCARDABLE;
407 const IMMUTABLE = sys::ZX_INFO_VMO_IMMUTABLE;
408 const VIA_IOB_HANDLE = sys::ZX_INFO_VMO_VIA_IOB_HANDLE;
409 }
410}
411
412impl std::fmt::Debug for VmoInfoFlags {
413 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
414 bitflags::parser::to_writer(self, f)
415 }
416}
417
418bitflags! {
419 #[repr(transparent)]
421 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
422 pub struct VmoChildOptions: u32 {
423 const SNAPSHOT = sys::ZX_VMO_CHILD_SNAPSHOT;
424 const SNAPSHOT_AT_LEAST_ON_WRITE = sys::ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE;
425 const RESIZABLE = sys::ZX_VMO_CHILD_RESIZABLE;
426 const SLICE = sys::ZX_VMO_CHILD_SLICE;
427 const NO_WRITE = sys::ZX_VMO_CHILD_NO_WRITE;
428 const REFERENCE = sys::ZX_VMO_CHILD_REFERENCE;
429 const SNAPSHOT_MODIFIED = sys::ZX_VMO_CHILD_SNAPSHOT_MODIFIED;
430 }
431}
432
433bitflags! {
434 #[repr(transparent)]
436 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
437 pub struct TransferDataOptions: u32 {
438 }
439}
440
441#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
443#[repr(transparent)]
444pub struct VmoOp(u32);
445impl VmoOp {
446 pub fn from_raw(raw: u32) -> VmoOp {
447 VmoOp(raw)
448 }
449 pub fn into_raw(self) -> u32 {
450 self.0
451 }
452}
453
454#[derive(Debug, Copy, Clone, Eq, PartialEq)]
456#[repr(u32)]
457pub enum CachePolicy {
458 Cached = sys::ZX_CACHE_POLICY_CACHED,
459 UnCached = sys::ZX_CACHE_POLICY_UNCACHED,
460 UnCachedDevice = sys::ZX_CACHE_POLICY_UNCACHED_DEVICE,
461 WriteCombining = sys::ZX_CACHE_POLICY_WRITE_COMBINING,
462 Unknown = u32::MAX,
463}
464
465impl From<u32> for CachePolicy {
466 fn from(v: u32) -> Self {
467 match v {
468 sys::ZX_CACHE_POLICY_CACHED => CachePolicy::Cached,
469 sys::ZX_CACHE_POLICY_UNCACHED => CachePolicy::UnCached,
470 sys::ZX_CACHE_POLICY_UNCACHED_DEVICE => CachePolicy::UnCachedDevice,
471 sys::ZX_CACHE_POLICY_WRITE_COMBINING => CachePolicy::WriteCombining,
472 _ => CachePolicy::Unknown,
473 }
474 }
475}
476
477impl Into<u32> for CachePolicy {
478 fn into(self) -> u32 {
479 match self {
480 CachePolicy::Cached => sys::ZX_CACHE_POLICY_CACHED,
481 CachePolicy::UnCached => sys::ZX_CACHE_POLICY_UNCACHED,
482 CachePolicy::UnCachedDevice => sys::ZX_CACHE_POLICY_UNCACHED_DEVICE,
483 CachePolicy::WriteCombining => sys::ZX_CACHE_POLICY_WRITE_COMBINING,
484 CachePolicy::Unknown => u32::MAX,
485 }
486 }
487}
488
489assoc_values!(VmoOp, [
490 COMMIT = sys::ZX_VMO_OP_COMMIT;
491 DECOMMIT = sys::ZX_VMO_OP_DECOMMIT;
492 LOCK = sys::ZX_VMO_OP_LOCK;
493 UNLOCK = sys::ZX_VMO_OP_UNLOCK;
494 CACHE_SYNC = sys::ZX_VMO_OP_CACHE_SYNC;
495 CACHE_INVALIDATE = sys::ZX_VMO_OP_CACHE_INVALIDATE;
496 CACHE_CLEAN = sys::ZX_VMO_OP_CACHE_CLEAN;
497 CACHE_CLEAN_INVALIDATE = sys::ZX_VMO_OP_CACHE_CLEAN_INVALIDATE;
498 ZERO = sys::ZX_VMO_OP_ZERO;
499 TRY_LOCK = sys::ZX_VMO_OP_TRY_LOCK;
500 DONT_NEED = sys::ZX_VMO_OP_DONT_NEED;
501 ALWAYS_NEED = sys::ZX_VMO_OP_ALWAYS_NEED;
502 PREFETCH = sys::ZX_VMO_OP_PREFETCH;
503]);
504
505unsafe_handle_properties!(object: Vmo,
506 props: [
507 {query_ty: VMO_CONTENT_SIZE, tag: VmoContentSizeTag, prop_ty: u64, get:get_content_size, set: set_content_size},
508 ]
509);
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514 use crate::{Iommu, IommuDescStub, ObjectType};
515 use fidl_fuchsia_kernel as fkernel;
516 use fuchsia_component::client::connect_channel_to_protocol;
517 use test_case::test_case;
518 use zerocopy::KnownLayout;
519
520 #[test]
521 fn vmo_create_contiguous() {
522 use zx::{Channel, MonotonicInstant};
523 let (client_end, server_end) = Channel::create();
524 connect_channel_to_protocol::<fkernel::IommuResourceMarker>(server_end).unwrap();
525 let service = fkernel::IommuResourceSynchronousProxy::new(client_end);
526 let resource =
527 service.get(MonotonicInstant::INFINITE).expect("couldn't get iommu resource");
528 let resource = unsafe { Resource::from(NullableHandle::from_raw(resource.into_raw())) };
532 let iommu = Iommu::create_stub(&resource, IommuDescStub::default()).unwrap();
533 let bti = Bti::create(&iommu, 0).unwrap();
534
535 let vmo = Vmo::create_contiguous(&bti, 8192, 0).unwrap();
536 let info = vmo.as_handle_ref().basic_info().unwrap();
537 assert_eq!(info.object_type, ObjectType::VMO);
538
539 let vmo_info = vmo.info().unwrap();
540 assert!(vmo_info.flags.contains(VmoInfoFlags::CONTIGUOUS));
541 }
542
543 #[test]
544 fn vmo_get_size() {
545 let size = 16 * 1024 * 1024;
546 let vmo = Vmo::create(size).unwrap();
547 assert_eq!(size, vmo.get_size().unwrap());
548 }
549
550 #[test]
551 fn vmo_set_size() {
552 let start_size = 4096;
554 let vmo = Vmo::create_with_opts(VmoOptions::RESIZABLE, start_size).unwrap();
555 assert_eq!(start_size, vmo.get_size().unwrap());
556
557 let new_size = 8192;
559 assert!(vmo.set_size(new_size).is_ok());
560 assert_eq!(new_size, vmo.get_size().unwrap());
561 }
562
563 #[test]
564 fn vmo_get_info_default() {
565 let size = 4096;
566 let vmo = Vmo::create(size).unwrap();
567 let info = vmo.info().unwrap();
568 assert!(!info.flags.contains(VmoInfoFlags::PAGER_BACKED));
569 assert!(info.flags.contains(VmoInfoFlags::PAGED));
570 }
571
572 #[test]
573 fn vmo_get_child_info() {
574 let size = 4096;
575 let vmo = Vmo::create(size).unwrap();
576 let info = vmo.info().unwrap();
577 assert!(!info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
578
579 let child = vmo.create_child(VmoChildOptions::SNAPSHOT, 0, 512).unwrap();
580 let info = child.info().unwrap();
581 assert!(info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
582
583 let child = vmo.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, 512).unwrap();
584 let info = child.info().unwrap();
585 assert!(info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
586
587 let child = vmo.create_child(VmoChildOptions::SLICE, 0, 512).unwrap();
588 let info = child.info().unwrap();
589 assert!(!info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
590 }
591
592 #[test]
593 fn vmo_set_size_fails_on_non_resizable() {
594 let size = 4096;
595 let vmo = Vmo::create(size).unwrap();
596 assert_eq!(size, vmo.get_size().unwrap());
597
598 let new_size = 8192;
599 assert_eq!(Err(Status::UNAVAILABLE), vmo.set_size(new_size));
600 assert_eq!(size, vmo.get_size().unwrap());
601 }
602
603 #[test_case(0)]
604 #[test_case(1)]
605 fn vmo_read_to_array(read_offset: usize) {
606 const ACTUAL_SIZE: usize = 5;
607 const ACTUAL: [u8; ACTUAL_SIZE] = [1, 2, 3, 4, 5];
608 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
609 vmo.write(&ACTUAL, 0).unwrap();
610 let read_len = ACTUAL_SIZE - read_offset;
611 assert_eq!(
612 &vmo.read_to_array::<u8, ACTUAL_SIZE>(read_offset as u64).unwrap()[..read_len],
613 &ACTUAL[read_offset..]
614 );
615 }
616
617 #[test_case(0)]
618 #[test_case(1)]
619 fn vmo_read_to_vec(read_offset: usize) {
620 const ACTUAL_SIZE: usize = 4;
621 const ACTUAL: [u8; ACTUAL_SIZE] = [6, 7, 8, 9];
622 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
623 vmo.write(&ACTUAL, 0).unwrap();
624 let read_len = ACTUAL_SIZE - read_offset;
625 assert_eq!(
626 &vmo.read_to_vec::<u8>(read_offset as u64, read_len as u64).unwrap(),
627 &ACTUAL[read_offset..]
628 );
629 }
630
631 #[test_case(0)]
632 #[test_case(1)]
633 fn vmo_read_to_object(read_offset: usize) {
634 #[repr(C)]
635 #[derive(Copy, Clone, Debug, Eq, KnownLayout, FromBytes, PartialEq)]
636 struct Object {
637 a: u8,
638 b: u8,
639 }
640
641 const ACTUAL_SIZE: usize = std::mem::size_of::<Object>();
642 const ACTUAL: [u8; ACTUAL_SIZE + 1] = [10, 11, 12];
643 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
644 vmo.write(&ACTUAL, 0).unwrap();
645 assert_eq!(
646 vmo.read_to_object::<Object>(read_offset as u64).unwrap(),
647 Object { a: ACTUAL[read_offset], b: ACTUAL[1 + read_offset] }
648 );
649 }
650
651 #[test]
652 fn vmo_read_write() {
653 let mut vec1 = vec![0; 16];
654 let vmo = Vmo::create(4096 as u64).unwrap();
655 assert!(vmo.write(b"abcdef", 0).is_ok());
656 assert!(vmo.read(&mut vec1, 0).is_ok());
657 assert_eq!(b"abcdef", &vec1[0..6]);
658 assert!(vmo.write(b"123", 2).is_ok());
659 assert!(vmo.read(&mut vec1, 0).is_ok());
660 assert_eq!(b"ab123f", &vec1[0..6]);
661
662 assert!(vmo.read(&mut vec1, 1).is_ok());
664 assert_eq!(b"b123f", &vec1[0..5]);
665
666 assert_eq!(&vmo.read_to_vec::<u8>(0, 6).expect("read_to_vec failed"), b"ab123f");
667 }
668
669 #[test]
670 fn vmo_child_snapshot() {
671 let size = 4096 * 2;
672 let vmo = Vmo::create(size).unwrap();
673
674 vmo.write(&[1; 4096], 0).unwrap();
675 vmo.write(&[2; 4096], 4096).unwrap();
676
677 let child = vmo.create_child(VmoChildOptions::SNAPSHOT, 0, size).unwrap();
678
679 child.write(&[3; 4096], 0).unwrap();
680
681 vmo.write(&[4; 4096], 0).unwrap();
682 vmo.write(&[5; 4096], 4096).unwrap();
683
684 let mut page = [0; 4096];
685
686 child.read(&mut page[..], 0).unwrap();
688 assert_eq!(&page[..], &[3; 4096][..]);
689 child.read(&mut page[..], 4096).unwrap();
690 assert_eq!(&page[..], &[2; 4096][..]);
691 }
692
693 #[test]
694 fn vmo_child_snapshot_at_least_on_write() {
695 let size = 4096 * 2;
696 let vmo = Vmo::create(size).unwrap();
697
698 vmo.write(&[1; 4096], 0).unwrap();
699 vmo.write(&[2; 4096], 4096).unwrap();
700
701 let child = vmo.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, size).unwrap();
702
703 child.write(&[3; 4096], 0).unwrap();
704
705 vmo.write(&[4; 4096], 0).unwrap();
706 vmo.write(&[5; 4096], 4096).unwrap();
707
708 let mut page = [0; 4096];
709
710 child.read(&mut page[..], 0).unwrap();
713 assert_eq!(&page[..], &[3; 4096][..]);
714 child.read(&mut page[..], 4096).unwrap();
715 assert!(
716 &page[..] == &[2; 4096][..] || &page[..] == &[5; 4096][..],
717 "expected page of 2 or 5, got {:?}",
718 &page[..]
719 );
720 }
721
722 #[test]
723 fn vmo_child_no_write() {
724 let size = 4096;
725 let vmo = Vmo::create(size).unwrap();
726 vmo.write(&[1; 4096], 0).unwrap();
727
728 let child =
729 vmo.create_child(VmoChildOptions::SLICE | VmoChildOptions::NO_WRITE, 0, size).unwrap();
730 assert_eq!(child.write(&[3; 4096], 0), Err(Status::ACCESS_DENIED));
731 }
732
733 #[test]
734 fn vmo_op_range_unsupported() {
735 let vmo = Vmo::create(12).unwrap();
736 assert_eq!(vmo.op_range(VmoOp::LOCK, 0, 1), Err(Status::NOT_SUPPORTED));
737 assert_eq!(vmo.op_range(VmoOp::UNLOCK, 0, 1), Err(Status::NOT_SUPPORTED));
738 }
739
740 #[test]
741 fn vmo_cache() {
742 let vmo = Vmo::create(12).unwrap();
743
744 assert_eq!(vmo.op_range(VmoOp::CACHE_SYNC, 0, 12), Ok(()));
746 assert_eq!(vmo.op_range(VmoOp::CACHE_INVALIDATE, 0, 12), Ok(()));
747 assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN, 0, 12), Ok(()));
748 assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN_INVALIDATE, 0, 12), Ok(()));
749 }
750
751 #[test]
752 fn vmo_create_child() {
753 let original = Vmo::create(16).unwrap();
754 assert!(original.write(b"one", 0).is_ok());
755
756 let clone =
758 original.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, 16).unwrap();
759 let mut read_buffer = vec![0; 16];
760 assert!(clone.read(&mut read_buffer, 0).is_ok());
761 assert_eq!(&read_buffer[0..3], b"one");
762
763 assert!(original.write(b"two", 0).is_ok());
765 assert!(original.read(&mut read_buffer, 0).is_ok());
766 assert_eq!(&read_buffer[0..3], b"two");
767 assert!(clone.read(&mut read_buffer, 0).is_ok());
768 assert_eq!(&read_buffer[0..3], b"one");
769
770 assert!(clone.write(b"three", 0).is_ok());
772 assert!(original.read(&mut read_buffer, 0).is_ok());
773 assert_eq!(&read_buffer[0..3], b"two");
774 assert!(clone.read(&mut read_buffer, 0).is_ok());
775 assert_eq!(&read_buffer[0..5], b"three");
776 }
777
778 #[test]
779 fn vmo_replace_as_executeable() {
780 use zx::{Channel, MonotonicInstant};
781
782 let vmo = Vmo::create(16).unwrap();
783
784 let info = vmo.as_handle_ref().basic_info().unwrap();
785 assert!(!info.rights.contains(Rights::EXECUTE));
786
787 let (client_end, server_end) = Channel::create();
788 connect_channel_to_protocol::<fkernel::VmexResourceMarker>(server_end).unwrap();
789 let service = fkernel::VmexResourceSynchronousProxy::new(client_end);
790 let resource = service.get(MonotonicInstant::INFINITE).expect("couldn't get vmex resource");
791 let resource =
792 unsafe { crate::Resource::from(NullableHandle::from_raw(resource.into_raw())) };
793
794 let exec_vmo = vmo.replace_as_executable(&resource).unwrap();
795 let info = exec_vmo.as_handle_ref().basic_info().unwrap();
796 assert!(info.rights.contains(Rights::EXECUTE));
797 }
798
799 #[test]
800 fn vmo_content_size() {
801 let start_size = 1024;
802 let vmo = Vmo::create_with_opts(VmoOptions::RESIZABLE, start_size).unwrap();
803 assert_eq!(vmo.get_content_size().unwrap(), start_size);
804 vmo.set_content_size(&0).unwrap();
805 assert_eq!(vmo.get_content_size().unwrap(), 0);
806
807 let content = b"abcdef";
809 assert!(vmo.write(content, 0).is_ok());
810 assert_eq!(vmo.get_content_size().unwrap(), 0);
811 }
812
813 #[test]
814 fn vmo_zero() {
815 let vmo = Vmo::create(16).unwrap();
816 let content = b"0123456789abcdef";
817 assert!(vmo.write(content, 0).is_ok());
818 let mut buf = vec![0u8; 16];
819 assert!(vmo.read(&mut buf[..], 0).is_ok());
820 assert_eq!(&buf[..], content);
821
822 assert!(vmo.op_range(VmoOp::ZERO, 0, 16).is_ok());
823 assert!(vmo.read(&mut buf[..], 0).is_ok());
824 assert_eq!(&buf[..], &[0u8; 16]);
825 }
826
827 #[test]
828 fn vmo_stream_size() {
829 let start_size = 1300;
830 let vmo = Vmo::create_with_opts(VmoOptions::UNBOUNDED, start_size).unwrap();
831 assert_eq!(vmo.get_stream_size().unwrap(), start_size);
832 vmo.set_stream_size(0).unwrap();
833 assert_eq!(vmo.get_stream_size().unwrap(), 0);
834
835 let content = b"abcdef";
837 assert!(vmo.write(content, 0).is_ok());
838 assert_eq!(vmo.get_stream_size().unwrap(), 0);
839
840 let mut buf = vec![1; 6];
842 vmo.set_stream_size(6).unwrap();
843 assert!(vmo.read(&mut buf, 0).is_ok());
844 assert_eq!(buf, vec![0; 6]);
846 }
847}