ostd/mm/frame/
unique.rs

1// SPDX-License-Identifier: MPL-2.0
2//! The unique frame pointer that is not shared with others.
3use vstd::atomic::PermissionU64;
4use vstd::prelude::*;
5use vstd::simple_pptr::{self, PPtr};
6
7use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
8
9use vstd_extra::cast_ptr::*;
10use vstd_extra::ownership::*;
11
12use super::meta::{AnyFrameMeta, GetFrameError, MetaSlot};
13
14use core::{marker::PhantomData, mem::ManuallyDrop, sync::atomic::Ordering};
15
16use super::meta::mapping::{
17    frame_to_index, frame_to_meta, max_meta_slots, meta_to_frame, META_SLOT_SIZE,
18};
19use super::meta::REF_COUNT_UNIQUE;
20use crate::mm::{Paddr, PagingLevel, MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
21use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
22use crate::specs::arch::paging_consts::PagingConsts;
23
24verus! {
25
26#[rustc_has_incoherent_inherent_impls]
27pub struct UniqueFrame<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> {
28    pub ptr: PPtr<MetaSlot>,
29    pub _marker: PhantomData<M>,
30}
31
32pub tracked struct UniqueFrameOwner<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> {
33    pub meta_own: M::Owner,
34    pub meta_perm: vstd_extra::cast_ptr::PointsTo<MetaSlot, M>,
35    pub ghost slot_index: usize,
36}
37
38pub ghost struct UniqueFrameModel<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> {
39    pub meta: <M::Owner as View>::V,
40}
41
42impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> Inv for UniqueFrameOwner<M> {
43    open spec fn inv(self) -> bool {
44        &&& self.meta_perm.is_init()
45        &&& self.meta_perm.wf()
46        &&& self.slot_index == frame_to_index(meta_to_frame(self.meta_perm.addr()))
47        &&& self.slot_index < max_meta_slots()
48        &&& (self.slot_index - FRAME_METADATA_RANGE().start) as usize % META_SLOT_SIZE() == 0
49        &&& self.meta_perm.addr() < FRAME_METADATA_RANGE().start + MAX_NR_PAGES() * META_SLOT_SIZE()
50    }
51}
52
53impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> Inv for UniqueFrameModel<M> {
54    open spec fn inv(self) -> bool {
55        true
56    }
57}
58
59impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> View for UniqueFrameOwner<M> {
60    type V = UniqueFrameModel<M>;
61
62    open spec fn view(&self) -> Self::V {
63        UniqueFrameModel { meta: self.meta_own@ }
64    }
65}
66
67impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> InvView for UniqueFrameOwner<M> {
68    proof fn view_preserves_inv(self) {
69    }
70}
71
72impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> OwnerOf for UniqueFrame<M> {
73    type Owner = UniqueFrameOwner<M>;
74
75    open spec fn wf(self, owner: Self::Owner) -> bool {
76        &&& self.ptr.addr() == owner.meta_perm.addr()
77    }
78}
79
80impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> ModelOf for UniqueFrame<M> {
81
82}
83
84impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> UniqueFrameOwner<M> {
85    pub open spec fn perm_inv(self, perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
86        &&& perm.is_init()
87        &&& perm.value().storage.addr() == self.meta_perm.addr()
88        &&& perm.value().storage.addr() == self.meta_perm.points_to.addr()
89    }
90
91    pub open spec fn global_inv(self, regions: MetaRegionOwners) -> bool {
92        &&& regions.slots.contains_key(self.slot_index) ==> self.perm_inv(
93            regions.slots[self.slot_index],
94        )
95        &&& regions.dropped_slots.contains_key(self.slot_index) ==> self.perm_inv(
96            regions.dropped_slots[self.slot_index],
97        )
98    }
99
100    pub proof fn from_raw_owner(
101        owner: M::Owner,
102        index: Ghost<usize>,
103        perm: vstd_extra::cast_ptr::PointsTo<MetaSlot, M>,
104    ) -> Self {
105        UniqueFrameOwner::<M> { meta_own: owner, meta_perm: perm, slot_index: index@ }
106    }
107}
108
109impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> UniqueFrame<M> {
110    /// Gets a [`UniqueFrame`] with a specific usage from a raw, unused page.
111    ///
112    /// The caller should provide the initial metadata of the page.
113    #[rustc_allow_incoherent_impl]
114    #[verus_spec(
115        with Tracked(regions): Tracked<&mut MetaRegionOwners>
116    )]
117    pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError>
118        requires
119            paddr < MAX_PADDR(),
120            paddr % PAGE_SIZE() == 0,
121            old(regions).slots.contains_key(frame_to_meta(paddr)),
122            old(regions).inv(),
123    {
124        #[verus_spec(with Tracked(regions))]
125        let from_unused = MetaSlot::get_from_unused(paddr, metadata, true);
126        Ok(Self { ptr: from_unused?, _marker: PhantomData })
127    }
128
129    /*
130    /// Repurposes the frame with a new metadata.
131    pub fn repurpose<M1: AnyFrameMeta>(self, metadata: M1) -> UniqueFrame<M1> {
132        // SAFETY: We are the sole owner and the metadata is initialized.
133        unsafe { self.slot().drop_meta_in_place() };
134        // SAFETY: We are the sole owner.
135        unsafe { self.slot().write_meta(metadata) };
136        // SAFETY: The metadata is initialized with type `M1`.
137        unsafe { core::mem::transmute(self) }
138    }*/
139    /// Gets the metadata of this page.
140    #[rustc_allow_incoherent_impl]
141    #[verifier::external_body]
142    pub fn meta(&self) -> (l: &M)
143        ensures
144    //            perm.mem_contents().value() == l,
145
146    {
147        unimplemented!()
148        // SAFETY: The type is tracked by the type system.
149        //        unsafe { &*self.slot().as_meta_ptr() }
150
151    }
152
153    /// Gets the mutable metadata of this page.
154    #[rustc_allow_incoherent_impl]
155    #[verus_spec(
156        with Tracked(perm) : Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>
157    )]
158    #[verifier::external_body]
159    pub fn meta_mut(&mut self) -> (res: ReprPtr<MetaSlot, M>)
160        requires
161    //            perm.is_init(),
162    //            perm.pptr() == old(self).ptr,
163    //            perm.value().wf(owner)
164
165        ensures
166            res.addr() == self.ptr.addr(),
167            res.ptr.addr() == self.ptr.addr(),
168            *self == *old(self),
169    {
170        // SAFETY: The type is tracked by the type system.
171        // And we have the exclusive access to the metadata.
172        //        let owner = regions.slot_owners.tracked_remove(frame_to_index(meta_to_frame(self.ptr.addr())));
173        //        let perm = owner.cast_perm();
174        //        regions.slot_owners.tracked_insert(frame_to_index(meta_to_frame(self.ptr.addr())), owner);
175        #[verus_spec(with Tracked(perm))]
176        let slot = self.slot();
177
178        #[verus_spec(with Tracked(perm))]
179        slot.as_meta_ptr()
180    }
181}
182
183impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> UniqueFrame<M> {
184    /// Gets the physical address of the start of the frame.
185    #[rustc_allow_incoherent_impl]
186    #[verus_spec(
187        with Tracked(regions) : Tracked<& MetaRegionOwners>
188    )]
189    #[verifier::external_body]
190    pub fn start_paddr(&self) -> Paddr {
191        //        #[verus_spec(with Tracked(&regions))]
192        let slot = self.slot();
193        slot.frame_paddr()
194    }
195
196    /// Gets the paging level of this page.
197    ///
198    /// This is the level of the page table entry that maps the frame,
199    /// which determines the size of the frame.
200    ///
201    /// Currently, the level is always 1, which means the frame is a regular
202    /// page frame.
203    #[rustc_allow_incoherent_impl]
204    pub const fn level(&self) -> PagingLevel {
205        1
206    }
207
208    /// Gets the size of this page in bytes.
209    #[rustc_allow_incoherent_impl]
210    pub const fn size(&self) -> usize {
211        PAGE_SIZE()
212    }
213
214    /*    /// Gets the dynamically-typed metadata of this frame.
215    ///
216    /// If the type is known at compile time, use [`Frame::meta`] instead.
217    #[rustc_allow_incoherent_impl]
218    #[verifier::external_body]
219    pub fn dyn_meta(&self) -> &M {
220        // SAFETY: The metadata is initialized and valid.
221        unsafe { &*self.slot().dyn_meta_ptr::<M>() }
222    }
223
224    /// Gets the dynamically-typed metadata of this frame.
225    ///
226    /// If the type is known at compile time, use [`Frame::meta`] instead.
227    #[rustc_allow_incoherent_impl]
228    #[verifier::external_body]
229    pub fn dyn_meta_mut(&mut self) -> &mut FrameMeta {
230        // SAFETY: The metadata is initialized and valid. We have the exclusive
231        // access to the frame.
232        unsafe { &mut *self.slot().dyn_meta_ptr() }
233    }*/
234    /*
235    /// Resets the frame to unused without up-calling the allocator.
236    ///
237    /// This is solely useful for the allocator implementation/testing and
238    /// is highly experimental. Usage of this function is discouraged.
239    ///
240    /// Usage of this function other than the allocator would actually leak
241    /// the frame since the allocator would not be aware of the frame.
242    //
243    // FIXME: We may have a better `Segment` and `UniqueSegment` design to
244    // allow the allocator hold the ownership of all the frames in a chunk
245    // instead of the head. Then this weird public API can be `#[cfg(ktest)]`.
246    pub fn reset_as_unused(self) {
247        let this = ManuallyDrop::new(self);
248
249        this.slot().ref_count.store(0, Ordering::Release);
250        // SAFETY: We are the sole owner and the reference count is 0.
251        // The slot is initialized.
252        unsafe { this.slot().drop_last_in_place() };
253    }*/
254    /// Converts this frame into a raw physical address.
255    #[rustc_allow_incoherent_impl]
256    #[verifier::external_body]
257    pub(crate) fn into_raw(self) -> Paddr {
258        let this = ManuallyDrop::new(self);
259        this.start_paddr()
260    }
261
262    /// Restores a raw physical address back into a unique frame.
263    ///
264    /// # Safety
265    ///
266    /// The caller must ensure that the physical address is valid and points to
267    /// a forgotten frame that was previously casted by [`Self::into_raw`].
268    #[rustc_allow_incoherent_impl]
269    #[verus_spec(res =>
270        with Tracked(regions): Tracked<&mut MetaRegionOwners>,
271            Tracked(meta_perm): Tracked<PointsTo<MetaSlot, M>>,
272            Tracked(meta_own): Tracked<M::Owner>
273    )]
274    #[verifier::external_body]
275    pub fn from_raw(paddr: Paddr) -> (res: (Self, Tracked<UniqueFrameOwner<M>>))
276        requires
277            paddr < MAX_PADDR(),
278            paddr % PAGE_SIZE() == 0,
279            old(regions).dropped_slots.contains_key(frame_to_index(paddr)),
280        ensures
281            res.0.ptr.addr() == frame_to_meta(paddr),
282            res.0.wf(res.1@),
283            res.1@.meta_own == meta_own,
284            res.1@.meta_perm == meta_perm,
285            regions.slots[frame_to_index(paddr)] == old(regions).dropped_slots[frame_to_index(
286                paddr,
287            )],
288            !regions.dropped_slots.contains_key(frame_to_index(paddr)),
289            regions.slots == old(regions).slots,
290            regions.slot_owners == old(regions).slot_owners,
291    {
292        let vaddr = frame_to_meta(paddr);
293        let ptr = vstd::simple_pptr::PPtr::<MetaSlot>::from_addr(vaddr);
294
295        let tracked slot_own = regions.dropped_slots.tracked_remove(frame_to_index(paddr));
296        proof { regions.slots.tracked_insert(frame_to_index(paddr), slot_own) }
297
298        (
299            Self { ptr, _marker: PhantomData },
300            Tracked(
301                UniqueFrameOwner::<M>::from_raw_owner(
302                    meta_own,
303                    Ghost(frame_to_index(paddr)),
304                    meta_perm,
305                ),
306            ),
307        )
308    }
309
310    #[rustc_allow_incoherent_impl]
311    #[verifier::external_body]
312    #[verus_spec(
313        with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
314    )]
315    pub fn slot<'a>(&self) -> &'a MetaSlot
316        requires
317            slot_perm.pptr() == self.ptr,
318            slot_perm.is_init(),
319        returns
320            slot_perm.value(),
321    {
322        unimplemented!()
323        // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
324        // mutably borrowed, so taking an immutable reference to it is safe.
325        //        unsafe { &*self.ptr }
326
327    }
328}
329
330/*impl<M: AnyFrameMeta + ?Sized> Drop for UniqueFrame<M> {
331    fn drop(&mut self) {
332        self.slot().ref_count.store(0, Ordering::Relaxed);
333        // SAFETY: We are the sole owner and the reference count is 0.
334        // The slot is initialized.
335        unsafe { self.slot().drop_last_in_place() };
336
337        super::allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
338    }
339}*/
340/*impl<M: AnyFrameMeta> From<UniqueFrame<Link<M>>> for Frame<M> {
341    #[verifier::external_body]
342    fn from(unique: UniqueFrame<Link<M>>) -> Self {
343        unimplemented!()/*
344        // The `Release` ordering make sure that previous writes are visible
345        // before the reference count is set to 1. It pairs with
346        // `MetaSlot::get_from_in_use`.
347        unique.slot().ref_count.store(1, Ordering::Release);
348        // SAFETY: The internal representation is now the same.
349        unsafe { core::mem::transmute(unique) }*/
350
351    }
352}*/
353/*impl<M: AnyFrameMeta> TryFrom<Frame<M>> for UniqueFrame<Link<M>> {
354    type Error = Frame<M>;
355
356    #[verifier::external_body]
357    /// Tries to get a unique frame from a shared frame.
358    ///
359    /// If the reference count is not 1, the frame is returned back.
360    fn try_from(frame: Frame<M>) -> Result<Self, Self::Error> {
361        unimplemented!()/*        match frame.slot().ref_count.compare_exchange(
362            1,
363            REF_COUNT_UNIQUE,
364            Ordering::Relaxed,
365            Ordering::Relaxed,
366        ) {
367            Ok(_) => {
368                // SAFETY: The reference count is now `REF_COUNT_UNIQUE`.
369                Ok(unsafe { core::mem::transmute::<Frame<M>, UniqueFrame<M>>(frame) })
370            }
371            Err(_) => Err(frame),
372        }*/
373
374    }
375}*/
376} // verus!