ostd/mm/frame/
frame_ref.rs

1// SPDX-License-Identifier: MPL-2.0
2use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
3
4use vstd::prelude::*;
5
6use vstd_extra::external::manually_drop::*;
7use vstd_extra::ownership::*;
8use vstd_extra::undroppable::*;
9
10use crate::mm::frame::meta::mapping::{frame_to_index, frame_to_meta, meta_to_frame};
11use crate::mm::frame::meta::{AnyFrameMeta, MetaSlot};
12use crate::mm::frame::MetaPerm;
13use crate::mm::{Paddr, PagingLevel, Vaddr};
14use crate::specs::arch::mm::{MAX_PADDR, PAGE_SIZE};
15use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
16
17use super::Frame;
18
19use vstd::simple_pptr::PPtr;
20
21verus! {
22
23/// A struct that can work as `&'a Frame<M>`.
24pub struct FrameRef<'a, M: AnyFrameMeta> {
25    pub inner: NeverDrop<Frame<M>>,
26    pub _marker: PhantomData<&'a Frame<M>>,
27}
28
29impl<M: AnyFrameMeta> Deref for FrameRef<'_, M> {
30    type Target = Frame<M>;
31
32    #[verus_spec(ensures returns manually_drop_deref_spec(&self.inner.0))]
33    fn deref(&self) -> &Self::Target {
34        &self.inner
35    }
36}
37
38#[verus_verify]
39impl<M: AnyFrameMeta> FrameRef<'_, M> {
40    /// Borrows the [`Frame`] at the physical address as a [`FrameRef`].
41    ///
42    /// # Safety
43    ///
44    /// The caller must ensure that:
45    ///  - the frame outlives the created reference, so that the reference can
46    ///    be seen as borrowed from that frame.
47    ///  - the type of the [`FrameRef`] (`M`) matches the borrowed frame.
48    #[verus_spec(r =>
49        with
50            Tracked(regions): Tracked<&mut MetaRegionOwners>,
51            Tracked(perm): Tracked<&MetaPerm<M>>,
52        requires
53            raw % PAGE_SIZE() == 0,
54            raw < MAX_PADDR(),
55            !old(regions).slots.contains_key(frame_to_index(raw)),
56            old(regions).inv(),
57        ensures
58            regions.inv(),
59            manually_drop_deref_spec(&r.inner.0).ptr.addr() == frame_to_meta(raw),
60    )]
61    #[verifier::external_body]
62    pub fn borrow_paddr(raw: Paddr) -> Self {
63        #[verus_spec(with Tracked(regions), Tracked(perm))]
64        let frame = Frame::from_raw(raw);
65
66        Self {
67            inner: NeverDrop::new(frame, Tracked(regions)),
68            _marker: PhantomData,
69        }
70    }
71}
72
73// TODO: I moved this here to avoid having to pull the rest of `sync` into the verification.
74// Once it is pulled in, we should delete this one.
75/// A trait that abstracts non-null pointers.
76///
77/// All common smart pointer types such as `Box<T>`,  `Arc<T>`, and `Weak<T>`
78/// implement this trait as they can be converted to and from the raw pointer
79/// type of `*const T`.
80///
81/// # Safety
82///
83/// This trait must be implemented correctly (according to the doc comments for
84/// each method). Types like [`Rcu`] rely on this assumption to safely use the
85/// raw pointers.
86///
87/// [`Rcu`]: super::Rcu
88pub unsafe trait NonNullPtr: 'static + Sized {
89    /// The target type that this pointer refers to.
90    // TODO: Support `Target: ?Sized`.
91    type Target;
92
93    /// A type that behaves just like a shared reference to the `NonNullPtr`.
94    type Ref<'a>;
95
96    /// The power of two of the pointer alignment.
97    fn ALIGN_BITS() -> u32;
98
99    /// Converts to a raw pointer.
100    ///
101    /// Each call to `into_raw` must be paired with a call to `from_raw`
102    /// in order to avoid memory leakage.
103    ///
104    /// The lower [`Self::ALIGN_BITS`] of the raw pointer is guaranteed to
105    /// be zero. In other words, the pointer is guaranteed to be aligned to
106    /// `1 << Self::ALIGN_BITS`.
107    fn into_raw(self, Tracked(regions): Tracked<&mut MetaRegionOwners>) -> PPtr<Self::Target>;
108
109    /// Converts back from a raw pointer.
110    ///
111    /// # Safety
112    ///
113    /// 1. The raw pointer must have been previously returned by a call to
114    ///    `into_raw`.
115    /// 2. The raw pointer must not be used after calling `from_raw`.
116    ///
117    /// Note that the second point is a hard requirement: Even if the
118    /// resulting value has not (yet) been dropped, the pointer cannot be
119    /// used because it may break Rust aliasing rules (e.g., `Box<T>`
120    /// requires the pointer to be unique and thus _never_ aliased).
121    unsafe fn from_raw(ptr: PPtr<Self::Target>) -> Self;
122
123    /// Obtains a shared reference to the original pointer.
124    ///
125    /// # Safety
126    ///
127    /// The original pointer must outlive the lifetime parameter `'a`, and during `'a`
128    /// no mutable references to the pointer will exist.
129    unsafe fn raw_as_ref<'a>(
130        raw: PPtr<Self::Target>,
131        Tracked(regions): Tracked<&mut MetaRegionOwners>,
132    ) -> Self::Ref<'a>
133        requires
134            old(regions).inv(),
135            old(regions).slots.contains_key(frame_to_index(meta_to_frame(raw.addr()))),
136            !old(regions).dropped_slots.contains_key(frame_to_index(meta_to_frame(raw.addr()))),
137    ;
138
139    /// Converts a shared reference to a raw pointer.
140    fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> PPtr<Self::Target>;
141}
142
143pub assume_specification[ usize::trailing_zeros ](_0: usize) -> u32;
144
145// SAFETY: `Frame` is essentially a `*const MetaSlot` that could be used as a non-null
146// `*const` pointer.
147unsafe impl<M: AnyFrameMeta + ?Sized + 'static> NonNullPtr for Frame<M> {
148    type Target = PhantomData<Self>;
149
150    type Ref<'a> = FrameRef<'a, M>;
151
152    fn ALIGN_BITS() -> u32 {
153        core::mem::align_of::<MetaSlot>().trailing_zeros()
154    }
155
156    fn into_raw(self, Tracked(regions): Tracked<&mut MetaRegionOwners>) -> PPtr<Self::Target> {
157        let ptr = self.ptr;
158        assert(self.constructor_requires(*old(regions))) by { admit() };
159        let _ = NeverDrop::new(self, Tracked(regions));
160        PPtr::<Self::Target>::from_addr(ptr.addr())
161    }
162
163    unsafe fn from_raw(raw: PPtr<Self::Target>) -> Self {
164        Self { ptr: PPtr::<MetaSlot>::from_addr(raw.addr()), _marker: PhantomData }
165    }
166
167    unsafe fn raw_as_ref<'a>(
168        raw: PPtr<Self::Target>,
169        Tracked(regions): Tracked<&mut MetaRegionOwners>,
170    ) -> Self::Ref<'a> {
171        let dropped = NeverDrop::<Frame<M>>::new(
172            Frame { ptr: PPtr::<MetaSlot>::from_addr(raw.addr()), _marker: PhantomData },
173            Tracked(regions),
174        );
175        Self::Ref { inner: dropped, _marker: PhantomData }
176    }
177
178    fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> PPtr<Self::Target> {
179        PPtr::from_addr(ptr_ref.inner.ptr.addr())
180    }
181}
182
183} // verus!