zx/pmt.rs
1// Copyright 2022 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 pmt objects.
6
7use crate::{AsHandleRef, HandleBased, HandleRef, NullableHandle, Status, ok, sys};
8use std::mem;
9
10/// An object representing a Zircon Pinned Memory Token.
11/// See [PMT Documentation](https://fuchsia.dev/fuchsia-src/reference/kernel_objects/pinned_memory_token) for details.
12///
13/// As essentially a subtype of `NullableHandle`, it can be freely interconverted.
14#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
15#[repr(transparent)]
16pub struct Pmt(NullableHandle);
17impl_handle_based!(Pmt);
18
19impl Pmt {
20 /// Unpins a Pinned Memory Token.
21 /// Wraps the
22 /// [`zx_pmt_unpin`](https://fuchsia.dev/fuchsia-src/reference/syscalls/pmt_unpin) system call
23 /// to unpin a pmt.
24 ///
25 /// This function is marked `unsafe` because calling it at the wrong time (i.e., while hardware
26 /// is still accessing the pinned memory) can lead to memory corruption.
27 ///
28 /// # Safety
29 ///
30 /// The caller must ensure hardware is no longer accessing the memory that has been pinned or
31 /// else risk arbitrary memory corruption. It is strongly recommended you do not call this in
32 /// a drop method.
33 pub unsafe fn unpin(self) -> Result<(), Status> {
34 let status = unsafe { sys::zx_pmt_unpin(self.raw_handle()) };
35
36 // According to the syscall documentation, after calling `zx_pmt_unpin`,
37 // the pmt handle cannot be used anymore, not even for `zx_handle_close`.
38 // This is also true even if the function returns an error.
39 mem::forget(self);
40
41 ok(status)?;
42 Ok(())
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use crate::Vmo;
50
51 #[test]
52 fn pmt_unpin_invalid_handle() {
53 let pmt = Pmt::from(NullableHandle::invalid());
54 let status = unsafe { pmt.unpin() };
55 assert_eq!(status, Err(Status::BAD_HANDLE));
56 }
57
58 #[test]
59 fn pmt_unpin_wrong_handle() {
60 let vmo = Vmo::create(0).unwrap();
61 let pmt = unsafe { Pmt::from(NullableHandle::from_raw(vmo.into_raw())) };
62
63 let status = unsafe { pmt.unpin() };
64 assert_eq!(status, Err(Status::WRONG_TYPE));
65 }
66}