1use crate::{
8 AsHandleRef, Bti, Handle, HandleBased, HandleRef, Koid, Name, ObjectQuery, Property,
9 PropertyQuery, Resource, Rights, Status, Topic, object_get_info_single, object_get_property,
10 object_set_property, ok, sys,
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<T: FromBytes>(
138 &self,
139 buffer: *mut T,
140 buffer_length: usize,
141 offset: u64,
142 ) -> Result<(), Status> {
143 let status = unsafe {
144 sys::zx_vmo_read(
145 self.raw_handle(),
146 buffer.cast::<u8>(),
147 offset,
148 buffer_length * std::mem::size_of::<T>(),
149 )
150 };
151 ok(status)
152 }
153
154 pub fn read_uninit<'a, T: Copy + FromBytes>(
160 &self,
161 data: &'a mut [MaybeUninit<T>],
162 offset: u64,
163 ) -> Result<&'a mut [T], Status> {
164 unsafe {
167 self.read_raw(
168 data.as_mut_ptr().cast::<T>(),
170 data.len(),
171 offset,
172 )?
173 }
174 Ok(
176 unsafe { std::slice::from_raw_parts_mut(data.as_mut_ptr().cast::<T>(), data.len()) },
182 )
183 }
184
185 pub fn read_to_vec<T: Copy + FromBytes>(
187 &self,
188 offset: u64,
189 length: u64,
190 ) -> Result<Vec<T>, Status> {
191 let len = length.try_into().map_err(|_| Status::INVALID_ARGS)?;
192 let mut buffer = Vec::with_capacity(len);
193 self.read_uninit(buffer.spare_capacity_mut(), offset)?;
194 unsafe {
195 buffer.set_len(len);
198 }
199 Ok(buffer)
200 }
201
202 pub fn read_to_array<T: Copy + FromBytes, const N: usize>(
204 &self,
205 offset: u64,
206 ) -> Result<[T; N], Status> {
207 let array: MaybeUninit<[MaybeUninit<T>; N]> = MaybeUninit::uninit();
209 let mut array = unsafe { array.assume_init() };
213
214 let buffer = unsafe {
220 std::slice::from_raw_parts_mut(
221 array.as_mut_ptr().cast::<MaybeUninit<u8>>(),
222 N * std::mem::size_of::<T>(),
223 )
224 };
225
226 self.read_uninit(buffer, offset)?;
227 let buffer = array.map(|a| unsafe { a.assume_init() });
232 Ok(buffer)
233 }
234
235 pub fn read_to_object<T: Copy + FromBytes>(&self, offset: u64) -> Result<T, Status> {
237 let mut object = MaybeUninit::<T>::uninit();
238 let buffer = unsafe {
244 std::slice::from_raw_parts_mut(
245 object.as_mut_ptr().cast::<MaybeUninit<u8>>(),
246 std::mem::size_of::<T>(),
247 )
248 };
249 self.read_uninit(buffer, offset)?;
250
251 let object = unsafe { object.assume_init() };
254 Ok(object)
255 }
256
257 pub fn write(&self, data: &[u8], offset: u64) -> Result<(), Status> {
261 unsafe {
262 let status = sys::zx_vmo_write(self.raw_handle(), data.as_ptr(), offset, data.len());
263 ok(status)
264 }
265 }
266
267 pub fn transfer_data(
269 &self,
270 options: TransferDataOptions,
271 offset: u64,
272 length: u64,
273 src_vmo: &Vmo,
274 src_offset: u64,
275 ) -> Result<(), Status> {
276 let status = unsafe {
277 sys::zx_vmo_transfer_data(
278 self.raw_handle(),
279 options.bits(),
280 offset,
281 length,
282 src_vmo.raw_handle(),
283 src_offset,
284 )
285 };
286 ok(status)
287 }
288
289 pub fn get_size(&self) -> Result<u64, Status> {
293 let mut size = 0;
294 let status = unsafe { sys::zx_vmo_get_size(self.raw_handle(), &mut size) };
295 ok(status).map(|()| size)
296 }
297
298 pub fn set_size(&self, size: u64) -> Result<(), Status> {
302 let status = unsafe { sys::zx_vmo_set_size(self.raw_handle(), size) };
303 ok(status)
304 }
305
306 pub fn get_stream_size(&self) -> Result<u64, Status> {
310 let mut size = 0;
311 let status = unsafe { sys::zx_vmo_get_stream_size(self.raw_handle(), &mut size) };
312 ok(status).map(|()| size)
313 }
314
315 pub fn set_stream_size(&self, size: u64) -> Result<(), Status> {
319 let status = unsafe { sys::zx_vmo_set_stream_size(self.raw_handle(), size) };
320 ok(status)
321 }
322
323 pub fn set_cache_policy(&self, cache_policy: CachePolicy) -> Result<(), Status> {
327 let status =
328 unsafe { sys::zx_vmo_set_cache_policy(self.raw_handle(), cache_policy as u32) };
329 ok(status)
330 }
331
332 pub fn op_range(&self, op: VmoOp, offset: u64, size: u64) -> Result<(), Status> {
338 let status = unsafe {
339 sys::zx_vmo_op_range(self.raw_handle(), op.into_raw(), offset, size, ptr::null_mut(), 0)
340 };
341 ok(status)
342 }
343
344 pub fn info(&self) -> Result<VmoInfo, Status> {
347 Ok(VmoInfo::from(object_get_info_single::<VmoInfoQuery>(self.as_handle_ref())?))
348 }
349
350 pub fn create_child(
356 &self,
357 opts: VmoChildOptions,
358 offset: u64,
359 size: u64,
360 ) -> Result<Vmo, Status> {
361 let mut out = 0;
362 let status = unsafe {
363 sys::zx_vmo_create_child(self.raw_handle(), opts.bits(), offset, size, &mut out)
364 };
365 ok(status)?;
366 unsafe { Ok(Vmo::from(Handle::from_raw(out))) }
367 }
368
369 pub fn replace_as_executable(self, vmex: &Resource) -> Result<Vmo, Status> {
375 let mut out = 0;
376 let status = unsafe {
377 sys::zx_vmo_replace_as_executable(self.raw_handle(), vmex.raw_handle(), &mut out)
378 };
379 std::mem::forget(self);
383 ok(status)?;
384 unsafe { Ok(Vmo::from(Handle::from_raw(out))) }
385 }
386}
387
388bitflags! {
389 #[repr(transparent)]
391 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
392 pub struct VmoOptions: u32 {
393 const RESIZABLE = sys::ZX_VMO_RESIZABLE;
394 const TRAP_DIRTY = sys::ZX_VMO_TRAP_DIRTY;
395 const UNBOUNDED = sys::ZX_VMO_UNBOUNDED;
396 }
397}
398
399#[repr(transparent)]
401#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, FromBytes, Immutable)]
402pub struct VmoInfoFlags(u32);
403
404bitflags! {
405 impl VmoInfoFlags : u32 {
406 const PAGED = sys::ZX_INFO_VMO_TYPE_PAGED;
407 const RESIZABLE = sys::ZX_INFO_VMO_RESIZABLE;
408 const IS_COW_CLONE = sys::ZX_INFO_VMO_IS_COW_CLONE;
409 const VIA_HANDLE = sys::ZX_INFO_VMO_VIA_HANDLE;
410 const VIA_MAPPING = sys::ZX_INFO_VMO_VIA_MAPPING;
411 const PAGER_BACKED = sys::ZX_INFO_VMO_PAGER_BACKED;
412 const CONTIGUOUS = sys::ZX_INFO_VMO_CONTIGUOUS;
413 const DISCARDABLE = sys::ZX_INFO_VMO_DISCARDABLE;
414 const IMMUTABLE = sys::ZX_INFO_VMO_IMMUTABLE;
415 const VIA_IOB_HANDLE = sys::ZX_INFO_VMO_VIA_IOB_HANDLE;
416 }
417}
418
419impl std::fmt::Debug for VmoInfoFlags {
420 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
421 bitflags::parser::to_writer(self, f)
422 }
423}
424
425bitflags! {
426 #[repr(transparent)]
428 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
429 pub struct VmoChildOptions: u32 {
430 const SNAPSHOT = sys::ZX_VMO_CHILD_SNAPSHOT;
431 const SNAPSHOT_AT_LEAST_ON_WRITE = sys::ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE;
432 const RESIZABLE = sys::ZX_VMO_CHILD_RESIZABLE;
433 const SLICE = sys::ZX_VMO_CHILD_SLICE;
434 const NO_WRITE = sys::ZX_VMO_CHILD_NO_WRITE;
435 const REFERENCE = sys::ZX_VMO_CHILD_REFERENCE;
436 const SNAPSHOT_MODIFIED = sys::ZX_VMO_CHILD_SNAPSHOT_MODIFIED;
437 }
438}
439
440bitflags! {
441 #[repr(transparent)]
443 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
444 pub struct TransferDataOptions: u32 {
445 }
446}
447
448#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
450#[repr(transparent)]
451pub struct VmoOp(u32);
452impl VmoOp {
453 pub fn from_raw(raw: u32) -> VmoOp {
454 VmoOp(raw)
455 }
456 pub fn into_raw(self) -> u32 {
457 self.0
458 }
459}
460
461#[derive(Debug, Copy, Clone, Eq, PartialEq)]
463#[repr(u32)]
464pub enum CachePolicy {
465 Cached = sys::ZX_CACHE_POLICY_CACHED,
466 UnCached = sys::ZX_CACHE_POLICY_UNCACHED,
467 UnCachedDevice = sys::ZX_CACHE_POLICY_UNCACHED_DEVICE,
468 WriteCombining = sys::ZX_CACHE_POLICY_WRITE_COMBINING,
469 Unknown = u32::MAX,
470}
471
472impl From<u32> for CachePolicy {
473 fn from(v: u32) -> Self {
474 match v {
475 sys::ZX_CACHE_POLICY_CACHED => CachePolicy::Cached,
476 sys::ZX_CACHE_POLICY_UNCACHED => CachePolicy::UnCached,
477 sys::ZX_CACHE_POLICY_UNCACHED_DEVICE => CachePolicy::UnCachedDevice,
478 sys::ZX_CACHE_POLICY_WRITE_COMBINING => CachePolicy::WriteCombining,
479 _ => CachePolicy::Unknown,
480 }
481 }
482}
483
484impl Into<u32> for CachePolicy {
485 fn into(self) -> u32 {
486 match self {
487 CachePolicy::Cached => sys::ZX_CACHE_POLICY_CACHED,
488 CachePolicy::UnCached => sys::ZX_CACHE_POLICY_UNCACHED,
489 CachePolicy::UnCachedDevice => sys::ZX_CACHE_POLICY_UNCACHED_DEVICE,
490 CachePolicy::WriteCombining => sys::ZX_CACHE_POLICY_WRITE_COMBINING,
491 CachePolicy::Unknown => u32::MAX,
492 }
493 }
494}
495
496assoc_values!(VmoOp, [
497 COMMIT = sys::ZX_VMO_OP_COMMIT;
498 DECOMMIT = sys::ZX_VMO_OP_DECOMMIT;
499 LOCK = sys::ZX_VMO_OP_LOCK;
500 UNLOCK = sys::ZX_VMO_OP_UNLOCK;
501 CACHE_SYNC = sys::ZX_VMO_OP_CACHE_SYNC;
502 CACHE_INVALIDATE = sys::ZX_VMO_OP_CACHE_INVALIDATE;
503 CACHE_CLEAN = sys::ZX_VMO_OP_CACHE_CLEAN;
504 CACHE_CLEAN_INVALIDATE = sys::ZX_VMO_OP_CACHE_CLEAN_INVALIDATE;
505 ZERO = sys::ZX_VMO_OP_ZERO;
506 TRY_LOCK = sys::ZX_VMO_OP_TRY_LOCK;
507 DONT_NEED = sys::ZX_VMO_OP_DONT_NEED;
508 ALWAYS_NEED = sys::ZX_VMO_OP_ALWAYS_NEED;
509 PREFETCH = sys::ZX_VMO_OP_PREFETCH;
510]);
511
512unsafe_handle_properties!(object: Vmo,
513 props: [
514 {query_ty: VMO_CONTENT_SIZE, tag: VmoContentSizeTag, prop_ty: u64, get:get_content_size, set: set_content_size},
515 ]
516);
517
518#[cfg(test)]
519mod tests {
520 use super::*;
521 use crate::{Iommu, IommuDescStub, ObjectType};
522 use fidl_fuchsia_kernel as fkernel;
523 use fuchsia_component::client::connect_channel_to_protocol;
524 use test_case::test_case;
525 use zerocopy::KnownLayout;
526
527 #[test]
528 fn vmo_create_contiguous_invalid_handle() {
529 let status = Vmo::create_contiguous(&Bti::from(Handle::invalid()), 4096, 0);
530 assert_eq!(status, Err(Status::BAD_HANDLE));
531 }
532
533 #[test]
534 fn vmo_create_contiguous() {
535 use zx::{Channel, HandleBased, MonotonicInstant};
536 let (client_end, server_end) = Channel::create();
537 connect_channel_to_protocol::<fkernel::IommuResourceMarker>(server_end).unwrap();
538 let service = fkernel::IommuResourceSynchronousProxy::new(client_end);
539 let resource =
540 service.get(MonotonicInstant::INFINITE).expect("couldn't get iommu resource");
541 let resource = unsafe { Resource::from(Handle::from_raw(resource.into_raw())) };
545 let iommu = Iommu::create_stub(&resource, IommuDescStub::default()).unwrap();
546 let bti = Bti::create(&iommu, 0).unwrap();
547
548 let vmo = Vmo::create_contiguous(&bti, 8192, 0).unwrap();
549 let info = vmo.as_handle_ref().basic_info().unwrap();
550 assert_eq!(info.object_type, ObjectType::VMO);
551
552 let vmo_info = vmo.info().unwrap();
553 assert!(vmo_info.flags.contains(VmoInfoFlags::CONTIGUOUS));
554 }
555
556 #[test]
557 fn vmo_get_size() {
558 let size = 16 * 1024 * 1024;
559 let vmo = Vmo::create(size).unwrap();
560 assert_eq!(size, vmo.get_size().unwrap());
561 }
562
563 #[test]
564 fn vmo_set_size() {
565 let start_size = 4096;
567 let vmo = Vmo::create_with_opts(VmoOptions::RESIZABLE, start_size).unwrap();
568 assert_eq!(start_size, vmo.get_size().unwrap());
569
570 let new_size = 8192;
572 assert!(vmo.set_size(new_size).is_ok());
573 assert_eq!(new_size, vmo.get_size().unwrap());
574 }
575
576 #[test]
577 fn vmo_get_info_default() {
578 let size = 4096;
579 let vmo = Vmo::create(size).unwrap();
580 let info = vmo.info().unwrap();
581 assert!(!info.flags.contains(VmoInfoFlags::PAGER_BACKED));
582 assert!(info.flags.contains(VmoInfoFlags::PAGED));
583 }
584
585 #[test]
586 fn vmo_get_child_info() {
587 let size = 4096;
588 let vmo = Vmo::create(size).unwrap();
589 let info = vmo.info().unwrap();
590 assert!(!info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
591
592 let child = vmo.create_child(VmoChildOptions::SNAPSHOT, 0, 512).unwrap();
593 let info = child.info().unwrap();
594 assert!(info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
595
596 let child = vmo.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, 512).unwrap();
597 let info = child.info().unwrap();
598 assert!(info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
599
600 let child = vmo.create_child(VmoChildOptions::SLICE, 0, 512).unwrap();
601 let info = child.info().unwrap();
602 assert!(!info.flags.contains(VmoInfoFlags::IS_COW_CLONE));
603 }
604
605 #[test]
606 fn vmo_set_size_fails_on_non_resizable() {
607 let size = 4096;
608 let vmo = Vmo::create(size).unwrap();
609 assert_eq!(size, vmo.get_size().unwrap());
610
611 let new_size = 8192;
612 assert_eq!(Err(Status::UNAVAILABLE), vmo.set_size(new_size));
613 assert_eq!(size, vmo.get_size().unwrap());
614 }
615
616 #[test_case(0)]
617 #[test_case(1)]
618 fn vmo_read_to_array(read_offset: usize) {
619 const ACTUAL_SIZE: usize = 5;
620 const ACTUAL: [u8; ACTUAL_SIZE] = [1, 2, 3, 4, 5];
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_array::<u8, ACTUAL_SIZE>(read_offset as u64).unwrap()[..read_len],
626 &ACTUAL[read_offset..]
627 );
628 }
629
630 #[test_case(0)]
631 #[test_case(1)]
632 fn vmo_read_to_vec(read_offset: usize) {
633 const ACTUAL_SIZE: usize = 4;
634 const ACTUAL: [u8; ACTUAL_SIZE] = [6, 7, 8, 9];
635 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
636 vmo.write(&ACTUAL, 0).unwrap();
637 let read_len = ACTUAL_SIZE - read_offset;
638 assert_eq!(
639 &vmo.read_to_vec::<u8>(read_offset as u64, read_len as u64).unwrap(),
640 &ACTUAL[read_offset..]
641 );
642 }
643
644 #[test_case(0)]
645 #[test_case(1)]
646 fn vmo_read_to_object(read_offset: usize) {
647 #[repr(C)]
648 #[derive(Copy, Clone, Debug, Eq, KnownLayout, FromBytes, PartialEq)]
649 struct Object {
650 a: u8,
651 b: u8,
652 }
653
654 const ACTUAL_SIZE: usize = std::mem::size_of::<Object>();
655 const ACTUAL: [u8; ACTUAL_SIZE + 1] = [10, 11, 12];
656 let vmo = Vmo::create(ACTUAL.len() as u64).unwrap();
657 vmo.write(&ACTUAL, 0).unwrap();
658 assert_eq!(
659 vmo.read_to_object::<Object>(read_offset as u64).unwrap(),
660 Object { a: ACTUAL[read_offset], b: ACTUAL[1 + read_offset] }
661 );
662 }
663
664 #[test]
665 fn vmo_read_write() {
666 let mut vec1 = vec![0; 16];
667 let vmo = Vmo::create(4096 as u64).unwrap();
668 assert!(vmo.write(b"abcdef", 0).is_ok());
669 assert!(vmo.read(&mut vec1, 0).is_ok());
670 assert_eq!(b"abcdef", &vec1[0..6]);
671 assert!(vmo.write(b"123", 2).is_ok());
672 assert!(vmo.read(&mut vec1, 0).is_ok());
673 assert_eq!(b"ab123f", &vec1[0..6]);
674
675 assert!(vmo.read(&mut vec1, 1).is_ok());
677 assert_eq!(b"b123f", &vec1[0..5]);
678
679 assert_eq!(&vmo.read_to_vec::<u8>(0, 6).expect("read_to_vec failed"), b"ab123f");
680 }
681
682 #[test]
683 fn vmo_child_snapshot() {
684 let size = 4096 * 2;
685 let vmo = Vmo::create(size).unwrap();
686
687 vmo.write(&[1; 4096], 0).unwrap();
688 vmo.write(&[2; 4096], 4096).unwrap();
689
690 let child = vmo.create_child(VmoChildOptions::SNAPSHOT, 0, size).unwrap();
691
692 child.write(&[3; 4096], 0).unwrap();
693
694 vmo.write(&[4; 4096], 0).unwrap();
695 vmo.write(&[5; 4096], 4096).unwrap();
696
697 let mut page = [0; 4096];
698
699 child.read(&mut page[..], 0).unwrap();
701 assert_eq!(&page[..], &[3; 4096][..]);
702 child.read(&mut page[..], 4096).unwrap();
703 assert_eq!(&page[..], &[2; 4096][..]);
704 }
705
706 #[test]
707 fn vmo_child_snapshot_at_least_on_write() {
708 let size = 4096 * 2;
709 let vmo = Vmo::create(size).unwrap();
710
711 vmo.write(&[1; 4096], 0).unwrap();
712 vmo.write(&[2; 4096], 4096).unwrap();
713
714 let child = vmo.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, size).unwrap();
715
716 child.write(&[3; 4096], 0).unwrap();
717
718 vmo.write(&[4; 4096], 0).unwrap();
719 vmo.write(&[5; 4096], 4096).unwrap();
720
721 let mut page = [0; 4096];
722
723 child.read(&mut page[..], 0).unwrap();
726 assert_eq!(&page[..], &[3; 4096][..]);
727 child.read(&mut page[..], 4096).unwrap();
728 assert!(
729 &page[..] == &[2; 4096][..] || &page[..] == &[5; 4096][..],
730 "expected page of 2 or 5, got {:?}",
731 &page[..]
732 );
733 }
734
735 #[test]
736 fn vmo_child_no_write() {
737 let size = 4096;
738 let vmo = Vmo::create(size).unwrap();
739 vmo.write(&[1; 4096], 0).unwrap();
740
741 let child =
742 vmo.create_child(VmoChildOptions::SLICE | VmoChildOptions::NO_WRITE, 0, size).unwrap();
743 assert_eq!(child.write(&[3; 4096], 0), Err(Status::ACCESS_DENIED));
744 }
745
746 #[test]
747 fn vmo_op_range_unsupported() {
748 let vmo = Vmo::create(12).unwrap();
749 assert_eq!(vmo.op_range(VmoOp::LOCK, 0, 1), Err(Status::NOT_SUPPORTED));
750 assert_eq!(vmo.op_range(VmoOp::UNLOCK, 0, 1), Err(Status::NOT_SUPPORTED));
751 }
752
753 #[test]
754 fn vmo_cache() {
755 let vmo = Vmo::create(12).unwrap();
756
757 assert_eq!(vmo.op_range(VmoOp::CACHE_SYNC, 0, 12), Ok(()));
759 assert_eq!(vmo.op_range(VmoOp::CACHE_INVALIDATE, 0, 12), Ok(()));
760 assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN, 0, 12), Ok(()));
761 assert_eq!(vmo.op_range(VmoOp::CACHE_CLEAN_INVALIDATE, 0, 12), Ok(()));
762 }
763
764 #[test]
765 fn vmo_create_child() {
766 let original = Vmo::create(16).unwrap();
767 assert!(original.write(b"one", 0).is_ok());
768
769 let clone =
771 original.create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, 16).unwrap();
772 let mut read_buffer = vec![0; 16];
773 assert!(clone.read(&mut read_buffer, 0).is_ok());
774 assert_eq!(&read_buffer[0..3], b"one");
775
776 assert!(original.write(b"two", 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..3], b"one");
782
783 assert!(clone.write(b"three", 0).is_ok());
785 assert!(original.read(&mut read_buffer, 0).is_ok());
786 assert_eq!(&read_buffer[0..3], b"two");
787 assert!(clone.read(&mut read_buffer, 0).is_ok());
788 assert_eq!(&read_buffer[0..5], b"three");
789 }
790
791 #[test]
792 fn vmo_replace_as_executeable() {
793 use zx::{Channel, HandleBased, MonotonicInstant};
794
795 let vmo = Vmo::create(16).unwrap();
796
797 let info = vmo.as_handle_ref().basic_info().unwrap();
798 assert!(!info.rights.contains(Rights::EXECUTE));
799
800 let (client_end, server_end) = Channel::create();
801 connect_channel_to_protocol::<fkernel::VmexResourceMarker>(server_end).unwrap();
802 let service = fkernel::VmexResourceSynchronousProxy::new(client_end);
803 let resource = service.get(MonotonicInstant::INFINITE).expect("couldn't get vmex resource");
804 let resource = unsafe { crate::Resource::from(Handle::from_raw(resource.into_raw())) };
805
806 let exec_vmo = vmo.replace_as_executable(&resource).unwrap();
807 let info = exec_vmo.as_handle_ref().basic_info().unwrap();
808 assert!(info.rights.contains(Rights::EXECUTE));
809 }
810
811 #[test]
812 fn vmo_content_size() {
813 let start_size = 1024;
814 let vmo = Vmo::create_with_opts(VmoOptions::RESIZABLE, start_size).unwrap();
815 assert_eq!(vmo.get_content_size().unwrap(), start_size);
816 vmo.set_content_size(&0).unwrap();
817 assert_eq!(vmo.get_content_size().unwrap(), 0);
818
819 let content = b"abcdef";
821 assert!(vmo.write(content, 0).is_ok());
822 assert_eq!(vmo.get_content_size().unwrap(), 0);
823 }
824
825 #[test]
826 fn vmo_zero() {
827 let vmo = Vmo::create(16).unwrap();
828 let content = b"0123456789abcdef";
829 assert!(vmo.write(content, 0).is_ok());
830 let mut buf = vec![0u8; 16];
831 assert!(vmo.read(&mut buf[..], 0).is_ok());
832 assert_eq!(&buf[..], content);
833
834 assert!(vmo.op_range(VmoOp::ZERO, 0, 16).is_ok());
835 assert!(vmo.read(&mut buf[..], 0).is_ok());
836 assert_eq!(&buf[..], &[0u8; 16]);
837 }
838
839 #[test]
840 fn vmo_stream_size() {
841 let start_size = 1300;
842 let vmo = Vmo::create_with_opts(VmoOptions::UNBOUNDED, start_size).unwrap();
843 assert_eq!(vmo.get_stream_size().unwrap(), start_size);
844 vmo.set_stream_size(0).unwrap();
845 assert_eq!(vmo.get_stream_size().unwrap(), 0);
846
847 let content = b"abcdef";
849 assert!(vmo.write(content, 0).is_ok());
850 assert_eq!(vmo.get_stream_size().unwrap(), 0);
851
852 let mut buf = vec![1; 6];
854 vmo.set_stream_size(6).unwrap();
855 assert!(vmo.read(&mut buf, 0).is_ok());
856 assert_eq!(buf, vec![0; 6]);
858 }
859}