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::drop_tracking::*;
11use vstd_extra::ownership::*;
12
13use super::meta::{has_safe_slot, AnyFrameMeta, GetFrameError, MetaSlot};
14
15use core::{marker::PhantomData, sync::atomic::Ordering};
16
17use super::meta::mapping::{
18    frame_to_index, frame_to_meta, max_meta_slots, meta_addr, meta_to_frame, META_SLOT_SIZE,
19};
20use super::meta::{REF_COUNT_UNIQUE, REF_COUNT_UNUSED};
21use crate::mm::frame::MetaPerm;
22use crate::mm::{Paddr, PagingLevel, MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
23use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
24use crate::specs::arch::paging_consts::PagingConsts;
25use crate::specs::mm::frame::meta_owners::MetaSlotStorage;
26use crate::specs::mm::frame::meta_owners::Metadata;
27use crate::specs::mm::frame::unique::UniqueFrameOwner;
28
29verus! {
30
31pub struct UniqueFrame<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> {
32    pub ptr: PPtr<MetaSlot>,
33    pub _marker: PhantomData<M>,
34}
35
36#[verus_verify]
37impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> UniqueFrame<M> {
38    /// Gets a [`UniqueFrame`] with a specific usage from a raw, unused page.
39    ///
40    /// The caller should provide the initial metadata of the page.
41    /// # Verified Properties
42    /// ## Preconditions
43    /// The page must be unused and the metadata region must be well-formed.
44    /// ## Postconditions
45    /// If the page is valid, the function returns a unique frame.
46    /// ## Safety
47    /// If `paddr` is misaligned or out of bounds, the function will return an error. If it returns a frame,
48    /// it also returns an owner for that frame, indicating that the caller now has exclusive ownership of it.
49    /// See [Safe Encapsulation] for more details.
50    #[verus_spec(res =>
51        with Tracked(regions): Tracked<&mut MetaRegionOwners>
52        -> owner: Tracked<Option<UniqueFrameOwner<M>>>
53        requires
54            old(regions).slots.contains_key(frame_to_index(paddr)),
55            old(regions).slot_owners.contains_key(frame_to_index(paddr)),
56            old(regions).slot_owners[frame_to_index(paddr)].usage is Unused,
57            old(regions).inv(),
58        ensures
59            !has_safe_slot(paddr) ==> res is Err,
60            res is Ok ==> res.unwrap().wf(owner@.unwrap()),
61    )]
62    pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError> {
63        #[verus_spec(with Tracked(regions))]
64        let from_unused = MetaSlot::get_from_unused(paddr, metadata, true);
65
66        if let Err(err) = from_unused {
67            proof_with!(|= Tracked(None));
68            Err(err)
69        } else {
70            let (ptr, Tracked(perm)) = from_unused.unwrap();
71            proof_decl! {
72                let tracked owner = UniqueFrameOwner::<M>::from_unused_owner(regions, paddr, perm);
73            }
74
75            proof_with!(|= Tracked(Some(owner)));
76            Ok(Self { ptr, _marker: PhantomData })
77        }
78    }
79
80    pub open spec fn transmute_spec<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(
81        self,
82        transmuted: UniqueFrame<M1>,
83    ) -> bool {
84        &&& transmuted.ptr.addr() == self.ptr.addr()
85        &&& transmuted._marker == PhantomData::<M1>
86    }
87
88    #[verifier::external_body]
89    pub fn transmute<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(self) -> (res: UniqueFrame<
90        M1,
91    >)
92        ensures
93            Self::transmute_spec(self, res),
94    {
95        unimplemented!()
96    }
97
98    /// Repurposes the frame with a new metadata.
99    /// # Verified Properties
100    /// ## Preconditions
101    /// - The caller must provide a valid owner for the frame, and the metadata region invariants must hold.
102    /// - The meta slot's reference count must be `REF_COUNT_UNIQUE`.
103    /// ## Postconditions
104    /// The function returns a new owner for the frame with the new metadata,
105    /// and the metadata region invariants are preserved.
106    /// ## Safety
107    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
108    /// and represents that the caller has exclusive ownership of the frame.
109    #[verus_spec(res =>
110        with Tracked(owner): Tracked<UniqueFrameOwner<M>>,
111            Tracked(regions): Tracked<&mut MetaRegionOwners>
112        -> new_owner: Tracked<UniqueFrameOwner<M1>>
113        requires
114            self.wf(owner),
115            owner.inv(),
116            old(regions).slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr()))),
117            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
118            old(regions).inv(),
119        ensures
120            res.wf(new_owner@),
121            new_owner@.meta_perm.value().metadata == metadata,
122            regions.inv(),
123    )]
124    pub fn repurpose<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(
125        self,
126        metadata: M1,
127    ) -> UniqueFrame<M1> {
128        let tracked mut slot_own = regions.slot_owners.tracked_remove(
129            frame_to_index(meta_to_frame(self.ptr.addr())),
130        );
131
132        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
133        let slot = self.slot();
134
135        assert(slot_own.inv()) by {
136            admit();
137        }
138
139        // SAFETY: We are the sole owner and the metadata is initialized.
140        #[verus_spec(with Tracked(&mut slot_own))]
141        slot.drop_meta_in_place();
142
143        let Tracked(meta_perm) = MetaSlot::cast_perm::<M1>(
144            self.ptr.addr(),
145            Tracked(owner.meta_perm.points_to),
146            Tracked(owner.meta_perm.inner_perms),
147        );
148
149        proof_decl! {
150            let tracked mut new_owner = UniqueFrameOwner::<M1>::from_unused_owner(
151                regions,
152                meta_to_frame(self.ptr.addr()),
153                meta_perm,
154            );
155        }
156
157        // SAFETY: We are the sole owner.
158        //        #[verus_spec(with Tracked(&mut new_owner.meta_perm.inner_perms.storage))]
159        //        slot.write_meta(metadata);
160
161        proof {
162            regions.slot_owners.tracked_insert(
163                frame_to_index(meta_to_frame(self.ptr.addr())),
164                slot_own,
165            );
166            admit();
167        }
168
169        // SAFETY: The metadata is initialized with type `M1`.
170        proof_with!(|= Tracked(new_owner));
171        self.transmute()
172    }
173
174    /// Gets the metadata of this page.
175    /// Note that this function body differs from the original, because `as_meta_ptr` returns
176    /// a `ReprPtr<MetaSlot, Metadata<M>>` instead of a `*M`. So in order to keep the immutable borrow, we
177    /// borrow the metadata value from that pointer.
178    /// # Verified Properties
179    /// ## Preconditions
180    /// The caller must provide a valid owner for the frame.
181    /// ## Postconditions
182    /// The function returns the metadata of the frame.
183    /// ## Safety
184    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
185    /// and represents that the caller has exclusive ownership of the frame.
186    #[verus_spec(
187        with Tracked(owner): Tracked<&'a UniqueFrameOwner<M>>
188    )]
189    pub fn meta<'a>(&self) -> (l: &'a M)
190        requires
191            owner.inv(),
192            self.wf(*owner),
193        ensures
194            owner.meta_perm.mem_contents().value().metadata == l,
195    {
196        // SAFETY: The type is tracked by the type system.
197        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
198        let slot = self.slot();
199
200        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
201        let ptr = slot.as_meta_ptr();
202
203        &ptr.borrow(Tracked(&owner.meta_perm)).metadata
204    }
205
206    /// Gets the mutable metadata of this page.
207    /// Verified Properties
208    /// ## Preconditions
209    /// The caller must provide a valid owner for the frame.
210    /// ## Postconditions
211    /// The function returns the mutable metadata of the frame.
212    /// ## Safety
213    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
214    /// and represents that the caller has exclusive ownership of the frame. (See [Safe Encapsulation])
215    #[verus_spec(
216        with Tracked(owner): Tracked<&UniqueFrameOwner<M>>
217    )]
218    pub fn meta_mut(&mut self) -> (res: ReprPtr<MetaSlot, Metadata<M>>)
219        requires
220            owner.inv(),
221            old(self).wf(*owner),
222        ensures
223            res.addr() == self.ptr.addr(),
224            res.ptr.addr() == self.ptr.addr(),
225            *self == *old(self),
226    {
227        // SAFETY: The type is tracked by the type system.
228        // And we have the exclusive access to the metadata.
229        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
230        let slot = self.slot();
231
232        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
233        slot.as_meta_ptr()
234    }
235}
236
237impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + ?Sized> UniqueFrame<M> {
238    /// Gets the physical address of the start of the frame.
239    #[verus_spec(
240        with Tracked(owner): Tracked<&UniqueFrameOwner<M>>,
241        requires
242            owner.inv(),
243            self.wf(*owner),
244        returns
245            meta_to_frame(self.ptr.addr()),
246    )]
247    pub fn start_paddr(&self) -> Paddr {
248        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
249        let slot = self.slot();
250
251        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
252        slot.frame_paddr()
253    }
254
255    /// Gets the paging level of this page.
256    ///
257    /// This is the level of the page table entry that maps the frame,
258    /// which determines the size of the frame.
259    ///
260    /// Currently, the level is always 1, which means the frame is a regular
261    /// page frame.
262    pub const fn level(&self) -> PagingLevel {
263        1
264    }
265
266    /// Gets the size of this page in bytes.
267    pub const fn size(&self) -> usize {
268        PAGE_SIZE
269    }
270
271    /*    /// Gets the dynamically-typed metadata of this frame.
272    ///
273    /// If the type is known at compile time, use [`Frame::meta`] instead.
274
275    #[verifier::external_body]
276    pub fn dyn_meta(&self) -> &M {
277        // SAFETY: The metadata is initialized and valid.
278        unsafe { &*self.slot().dyn_meta_ptr::<M>() }
279    }
280
281    /// Gets the dynamically-typed metadata of this frame.
282    ///
283    /// If the type is known at compile time, use [`Frame::meta`] instead.
284
285    #[verifier::external_body]
286    pub fn dyn_meta_mut(&mut self) -> &mut FrameMeta {
287        // SAFETY: The metadata is initialized and valid. We have the exclusive
288        // access to the frame.
289        unsafe { &mut *self.slot().dyn_meta_ptr() }
290    }*/
291    pub open spec fn into_raw_requires(self, regions: MetaRegionOwners) -> bool {
292        &&& regions.slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
293        &&& regions.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count == 0
294        &&& regions.inv()
295    }
296
297    pub open spec fn into_raw_ensures(
298        self,
299        old_regions: MetaRegionOwners,
300        regions: MetaRegionOwners,
301        r: Paddr,
302    ) -> bool {
303        &&& r == meta_to_frame(self.ptr.addr())
304        &&& regions.inv()
305        &&& regions.slots =~= old_regions.slots
306        &&& regions.slot_owners[frame_to_index(r)].raw_count == 1
307        &&& forall|i: usize|
308            #![trigger regions.slot_owners[i]]
309            i != frame_to_index(r) ==> regions.slot_owners[i] == old_regions.slot_owners[i]
310    }
311
312    /*
313    /// Resets the frame to unused without up-calling the allocator.
314    ///
315    /// This is solely useful for the allocator implementation/testing and
316    /// is highly experimental. Usage of this function is discouraged.
317    ///
318    /// Usage of this function other than the allocator would actually leak
319    /// the frame since the allocator would not be aware of the frame.
320    //
321    // FIXME: We may have a better `Segment` and `UniqueSegment` design to
322    // allow the allocator hold the ownership of all the frames in a chunk
323    // instead of the head. Then this weird public API can be `#[cfg(ktest)]`.
324    pub fn reset_as_unused(self) {
325        let this = ManuallyDrop::new(self);
326
327        this.slot().ref_count.store(0, Ordering::Release);
328        // SAFETY: We are the sole owner and the reference count is 0.
329        // The slot is initialized.
330        unsafe { this.slot().drop_last_in_place() };
331    }*/
332    /// Converts this frame into a raw physical address.
333    #[verus_spec(r =>
334        with Tracked(owner): Tracked<&UniqueFrameOwner<M>>,
335            Tracked(regions): Tracked<&mut MetaRegionOwners>
336        requires
337            Self::into_raw_requires(self, *old(regions)),
338            self.wf(*owner),
339            owner.inv(),
340            old(regions).inv(),
341            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count == 0,
342            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
343        ensures
344            Self::into_raw_ensures(self, *old(regions), *regions, r),
345            regions.inv(),
346    )]
347    pub(crate) fn into_raw(self) -> Paddr {
348        #[verus_spec(with Tracked(owner))]
349        let paddr = self.start_paddr();
350
351        assert(self.constructor_requires(*old(regions)));
352        let _ = ManuallyDrop::new(self, Tracked(regions));
353
354        paddr
355    }
356
357    /// Restores a raw physical address back into a unique frame.
358    ///
359    /// # Safety
360    ///
361    /// The caller must ensure that the physical address is valid and points to
362    /// a forgotten frame that was previously casted by [`Self::into_raw`].
363    #[verus_spec(res =>
364        with Tracked(regions): Tracked<&mut MetaRegionOwners>,
365            Tracked(meta_perm): Tracked<PointsTo<MetaSlot, Metadata<M>>>,
366            Tracked(meta_own): Tracked<M::Owner>
367    )]
368    pub(crate) fn from_raw(paddr: Paddr) -> (res: (Self, Tracked<UniqueFrameOwner<M>>))
369        requires
370            paddr < MAX_PADDR,
371            paddr % PAGE_SIZE == 0,
372            old(regions).inv(),
373            old(regions).slot_owners.contains_key(frame_to_index(paddr)),
374            old(regions).slot_owners[frame_to_index(paddr)].raw_count > 0,
375            !old(regions).slots.contains_key(frame_to_index(paddr)),
376            meta_perm.inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
377            meta_perm.addr() == frame_to_meta(paddr),
378        ensures
379            res.0.ptr.addr() == frame_to_meta(paddr),
380            res.0.wf(res.1@),
381            res.1@.meta_own == meta_own,
382            res.1@.meta_perm == meta_perm,
383            regions.inv(),
384            regions.slot_owners[frame_to_index(paddr)].raw_count == old(
385                regions,
386            ).slot_owners[frame_to_index(paddr)].raw_count - 1,
387    {
388        let vaddr = frame_to_meta(paddr);
389        let ptr = vstd::simple_pptr::PPtr::<MetaSlot>::from_addr(vaddr);
390
391        proof {
392            let tracked mut slot_own = regions.slot_owners.tracked_remove(frame_to_index(paddr));
393            slot_own.raw_count = (slot_own.raw_count - 1) as usize;
394            regions.slot_owners.tracked_insert(frame_to_index(paddr), slot_own);
395        }
396
397        let tracked owner = UniqueFrameOwner {
398            meta_own,
399            meta_perm,
400            slot_index: frame_to_index(paddr),
401        };
402
403        (Self { ptr, _marker: PhantomData }, Tracked(owner))
404    }
405
406    #[verifier::external_body]
407    #[verus_spec(
408        with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
409    )]
410    pub fn slot<'a>(&self) -> &'a MetaSlot
411        requires
412            slot_perm.pptr() == self.ptr,
413            slot_perm.is_init(),
414        returns
415            slot_perm.value(),
416    {
417        unimplemented!()
418        // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
419        // mutably borrowed, so taking an immutable reference to it is safe.
420        //        unsafe { &*self.ptr }
421
422    }
423}
424
425impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + ?Sized> UniqueFrame<M> {
426    #[verus_spec(
427        with Tracked(owner): Tracked<UniqueFrameOwner<M>>,
428            Tracked(regions): Tracked<&mut MetaRegionOwners>,
429        requires
430            old(self).wf(owner),
431            owner.inv(),
432            old(regions).slot_owners.contains_key(owner.slot_index),
433            old(regions).slot_owners[owner.slot_index].raw_count == 0,
434            old(regions).slot_owners[owner.slot_index].self_addr == meta_addr(owner.slot_index),
435            !old(regions).slots.contains_key(owner.slot_index),
436            owner.meta_perm.inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
437            owner.meta_perm.inner_perms.in_list.value() == 0,
438            owner.meta_perm.inner_perms.storage.is_init(),
439            owner.meta_perm.inner_perms.vtable_ptr.is_init(),
440            old(regions).inv(),
441        ensures
442            regions.slot_owners[owner.slot_index].raw_count == 0,
443            regions.inv(),
444    )]
445    fn drop(&mut self) {
446        let ghost idx = owner.slot_index;
447        let ghost inner_storage_id = owner.meta_perm.inner_perms.storage.id();
448        let ghost inner_ref_count_id = owner.meta_perm.inner_perms.ref_count.id();
449        let ghost inner_vtable_pptr = owner.meta_perm.inner_perms.vtable_ptr.pptr();
450        let ghost inner_in_list_id = owner.meta_perm.inner_perms.in_list.id();
451
452        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
453        let tracked perm = owner.meta_perm.points_to;
454
455        proof {
456            assert(perm.value().storage.id() == inner_storage_id);
457            assert(perm.value().ref_count.id() == inner_ref_count_id);
458            slot_own.inner_perms = owner.meta_perm.inner_perms;
459        }
460        ;
461
462        // SAFETY: We are the sole owner and the reference count is 0.
463        // The slot is initialized.
464        #[verus_spec(with Tracked(&perm))]
465        let slot = self.slot();
466
467        #[verus_spec(with Tracked(&mut slot_own))]
468        slot.drop_last_in_place();
469
470        proof {
471            regions.slot_owners.tracked_insert(idx, slot_own);
472            regions.slots.tracked_insert(idx, perm);
473        }
474
475        //        super::allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
476    }
477}
478
479/*impl<M: AnyFrameMeta> From<UniqueFrame<Link<M>>> for Frame<M> {
480    #[verifier::external_body]
481    fn from(unique: UniqueFrame<Link<M>>) -> Self {
482        unimplemented!()/*
483        // The `Release` ordering make sure that previous writes are visible
484        // before the reference count is set to 1. It pairs with
485        // `MetaSlot::get_from_in_use`.
486        unique.slot().ref_count.store(1, Ordering::Release);
487        // SAFETY: The internal representation is now the same.
488        unsafe { core::mem::transmute(unique) }*/
489
490    }
491}*/
492/*impl<M: AnyFrameMeta> TryFrom<Frame<M>> for UniqueFrame<Link<M>> {
493    type Error = Frame<M>;
494
495    #[verifier::external_body]
496    /// Tries to get a unique frame from a shared frame.
497    ///
498    /// If the reference count is not 1, the frame is returned back.
499    fn try_from(frame: Frame<M>) -> Result<Self, Self::Error> {
500        unimplemented!()/*        match frame.slot().ref_count.compare_exchange(
501            1,
502            REF_COUNT_UNIQUE,
503            Ordering::Relaxed,
504            Ordering::Relaxed,
505        ) {
506            Ok(_) => {
507                // SAFETY: The reference count is now `REF_COUNT_UNIQUE`.
508                Ok(unsafe { core::mem::transmute::<Frame<M>, UniqueFrame<M>>(frame) })
509            }
510            Err(_) => Err(frame),
511        }*/
512
513    }
514}*/
515} // verus!