Skip to main content

ostd/mm/frame/
frame_ref.rs

1// SPDX-License-Identifier: MPL-2.0
2use core::{marker::PhantomData, ops::Deref, ptr::NonNull};
3
4use vstd::prelude::*;
5use vstd::simple_pptr::PPtr;
6use vstd_extra::cast_ptr::Repr;
7use vstd_extra::drop_tracking::*;
8use vstd_extra::prelude::*;
9
10use crate::mm::frame::MetaPerm;
11use crate::mm::frame::meta::mapping::{frame_to_meta, meta_to_frame};
12
13use crate::specs::mm::frame::{
14    mapping::frame_to_index, meta_owners::MetaSlotStorage, meta_region_owners::MetaRegionOwners,
15};
16
17use super::{
18    Frame,
19    meta::{AnyFrameMeta, MetaSlot},
20};
21use crate::mm::Paddr;
22
23verus! {
24
25/// A struct that can work as `&'a Frame<M>`.
26// FIXME: field visibility
27pub struct FrameRef<'a, M: AnyFrameMeta + ?Sized + Repr<MetaSlotStorage>> {
28    pub inner: ManuallyDrop<Frame<M>>,
29    pub _marker: PhantomData<&'a Frame<M>>,
30}
31
32#[verus_verify]
33impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> FrameRef<'_, M> {
34    /// Borrows the [`Frame`] at the physical address as a [`FrameRef`].
35    ///
36    /// Under the borrow-protocol redesign, `from_raw` mints one
37    /// `frame_obligations` entry at the slot index and `MD::new`
38    /// immediately consumes it — net-zero on the ledger across this
39    /// borrow. The slot's `ref_count` is unchanged (the existing live
40    /// reference covers the borrow's lifetime via the `'a` lifetime).
41    ///
42    /// # Safety
43    /// By providing a borrowed `MetaPerm` of the appropriate type, the
44    /// caller ensures that the frame has that type and that the
45    /// `FrameRef` will be useless if it outlives the frame.
46    #[verus_spec(r =>
47        with
48            Tracked(regions): Tracked<&mut MetaRegionOwners>,
49        requires
50            Frame::<M>::from_raw_requires_safety(*old(regions), raw),
51        ensures
52            final(regions).inv(),
53            r.inner.0.ptr.addr() == frame_to_meta(raw),
54            final(regions).slot_owners == old(regions).slot_owners,
55            final(regions).slots == old(regions).slots,
56            final(regions).frame_obligations == old(regions).frame_obligations,
57    )]
58    pub(in crate::mm) unsafe fn borrow_paddr(raw: Paddr) -> Self {
59        proof {
60            old(regions).inv_implies_correct_addr(raw);
61        }
62
63        proof_decl! {
64            let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<usize>;
65        }
66        // `from_raw` mints one `frame_obligations` entry at the slot and
67        // hands back the token; the token is dropped affinely (the ledger
68        // entry is what matters). `MD::new` then consumes that entry. Net
69        // effect on the ledger: zero.
70        let frame = unsafe {
71            #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
72            Frame::from_raw(raw)
73        };
74
75        let inner = ManuallyDrop::new(frame, Tracked(regions));
76
77        Self { inner, _marker: PhantomData }
78    }
79}
80
81impl<M: AnyFrameMeta + ?Sized + Repr<MetaSlotStorage>> Deref for FrameRef<'_, M> {
82    type Target = Frame<M>;
83
84    #[verus_spec(ensures returns &self.inner.0)]
85    fn deref(&self) -> &Self::Target {
86        &self.inner
87    }
88}
89
90// TODO: I moved this here to avoid having to pull the rest of `sync` into the verification.
91// Once it is pulled in, we should delete this one.
92/// A trait that abstracts non-null pointers.
93///
94/// All common smart pointer types such as `Box<T>`,  `Arc<T>`, and `Weak<T>`
95/// implement this trait as they can be converted to and from the raw pointer
96/// type of `*const T`.
97///
98/// # Safety
99///
100/// This trait must be implemented correctly (according to the doc comments for
101/// each method). Types like [`Rcu`] rely on this assumption to safely use the
102/// raw pointers.
103///
104/// [`Rcu`]: super::Rcu
105pub unsafe trait NonNullPtr: 'static + Sized + TrackDrop<State = MetaRegionOwners> {
106    /// The target type that this pointer refers to.
107    // TODO: Support `Target: ?Sized`.
108    type Target;
109
110    /// A type that behaves just like a shared reference to the `NonNullPtr`.
111    type Ref<'a>;
112
113    /// The power of two of the pointer alignment.
114    fn ALIGN_BITS() -> u32;
115
116    /// Converts to a raw pointer.
117    ///
118    /// Each call to `into_raw` must be paired with a call to `from_raw`
119    /// in order to avoid memory leakage.
120    ///
121    /// The lower [`Self::ALIGN_BITS`] of the raw pointer is guaranteed to
122    /// be zero. In other words, the pointer is guaranteed to be aligned to
123    /// `1 << Self::ALIGN_BITS`.
124    fn into_raw(self, Tracked(regions): Tracked<&mut MetaRegionOwners>) -> PPtr<Self::Target>
125        requires
126            self.constructor_requires(*old(regions)),
127    ;
128
129    /// Converts back from a raw pointer.
130    ///
131    /// # Safety
132    ///
133    /// 1. The raw pointer must have been previously returned by a call to
134    ///    `into_raw`.
135    /// 2. The raw pointer must not be used after calling `from_raw`.
136    ///
137    /// Note that the second point is a hard requirement: Even if the
138    /// resulting value has not (yet) been dropped, the pointer cannot be
139    /// used because it may break Rust aliasing rules (e.g., `Box<T>`
140    /// requires the pointer to be unique and thus _never_ aliased).
141    unsafe fn from_raw(ptr: PPtr<Self::Target>) -> Self;
142
143    /// Obtains a shared reference to the original pointer.
144    ///
145    /// # Safety
146    ///
147    /// The original pointer must outlive the lifetime parameter `'a`, and during `'a`
148    /// no mutable references to the pointer will exist.
149    unsafe fn raw_as_ref<'a>(
150        raw: PPtr<Self::Target>,
151        Tracked(regions): Tracked<&mut MetaRegionOwners>,
152    ) -> Self::Ref<'a>
153        requires
154            old(regions).inv(),
155            old(regions).slot_owners.contains_key(frame_to_index(meta_to_frame(raw.addr()))),
156    ;
157
158    /// Converts a shared reference to a raw pointer.
159    fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> PPtr<Self::Target>;
160}
161
162pub assume_specification[ usize::trailing_zeros ](_0: usize) -> u32
163;
164
165// SAFETY: `Frame` is essentially a `*const MetaSlot` that could be used as a non-null
166// `*const` pointer.
167unsafe impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + 'static> NonNullPtr for Frame<M> {
168    type Target = PhantomData<Self>;
169
170    type Ref<'a> = FrameRef<'a, M>;
171
172    fn ALIGN_BITS() -> u32 {
173        core::mem::align_of::<MetaSlot>().trailing_zeros()
174    }
175
176    fn into_raw(self, Tracked(regions): Tracked<&mut MetaRegionOwners>) -> PPtr<Self::Target> {
177        let ptr = self.ptr;
178        proof {
179            // Mint the obligation that `MD::new` will immediately
180            // consume — net-zero on the ledger; the Frame value is
181            // forgotten inside the wrapper, and `ref_count` (set by the
182            // original producer) stays elevated to balance the eventual
183            // `from_raw + drop`.
184            let tracked _ = regions.tracked_mint_frame_obligation(self.index());
185        }
186        let _ = ManuallyDrop::new(self, Tracked(regions));
187        PPtr::<Self::Target>::from_addr(ptr.addr())
188    }
189
190    unsafe fn from_raw(raw: PPtr<Self::Target>) -> Self {
191        Self { ptr: PPtr::<MetaSlot>::from_addr(raw.addr()), _marker: PhantomData }
192    }
193
194    unsafe fn raw_as_ref<'a>(
195        raw: PPtr<Self::Target>,
196        Tracked(regions): Tracked<&mut MetaRegionOwners>,
197    ) -> Self::Ref<'a> {
198        let frame = Frame::<M> {
199            ptr: PPtr::<MetaSlot>::from_addr(raw.addr()),
200            _marker: PhantomData,
201        };
202        proof {
203            let tracked _ = regions.tracked_mint_frame_obligation(frame.index());
204        }
205        let dropped = ManuallyDrop::<Frame<M>>::new(frame, Tracked(regions));
206        Self::Ref { inner: dropped, _marker: PhantomData }
207    }
208
209    fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> PPtr<Self::Target> {
210        PPtr::from_addr(ptr_ref.inner.ptr.addr())
211    }
212}
213
214} // verus!