]> git.proxmox.com Git - rustc.git/blob - src/vendor/fuchsia-zircon/src/vmo.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / vendor / fuchsia-zircon / src / vmo.rs
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.
4
5 //! Type-safe bindings for Zircon vmo objects.
6
7 use {AsHandleRef, Cookied, HandleBased, Handle, HandleRef, Status};
8 use {sys, into_result};
9 use std::{mem, ptr};
10
11 /// An object representing a Zircon
12 /// [virtual memory object](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/vm_object.md).
13 ///
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 {}
19
20 impl Vmo {
21 /// Create a virtual memory object.
22 ///
23 /// Wraps the
24 /// `zx_vmo_create`
25 /// syscall. See the
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> {
29 let mut handle = 0;
30 let status = unsafe { sys::zx_vmo_create(size, options as u32, &mut handle) };
31 into_result(status, ||
32 Vmo::from(Handle(handle)))
33 }
34
35 /// Read from a virtual memory object.
36 ///
37 /// Wraps the `zx_vmo_read` syscall.
38 pub fn read(&self, data: &mut [u8], offset: u64) -> Result<usize, Status> {
39 unsafe {
40 let mut actual = 0;
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)
44 }
45 }
46
47 /// Write to a virtual memory object.
48 ///
49 /// Wraps the `zx_vmo_write` syscall.
50 pub fn write(&self, data: &[u8], offset: u64) -> Result<usize, Status> {
51 unsafe {
52 let mut actual = 0;
53 let status = sys::zx_vmo_write(self.raw_handle(), data.as_ptr(),
54 offset, data.len(), &mut actual);
55 into_result(status, || actual)
56 }
57 }
58
59 /// Get the size of a virtual memory object.
60 ///
61 /// Wraps the `zx_vmo_get_size` syscall.
62 pub fn get_size(&self) -> Result<u64, Status> {
63 let mut size = 0;
64 let status = unsafe { sys::zx_vmo_get_size(self.raw_handle(), &mut size) };
65 into_result(status, || size)
66 }
67
68 /// Attempt to change the size of a virtual memory object.
69 ///
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, || ())
74 }
75
76 /// Perform an operation on a range of a virtual memory object.
77 ///
78 /// Wraps the
79 /// [zx_vmo_op_range](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_op_range.md)
80 /// syscall.
81 pub fn op_range(&self, op: VmoOp, offset: u64, size: u64) -> Result<(), Status> {
82 let status = unsafe {
83 sys::zx_vmo_op_range(self.raw_handle(), op as u32, offset, size, ptr::null_mut(), 0)
84 };
85 into_result(status, || ())
86 }
87
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`.
90 ///
91 /// Wraps the
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])
95 -> Result<(), Status>
96 {
97 let status = unsafe {
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>())
100 };
101 into_result(status, || ())
102 }
103
104 /// Create a new virtual memory object that clones a range of this one.
105 ///
106 /// Wraps the
107 /// [zx_vmo_clone](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/vmo_clone.md)
108 /// syscall.
109 pub fn clone(&self, options: VmoCloneOpts, offset: u64, size: u64) -> Result<Vmo, Status> {
110 let mut out = 0;
111 let status = unsafe {
112 sys::zx_vmo_clone(self.raw_handle(), options as u32, offset, size, &mut out)
113 };
114 into_result(status, || Vmo::from(Handle(out)))
115 }
116 }
117
118 /// Options for creating virtual memory objects. None supported yet.
119 #[repr(u32)]
120 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
121 pub enum VmoOpts {
122 /// Default options.
123 Default = 0,
124 }
125
126 impl Default for VmoOpts {
127 fn default() -> Self {
128 VmoOpts::Default
129 }
130 }
131
132 #[repr(u32)]
133 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
134 pub enum VmoOp {
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,
151 }
152
153 #[repr(u32)]
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,
158 }
159
160 impl Default for VmoCloneOpts {
161 fn default() -> Self {
162 VmoCloneOpts::CopyOnWrite
163 }
164 }
165
166 #[cfg(test)]
167 mod tests {
168 use super::*;
169
170 #[test]
171 fn vmo_get_size() {
172 let size = 16 * 1024 * 1024;
173 let vmo = Vmo::create(size, VmoOpts::Default).unwrap();
174 assert_eq!(size, vmo.get_size().unwrap());
175 }
176
177 #[test]
178 fn vmo_set_size() {
179 let start_size = 12;
180 let vmo = Vmo::create(start_size, VmoOpts::Default).unwrap();
181 assert_eq!(start_size, vmo.get_size().unwrap());
182
183 // Change the size and make sure the new size is reported
184 let new_size = 23;
185 assert!(vmo.set_size(new_size).is_ok());
186 assert_eq!(new_size, vmo.get_size().unwrap());
187 }
188
189 #[test]
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]);
201 }
202
203 #[test]
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));
208 }
209
210 #[test]
211 fn vmo_lookup() {
212 let vmo = Vmo::create(12, VmoOpts::Default).unwrap();
213 let mut buffer = vec![0; 2];
214
215 // Lookup will fail as it is not committed yet.
216 assert_eq!(vmo.lookup(0, 12, &mut buffer), Err(Status::ErrNoMemory));
217
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);
223
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));
227 }
228
229 #[test]
230 fn vmo_cache() {
231 let vmo = Vmo::create(12, VmoOpts::Default).unwrap();
232
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(()));
238 }
239
240 #[test]
241 fn vmo_clone() {
242 let original = Vmo::create(12, VmoOpts::Default).unwrap();
243 assert_eq!(original.write(b"one", 0), Ok(3));
244
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");
250
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");
257
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");
264
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");
272 }
273 }