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}