1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 //! Type-safe bindings for Zircon vmo objects.
7 use {AsHandleRef, Cookied, HandleBased, Handle, HandleRef, Status}
;
8 use {sys, into_result}
;
11 /// An object representing a Zircon
12 /// [virtual memory object](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/vm_object.md).
14 /// As essentially a subtype of `Handle`, it can be freely interconverted.
15 #[derive(Debug, Eq, PartialEq)]
16 pub struct Vmo(Handle
);
17 impl_handle_based
!(Vmo
);
18 impl Cookied
for Vmo {}
21 /// Create a virtual memory object.
26 /// [Shared Memory: Virtual Memory Objects (VMOs)](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Shared-Memory_Virtual-Memory-Objects-VMOs)
27 /// for more information.
28 pub fn create(size
: u64, options
: VmoOpts
) -> Result
<Vmo
, Status
> {
30 let status
= unsafe { sys::zx_vmo_create(size, options as u32, &mut handle) }
;
31 into_result(status
, ||
32 Vmo
::from(Handle(handle
)))
35 /// Read from a virtual memory object.
37 /// Wraps the `zx_vmo_read` syscall.
38 pub fn read(&self, data
: &mut [u8], offset
: u64) -> Result
<usize, Status
> {
41 let status
= sys
::zx_vmo_read(self.raw_handle(), data
.as_mut_ptr(),
42 offset
, data
.len(), &mut actual
);
43 into_result(status
, || actual
)
47 /// Write to a virtual memory object.
49 /// Wraps the `zx_vmo_write` syscall.
50 pub fn write(&self, data
: &[u8], offset
: u64) -> Result
<usize, Status
> {
53 let status
= sys
::zx_vmo_write(self.raw_handle(), data
.as_ptr(),
54 offset
, data
.len(), &mut actual
);
55 into_result(status
, || actual
)
59 /// Get the size of a virtual memory object.
61 /// Wraps the `zx_vmo_get_size` syscall.
62 pub fn get_size(&self) -> Result
<u64, Status
> {
64 let status
= unsafe { sys::zx_vmo_get_size(self.raw_handle(), &mut size) }
;
65 into_result(status
, || size
)
68 /// Attempt to change the size of a virtual memory object.
70 /// Wraps the `zx_vmo_set_size` syscall.
71 pub fn set_size(&self, size
: u64) -> Result
<(), Status
> {
72 let status
= unsafe { sys::zx_vmo_set_size(self.raw_handle(), size) }
;
73 into_result(status
, || ())
76 /// Perform an operation on a range of a virtual memory object.
79 /// [zx_vmo_op_range](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_op_range.md)
81 pub fn op_range(&self, op
: VmoOp
, offset
: u64, size
: u64) -> Result
<(), Status
> {
83 sys
::zx_vmo_op_range(self.raw_handle(), op
as u32, offset
, size
, ptr
::null_mut(), 0)
85 into_result(status
, || ())
88 /// Look up a list of physical addresses corresponding to the pages held by the VMO from
89 /// `offset` to `offset`+`size`, and store them in `buffer`.
92 /// [zx_vmo_op_range](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_op_range.md)
93 /// syscall with ZX_VMO_OP_LOOKUP.
94 pub fn lookup(&self, offset
: u64, size
: u64, buffer
: &mut [sys
::zx_paddr_t
])
98 sys
::zx_vmo_op_range(self.raw_handle(), sys
::ZX_VMO_OP_LOOKUP
, offset
, size
,
99 buffer
.as_mut_ptr() as *mut u8, buffer
.len() * mem
::size_of
::<sys
::zx_paddr_t
>())
101 into_result(status
, || ())
104 /// Create a new virtual memory object that clones a range of this one.
107 /// [zx_vmo_clone](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_clone.md)
109 pub fn clone(&self, options
: VmoCloneOpts
, offset
: u64, size
: u64) -> Result
<Vmo
, Status
> {
111 let status
= unsafe {
112 sys
::zx_vmo_clone(self.raw_handle(), options
as u32, offset
, size
, &mut out
)
114 into_result(status
, || Vmo
::from(Handle(out
)))
118 /// Options for creating virtual memory objects. None supported yet.
120 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
126 impl Default
for VmoOpts
{
127 fn default() -> Self {
133 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
135 /// Commit `size` bytes worth of pages starting at byte `offset` for the VMO.
136 Commit
= sys
::ZX_VMO_OP_COMMIT
,
137 /// Release a range of pages previously committed to the VMO from `offset` to `offset`+`size`.
138 Decommit
= sys
::ZX_VMO_OP_DECOMMIT
,
139 // Presently unsupported.
140 Lock
= sys
::ZX_VMO_OP_LOCK
,
141 // Presently unsupported.
142 Unlock
= sys
::ZX_VMO_OP_UNLOCK
,
143 /// Perform a cache sync operation.
144 CacheSync
= sys
::ZX_VMO_OP_CACHE_SYNC
,
145 /// Perform a cache invalidation operation.
146 CacheInvalidate
= sys
::ZX_VMO_OP_CACHE_INVALIDATE
,
147 /// Perform a cache clean operation.
148 CacheClean
= sys
::ZX_VMO_OP_CACHE_CLEAN
,
149 /// Perform cache clean and invalidation operations together.
150 CacheCleanInvalidate
= sys
::ZX_VMO_OP_CACHE_CLEAN_INVALIDATE
,
154 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
155 pub enum VmoCloneOpts
{
156 /// Create a copy-on-write clone.
157 CopyOnWrite
= sys
::ZX_VMO_CLONE_COPY_ON_WRITE
,
160 impl Default
for VmoCloneOpts
{
161 fn default() -> Self {
162 VmoCloneOpts
::CopyOnWrite
172 let size
= 16 * 1024 * 1024;
173 let vmo
= Vmo
::create(size
, VmoOpts
::Default
).unwrap();
174 assert_eq
!(size
, vmo
.get_size().unwrap());
180 let vmo
= Vmo
::create(start_size
, VmoOpts
::Default
).unwrap();
181 assert_eq
!(start_size
, vmo
.get_size().unwrap());
183 // Change the size and make sure the new size is reported
185 assert
!(vmo
.set_size(new_size
).is_ok());
186 assert_eq
!(new_size
, vmo
.get_size().unwrap());
190 fn vmo_read_write() {
191 let mut vec1
= vec
![0; 16];
192 let vmo
= Vmo
::create(vec1
.len() as u64, VmoOpts
::Default
).unwrap();
193 assert_eq
!(vmo
.write(b
"abcdef", 0), Ok(6));
194 assert_eq
!(16, vmo
.read(&mut vec1
, 0).unwrap());
195 assert_eq
!(b
"abcdef", &vec1
[0..6]);
196 assert_eq
!(vmo
.write(b
"123", 2), Ok(3));
197 assert_eq
!(16, vmo
.read(&mut vec1
, 0).unwrap());
198 assert_eq
!(b
"ab123f", &vec1
[0..6]);
199 assert_eq
!(15, vmo
.read(&mut vec1
, 1).unwrap());
200 assert_eq
!(b
"b123f", &vec1
[0..5]);
204 fn vmo_op_range_unsupported() {
205 let vmo
= Vmo
::create(12, VmoOpts
::Default
).unwrap();
206 assert_eq
!(vmo
.op_range(VmoOp
::Lock
, 0, 1), Err(Status
::ErrNotSupported
));
207 assert_eq
!(vmo
.op_range(VmoOp
::Unlock
, 0, 1), Err(Status
::ErrNotSupported
));
212 let vmo
= Vmo
::create(12, VmoOpts
::Default
).unwrap();
213 let mut buffer
= vec
![0; 2];
215 // Lookup will fail as it is not committed yet.
216 assert_eq
!(vmo
.lookup(0, 12, &mut buffer
), Err(Status
::ErrNoMemory
));
218 // Commit and try again.
219 assert_eq
!(vmo
.op_range(VmoOp
::Commit
, 0, 12), Ok(()));
220 assert_eq
!(vmo
.lookup(0, 12, &mut buffer
), Ok(()));
221 assert_ne
!(buffer
[0], 0);
222 assert_eq
!(buffer
[1], 0);
224 // If we decommit then lookup should go back to failing.
225 assert_eq
!(vmo
.op_range(VmoOp
::Decommit
, 0, 12), Ok(()));
226 assert_eq
!(vmo
.lookup(0, 12, &mut buffer
), Err(Status
::ErrNoMemory
));
231 let vmo
= Vmo
::create(12, VmoOpts
::Default
).unwrap();
233 // Cache operations should all succeed.
234 assert_eq
!(vmo
.op_range(VmoOp
::CacheSync
, 0, 12), Ok(()));
235 assert_eq
!(vmo
.op_range(VmoOp
::CacheInvalidate
, 0, 12), Ok(()));
236 assert_eq
!(vmo
.op_range(VmoOp
::CacheClean
, 0, 12), Ok(()));
237 assert_eq
!(vmo
.op_range(VmoOp
::CacheCleanInvalidate
, 0, 12), Ok(()));
242 let original
= Vmo
::create(12, VmoOpts
::Default
).unwrap();
243 assert_eq
!(original
.write(b
"one", 0), Ok(3));
245 // Clone the VMO, and make sure it contains what we expect.
246 let clone
= original
.clone(VmoCloneOpts
::CopyOnWrite
, 0, 10).unwrap();
247 let mut read_buffer
= vec
![0; 16];
248 assert_eq
!(clone
.read(&mut read_buffer
, 0), Ok(10));
249 assert_eq
!(&read_buffer
[0..3], b
"one");
251 // Writing to the original will affect the clone too, surprisingly.
252 assert_eq
!(original
.write(b
"two", 0), Ok(3));
253 assert_eq
!(original
.read(&mut read_buffer
, 0), Ok(12));
254 assert_eq
!(&read_buffer
[0..3], b
"two");
255 assert_eq
!(clone
.read(&mut read_buffer
, 0), Ok(10));
256 assert_eq
!(&read_buffer
[0..3], b
"two");
258 // However, writing to the clone will not affect the original
259 assert_eq
!(clone
.write(b
"three", 0), Ok(5));
260 assert_eq
!(original
.read(&mut read_buffer
, 0), Ok(12));
261 assert_eq
!(&read_buffer
[0..3], b
"two");
262 assert_eq
!(clone
.read(&mut read_buffer
, 0), Ok(10));
263 assert_eq
!(&read_buffer
[0..5], b
"three");
265 // And now that the copy-on-write has happened, writing to the original will not affect the
266 // clone. How bizarre.
267 assert_eq
!(original
.write(b
"four", 0), Ok(4));
268 assert_eq
!(original
.read(&mut read_buffer
, 0), Ok(12));
269 assert_eq
!(&read_buffer
[0..4], b
"four");
270 assert_eq
!(clone
.read(&mut read_buffer
, 0), Ok(10));
271 assert_eq
!(&read_buffer
[0..5], b
"three");