ostd/mm/frame/
mod.rs

1// SPDX-License-Identifier: MPL-2.0
2//! Frame (physical memory page) management.
3//!
4//! A frame is an aligned, contiguous range of bytes in physical memory. The
5//! sizes of base frames and huge frames (that are mapped as "huge pages") are
6//! architecture-dependent. A frame can be mapped to virtual address spaces
7//! using the page table.
8//!
9//! Frames can be accessed through frame handles, namely, [`Frame`]. A frame
10//! handle is a reference-counted pointer to a frame. When all handles to a
11//! frame are dropped, the frame is released and can be reused.  Contiguous
12//! frames are managed with [`Segment`].
13//!
14//! There are various kinds of frames. The top-level grouping of frame kinds
15//! are "typed" frames and "untyped" frames. Typed frames host Rust objects
16//! that must follow the visibility, lifetime and borrow rules of Rust, thus
17//! not being able to be directly manipulated. Untyped frames are raw memory
18//! that can be manipulated directly. So only untyped frames can be
19//!  - safely shared to external entities such as device drivers or user-space
20//!    applications.
21//!  - or directly manipulated with readers and writers that neglect Rust's
22//!    "alias XOR mutability" rule.
23//!
24//! The kind of a frame is determined by the type of its metadata. Untyped
25//! frames have its metadata type that implements the [`AnyUFrameMeta`]
26//! trait, while typed frames don't.
27//!
28//! Frames can have dedicated metadata, which is implemented in the [`meta`]
29//! module. The reference count and usage of a frame are stored in the metadata
30//! as well, leaving the handle only a pointer to the metadata slot. Users
31//! can create custom metadata types by implementing the [`AnyFrameMeta`] trait.
32//pub mod allocator;
33pub mod allocator;
34pub mod linked_list;
35pub mod meta;
36pub mod segment;
37pub mod unique;
38pub mod untyped;
39
40mod frame_ref;
41
42#[cfg(ktest)]
43mod test;
44
45use vstd::atomic::PermissionU64;
46use vstd::prelude::*;
47use vstd::simple_pptr::{self, PPtr};
48
49use vstd_extra::cast_ptr;
50
51use core::{
52    marker::PhantomData,
53    sync::atomic::{AtomicUsize, Ordering},
54};
55
56//pub use allocator::GlobalFrameAllocator;
57use meta::REF_COUNT_UNUSED;
58pub use segment::Segment;
59
60// Re-export commonly used types
61use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
62pub use frame_ref::FrameRef;
63pub use linked_list::{CursorMut, Link, LinkedList};
64pub use meta::mapping::{
65    frame_to_index, frame_to_index_spec, frame_to_meta, meta_addr, meta_to_frame, META_SLOT_SIZE,
66};
67pub use meta::{has_safe_slot, AnyFrameMeta, GetFrameError, MetaSlot};
68pub use unique::UniqueFrame;
69
70use crate::mm::page_table::{PageTableConfig, PageTablePageMeta};
71
72use vstd_extra::cast_ptr::*;
73use vstd_extra::drop_tracking::*;
74use vstd_extra::ownership::*;
75
76use crate::mm::{
77    kspace::{LINEAR_MAPPING_BASE_VADDR, VMALLOC_BASE_VADDR},
78    Paddr, PagingLevel, Vaddr, MAX_PADDR,
79};
80use crate::specs::arch::mm::{MAX_NR_PAGES, PAGE_SIZE};
81use crate::specs::mm::frame::frame_specs::*;
82use crate::specs::mm::frame::meta_owners::*;
83use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
84
85verus! {
86
87/// A smart pointer to a frame.
88///
89/// A frame is a contiguous range of bytes in physical memory. The [`Frame`]
90/// type is a smart pointer to a frame that is reference-counted.
91///
92/// Frames are associated with metadata. The type of the metadata `M` is
93/// determines the kind of the frame. If `M` implements [`AnyUFrameMeta`], the
94/// frame is a untyped frame. Otherwise, it is a typed frame.
95/// # Verification Design
96#[repr(transparent)]
97pub struct Frame<M: AnyFrameMeta> {
98    pub ptr: PPtr<MetaSlot>,
99    pub _marker: PhantomData<M>,
100}
101
102impl<M: AnyFrameMeta> Clone for Frame<M> {
103    fn clone(&self) -> Self {
104        Self { ptr: PPtr::<MetaSlot>::from_addr(self.ptr.0), _marker: PhantomData }
105    }
106}
107
108/// We need to keep track of when frames are forgotten with `ManuallyDrop`.
109/// We maintain a counter for each frame of how many times it has been forgotten (`raw_count`).
110/// Calling `ManuallyDrop::new` increments the counter. It is technically safe to forget a frame multiple times,
111/// and this will happen with read-only `FrameRef`s. All such references need to be dropped by the time
112/// `from_raw` is called. So, `ManuallyDrop::drop` decrements the counter when the reference is dropped,
113/// and `from_raw` may only be called when the counter is 1.
114impl<M: AnyFrameMeta> TrackDrop for Frame<M> {
115    type State = MetaRegionOwners;
116
117    open spec fn constructor_requires(self, s: Self::State) -> bool {
118        &&& s.slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
119        &&& s.inv()
120    }
121
122    open spec fn constructor_ensures(self, s0: Self::State, s1: Self::State) -> bool {
123        let slot_own = s0.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))];
124        &&& s1.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))] == MetaSlotOwner {
125            raw_count: (slot_own.raw_count + 1) as usize,
126            ..slot_own
127        }
128        &&& forall|i: usize|
129            #![trigger s1.slot_owners[i]]
130            i != frame_to_index(meta_to_frame(self.ptr.addr())) ==> s1.slot_owners[i]
131                == s0.slot_owners[i]
132        &&& s1.slots =~= s0.slots
133        &&& s1.slot_owners.dom() =~= s0.slot_owners.dom()
134    }
135
136    proof fn constructor_spec(self, tracked s: &mut Self::State) {
137        let meta_addr = self.ptr.addr();
138        let index = frame_to_index(meta_to_frame(meta_addr));
139        let tracked mut slot_own = s.slot_owners.tracked_remove(index);
140        slot_own.raw_count = (slot_own.raw_count + 1) as usize;
141        s.slot_owners.tracked_insert(index, slot_own);
142    }
143
144    open spec fn drop_requires(self, s: Self::State) -> bool {
145        &&& s.slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
146        &&& s.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count > 0
147    }
148
149    open spec fn drop_ensures(self, s0: Self::State, s1: Self::State) -> bool {
150        let slot_own = s0.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))];
151        &&& s1.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count == (
152        slot_own.raw_count - 1) as usize
153        &&& forall|i: usize|
154            #![trigger s1.slot_owners[i]]
155            i != frame_to_index(meta_to_frame(self.ptr.addr())) ==> s1.slot_owners[i]
156                == s0.slot_owners[i]
157        &&& s1.slots =~= s0.slots
158        &&& s1.slot_owners.dom() =~= s0.slot_owners.dom()
159    }
160
161    proof fn drop_spec(self, tracked s: &mut Self::State) {
162        let index = frame_to_index(meta_to_frame(self.ptr.addr()));
163        let tracked mut slot_own = s.slot_owners.tracked_remove(index);
164        slot_own.raw_count = (slot_own.raw_count - 1) as usize;
165        s.slot_owners.tracked_insert(index, slot_own);
166    }
167}
168
169impl<M: AnyFrameMeta> Inv for Frame<M> {
170    open spec fn inv(self) -> bool {
171        &&& self.ptr.addr() % META_SLOT_SIZE == 0
172        &&& FRAME_METADATA_RANGE.start <= self.ptr.addr() < FRAME_METADATA_RANGE.start
173            + MAX_NR_PAGES * META_SLOT_SIZE
174        &&& self.ptr.addr() < VMALLOC_BASE_VADDR - LINEAR_MAPPING_BASE_VADDR
175    }
176}
177
178impl<M: AnyFrameMeta> Frame<M> {
179    pub open spec fn paddr(self) -> usize {
180        meta_to_frame(self.ptr.addr())
181    }
182
183    pub open spec fn index(self) -> usize {
184        frame_to_index(self.paddr())
185    }
186}
187
188#[verus_verify]
189impl<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
190    /// Gets a [`Frame`] with a specific usage from a raw, unused page.
191    ///
192    /// The caller should provide the initial metadata of the page.
193    ///
194    /// If the provided frame is not truly unused at the moment, it will return
195    /// an error. If wanting to acquire a frame that is already in use, use
196    /// [`Frame::from_in_use`] instead.
197    /// # Verified Properties
198    /// ## Preconditions
199    /// - **Safety Invariant**: Metaslot region invariants must hold.
200    /// - **Bookkeeping**: The slot must be available in order to get the permission.
201    /// This is stronger than it needs to be; absent permissions correspond to error cases.
202    /// ## Postconditions
203    /// - **Safety Invariant**: Metaslot region invariants hold after the call.
204    /// - **Correctness**: If successful, the function returns a pointer to the metadata slot and a permission to the slot.
205    /// - **Correctness**: If successful, the slot is initialized with the given metadata.
206    /// ## Safety
207    /// - This function returns an error if `paddr` does not correspond to a valid slot or the slot is in use.
208    #[verus_spec(r =>
209        with
210            Tracked(regions): Tracked<&mut MetaRegionOwners>
211            -> perm: Tracked<Option<PointsTo<MetaSlot, Metadata<M>>>>
212        requires
213            old(regions).inv(),
214            old(regions).slots.contains_key(frame_to_index(paddr)),
215        ensures
216            regions.inv(),
217            r matches Ok(res) ==> perm@ is Some && MetaSlot::get_from_unused_perm_spec(paddr, metadata, false, res.ptr, perm@.unwrap()),
218            r is Ok ==> MetaSlot::get_from_unused_spec(paddr, false, *old(regions), *regions),
219            !has_safe_slot(paddr) ==> r is Err,
220    )]
221    pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError> {
222        #[verus_spec(with Tracked(regions))]
223        let from_unused = MetaSlot::get_from_unused(paddr, metadata, false);
224        if let Err(err) = from_unused {
225            proof_with!(|= Tracked(None));
226            Err(err)
227        } else {
228            let (ptr, Tracked(perm)) = from_unused.unwrap();
229            proof_with!(|= Tracked(Some(perm)));
230            Ok(Self { ptr, _marker: PhantomData })
231        }
232    }
233
234    /// Gets the metadata of this page.
235    /// # Verified Properties
236    /// ## Preconditions
237    /// - The caller must have a valid permission for the frame.
238    /// ## Postconditions
239    /// - The function returns the metadata of the frame.
240    /// ## Safety
241    /// - By requiring the caller to provide a typed permission, we ensure that the metadata is of type `M`.
242    /// While a non-verified caller cannot be trusted to obey this interface, all functions that return a `Frame<M>` also
243    /// return an appropriate permission.
244    #[verus_spec(
245        with Tracked(perm) : Tracked<&'a PointsTo<MetaSlot, Metadata<M>>>,
246        requires
247            self.ptr.addr() == perm.addr(),
248            self.ptr == perm.points_to.pptr(),
249            perm.is_init(),
250            perm.wf(&perm.inner_perms),
251        returns
252            perm.value().metadata,
253    )]
254    pub fn meta(&self) -> &'a M {
255        // SAFETY: The type is tracked by the type system.
256        #[verus_spec(with Tracked(&perm.points_to))]
257        let slot = self.slot();
258
259        #[verus_spec(with Tracked(&perm.points_to))]
260        let ptr = slot.as_meta_ptr();
261
262        &ptr.borrow(Tracked(perm)).metadata
263    }
264}
265
266#[verus_verify]
267impl<M: AnyFrameMeta> Frame<M> {
268    /// Gets a dynamically typed [`Frame`] from a raw, in-use page.
269    ///
270    /// If the provided frame is not in use at the moment, it will return an error.
271    ///
272    /// The returned frame will have an extra reference count to the frame.
273    ///
274    /// # Verified Properties
275    /// ## Preconditions
276    /// - **Safety Invariant**: Metaslot region invariants must hold.
277    /// - **Liveness**: The slot must have fewer than `REF_COUNT_MAX - 1` references or the function will panic.
278    /// ## Postconditions
279    /// - **Safety Invariant**: Metaslot region invariants hold after the call.
280    /// - **Correctness**: If successful, the function returns the frame at `paddr`.
281    /// - **Correctness**: If successful, the frame has an extra reference count to the frame.
282    /// - **Safety**: Frames other than the one at `paddr` are not affected by the call.
283    /// ## Safety
284    /// - If `paddr` is a valid frame address, it is safe to take a reference to the frame.
285    /// - If `paddr` is not a valid frame address, the function will return an error.
286    #[verus_spec(res =>
287        with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
288        requires
289            old(regions).inv(),
290            old(regions).slots.contains_key(frame_to_index(paddr)),
291            !MetaSlot::get_from_in_use_panic_cond(paddr, *old(regions)),
292        ensures
293            regions.inv(),
294            res is Ok ==>
295                regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() ==
296                old(regions).slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1,
297            res matches Ok(res) ==>
298                res.ptr == old(regions).slots[frame_to_index(paddr)].pptr(),
299            !has_safe_slot(paddr) ==> res is Err,
300            forall|i: usize|
301                #![trigger regions.slot_owners[i]]
302                i != frame_to_index(paddr) ==> regions.slot_owners[i] == old(regions).slot_owners[i]
303    )]
304    pub fn from_in_use(paddr: Paddr) -> Result<Self, GetFrameError> {
305        #[verus_spec(with Tracked(regions))]
306        let from_in_use = MetaSlot::get_from_in_use(paddr);
307        Ok(Self { ptr: from_in_use?, _marker: PhantomData })
308    }
309}
310
311#[verus_verify]
312impl<'a, M: AnyFrameMeta> Frame<M> {
313    /// Gets the physical address of the start of the frame.
314    #[verus_spec(
315        with Tracked(perm): Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>
316    )]
317    pub fn start_paddr(&self) -> Paddr
318        requires
319            perm.addr() == self.ptr.addr(),
320            perm.is_init(),
321            FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end,
322            perm.addr() % META_SLOT_SIZE == 0,
323        returns
324            meta_to_frame(self.ptr.addr()),
325    {
326        #[verus_spec(with Tracked(perm))]
327        let slot = self.slot();
328
329        #[verus_spec(with Tracked(perm))]
330        slot.frame_paddr()
331    }
332
333    /// Gets the map level of this page.
334    ///
335    /// This is the level of the page table entry that maps the frame,
336    /// which determines the size of the frame.
337    ///
338    /// Currently, the level is always 1, which means the frame is a regular
339    /// page frame.
340    pub const fn map_level(&self) -> PagingLevel {
341        1
342    }
343
344    /// Gets the size of this page in bytes.
345    pub const fn size(&self) -> usize {
346        PAGE_SIZE
347    }
348
349    /*    /// Gets the dynamically-typed metadata of this frame.
350    ///
351    /// If the type is known at compile time, use [`Frame::meta`] instead.
352    pub fn dyn_meta(&self) -> FrameMeta {
353        // SAFETY: The metadata is initialized and valid.
354        unsafe { &*self.slot().dyn_meta_ptr() }
355    }*/
356    /// Gets the reference count of the frame.
357    ///
358    /// It returns the number of all references to the frame, including all the
359    /// existing frame handles ([`Frame`], [`Frame<dyn AnyFrameMeta>`]), and all
360    /// the mappings in the page table that points to the frame.
361    ///
362    /// # Verified Properties
363    /// ## Preconditions
364    /// - **Safety Invariant**: Metaslot region invariants must hold.
365    /// - **Bookkeeping**: The caller must have a valid and well-typed permission for the frame.
366    /// ## Postconditions
367    /// - **Correctness**: The function returns the reference count of the frame.
368    /// ## Safety
369    /// - The function is safe to call, but using it requires extra care. The
370    /// reference count can be changed by other threads at any time including
371    /// potentially between calling this method and acting on the result.
372    #[verus_spec(
373        with Tracked(slot_own): Tracked<&mut MetaSlotOwner>,
374            Tracked(perm) : Tracked<&PointsTo<MetaSlot, Metadata<M>>>
375    )]
376    pub fn reference_count(&self) -> u64
377        requires
378            perm.addr() == self.ptr.addr(),
379            perm.points_to.pptr() == self.ptr,
380            perm.is_init(),
381            perm.wf(&perm.inner_perms),
382            perm.inner_perms.ref_count.id() == perm.points_to.value().ref_count.id(),
383        returns
384            perm.value().ref_count,
385    {
386        #[verus_spec(with Tracked(&perm.points_to))]
387        let slot = self.slot();
388        slot.ref_count.load(Tracked(&perm.inner_perms.ref_count))
389    }
390
391    /// Borrows a reference from the given frame.
392    /// # Verified Properties
393    /// ## Preconditions
394    /// - **Safety Invariant**: Metaslot region invariants must hold.
395    /// - **Bookkeeping**: The caller must have a valid and well-typed permission for the frame.
396    /// ## Postconditions
397    /// - **Safety Invariant**: Metaslot region invariants hold after the call.
398    /// - **Correctness**: The function returns a reference to the frame.
399    /// - **Correctness**: The system context is unchanged.
400    #[verus_spec(res =>
401        with Tracked(regions): Tracked<&mut MetaRegionOwners>,
402            Tracked(perm): Tracked<&MetaPerm<M>>,
403        requires
404            old(regions).inv(),
405            old(regions).slot_owners[self.index()].raw_count == 1,
406            old(regions).slot_owners[self.index()].self_addr == self.ptr.addr(),
407            perm.points_to.pptr() == self.ptr,
408            perm.points_to.value().wf(old(regions).slot_owners[self.index()]),
409            perm.is_init(),
410            self.inv(),
411        ensures
412            regions.inv(),
413            res.inner@.ptr.addr() == self.ptr.addr(),
414            regions.slots =~= old(regions).slots,
415            regions.slot_owners =~= old(regions).slot_owners,
416    )]
417    pub fn borrow(&self) -> FrameRef<'a, M> {
418        assert(regions.slot_owners.contains_key(self.index()));
419        broadcast use crate::mm::frame::meta::mapping::group_page_meta;
420        // SAFETY: Both the lifetime and the type matches `self`.
421
422        #[verus_spec(with Tracked(&perm.points_to))]
423        let paddr = self.start_paddr();
424
425        #[verus_spec(with Tracked(regions), Tracked(perm))]
426        FrameRef::borrow_paddr(paddr)
427    }
428
429    /// Forgets the handle to the frame.
430    ///
431    /// This will result in the frame being leaked without calling the custom dropper.
432    ///
433    /// A physical address to the frame is returned in case the frame needs to be
434    /// restored using [`Frame::from_raw`] later. This is useful when some architectural
435    /// data structures need to hold the frame handle such as the page table.
436    ///
437    /// # Verified Properties
438    /// ## Preconditions
439    /// - **Safety Invariant**: Metaslot region invariants must hold.
440    /// - **Safety**: The frame must be in use (not unused).
441    /// ## Postconditions
442    /// - **Safety Invariant**: Metaslot region invariants hold after the call.
443    /// - **Correctness**: The function returns the physical address of the frame.
444    /// - **Correctness**: The frame's raw count is incremented.
445    /// - **Safety**: Frames other than this one are not affected by the call.
446    /// ## Safety
447    /// - We require the slot to be in use to ensure that a fresh frame handle will not be created until the raw frame is restored.
448    /// - The owner's raw count is incremented so that we can enforce the safety requirement on `Frame::from_raw`.
449    #[verus_spec(r =>
450        with
451            Tracked(regions): Tracked<&mut MetaRegionOwners>,
452                -> frame_perm: Tracked<MetaPerm<M>>,
453        requires
454            old(regions).inv(),
455            old(regions).slots.contains_key(self.index()),
456            self.inv(),
457            old(regions).slot_owners[self.index()].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
458        ensures
459            regions.inv(),
460            r == self.paddr(),
461            frame_perm@.points_to == old(regions).slots[self.index()],
462            regions.slot_owners[self.index()].raw_count
463                == (old(regions).slot_owners[self.index()].raw_count + 1) as usize,
464            self.into_raw_post_noninterference(*old(regions), *regions),
465    )]
466    pub(in crate::mm) fn into_raw(self) -> Paddr {
467        broadcast use crate::mm::frame::meta::mapping::group_page_meta;
468
469        let tracked perm = regions.slots.tracked_borrow(self.index());
470
471        assert(perm.addr() == self.ptr.addr()) by {
472            assert(frame_to_meta(meta_to_frame(self.ptr.addr())) == self.ptr.addr());
473        };
474
475        #[verus_spec(with Tracked(perm))]
476        let paddr = self.start_paddr();
477
478        let ghost index = self.index();
479
480        assert(self.constructor_requires(*regions));
481        let _ = ManuallyDrop::new(self, Tracked(regions));
482
483        assert(regions.slots.contains_key(index));
484        let tracked meta_perm = regions.copy_perm::<M>(index);
485
486        proof_with!(|= Tracked(meta_perm));
487        paddr
488    }
489
490    /// Restores a forgotten [`Frame`] from a physical address.
491    ///
492    /// # Safety
493    ///
494    /// The caller should only restore a `Frame` that was previously forgotten using
495    /// [`Frame::into_raw`].
496    ///
497    /// And the restoring operation should only be done once for a forgotten
498    /// [`Frame`]. Otherwise double-free will happen.
499    ///
500    /// Also, the caller ensures that the usage of the frame is correct. There's
501    /// no checking of the usage in this function.
502    ///
503    /// # Verified Properties
504    /// ## Preconditions
505    /// - **Safety Invariant**: Metaslot region invariants must hold.
506    /// - **Safety**: The caller must have a valid and well-typed permission for the frame.
507    /// - **Safety**: There must be at least one raw frame at `paddr`.
508    /// ## Postconditions
509    /// - **Safety Invariant**: Metaslot region invariants hold after the call.
510    /// - **Correctness**: The function returns the frame at `paddr`.
511    /// - **Correctness**: The frame's raw count is decremented.
512    /// - **Safety**: Frames other than this one are not affected by the call.
513    /// - **Safety**: The count of raw frames is restored to 0.
514    /// ## Safety
515    /// - When `into_raw` was called, the frame was marked to be ignored by the garbage collector.
516    /// Now we construct a new frame at the same address, which will be managed by the garbage collector again.
517    /// We ensure that we only do this once by setting the raw count to 0. We will only call this function again
518    /// if we have since forgotten the frame again.
519    #[verus_spec(r =>
520        with
521            Tracked(regions): Tracked<&mut MetaRegionOwners>,
522            Tracked(perm): Tracked<&MetaPerm<M>>,
523        requires
524            Self::from_raw_requires(*old(regions), paddr),
525            perm.points_to.is_init(),
526            perm.points_to.addr() == frame_to_meta(paddr),
527            perm.points_to.value().wf(old(regions).slot_owners[frame_to_index(paddr)]),
528        ensures
529            Self::from_raw_ensures(*old(regions), *regions, paddr, r),
530            regions.slots == old(regions).slots.insert(frame_to_index(paddr), perm.points_to),
531    )]
532    pub(in crate::mm) fn from_raw(paddr: Paddr) -> Self {
533        let vaddr = frame_to_meta(paddr);
534        let ptr = PPtr::from_addr(vaddr);
535
536        proof {
537            let index = frame_to_index(paddr);
538            regions.sync_perm::<M>(index, perm);
539
540            let tracked mut slot_own = regions.slot_owners.tracked_remove(index);
541            slot_own.raw_count = 0usize;
542            regions.slot_owners.tracked_insert(index, slot_own);
543        }
544
545        Self { ptr, _marker: PhantomData }
546    }
547
548    /// Gets the metadata slot of the frame.
549    ///
550    /// # Verified Properties
551    /// ## Preconditions
552    /// - **Safety**: The caller must have a valid permission for the frame.
553    /// ## Postconditions
554    /// - **Correctness**: The function returns a reference to the metadata slot of the frame.
555    /// ## Safety
556    /// - There is no way to mutably borrow the metadata slot, so taking an immutable reference is safe.
557    /// (The fields of the slot can be mutably borrowed, but not the slot itself.)
558    #[verus_spec(
559        with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
560    )]
561    pub fn slot(&self) -> (slot: &'a MetaSlot)
562        requires
563            slot_perm.pptr() == self.ptr,
564            slot_perm.is_init(),
565        returns
566            slot_perm.value(),
567    {
568        // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
569        // mutably borrowed, so taking an immutable reference to it is safe.
570        self.ptr.borrow(Tracked(slot_perm))
571    }
572}
573
574/// Increases the reference count of the frame by one.
575///
576/// # Verified Properties
577/// ## Preconditions
578/// - **Safety Invariant**: Metaslot region invariants must hold.
579/// - **Safety**: The physical address must represent a valid frame.
580/// ## Postconditions
581/// - **Safety Invariant**: Metaslot region invariants hold after the call.
582/// - **Correctness**: The reference count of the frame is increased by one.
583/// - **Safety**: Frames other than this one are not affected by the call.
584/// ## Safety
585/// We enforce the safety requirements that `paddr` represents a valid frame and the caller has already held a reference to the it.
586/// It is safe to require these as preconditions because the function is internal, so the caller must obey the preconditions.
587#[verus_spec(
588    with Tracked(regions): Tracked<&mut MetaRegionOwners>
589)]
590pub(in crate::mm) fn inc_frame_ref_count(paddr: Paddr)
591    requires
592        old(regions).inv(),
593        old(regions).slots.contains_key(frame_to_index(paddr)),
594        has_safe_slot(paddr),
595        !MetaSlot::inc_ref_count_panic_cond(
596            old(regions).slot_owners[frame_to_index(paddr)].inner_perms.ref_count,
597        ),
598    ensures
599        regions.inv(),
600        regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() == old(
601            regions,
602        ).slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1,
603        regions.slots =~= old(regions).slots,
604        forall|i: usize|
605            i != frame_to_index(paddr) ==> (#[trigger] regions.slot_owners[i] == old(
606                regions,
607            ).slot_owners[i]),
608        regions.slot_owners.dom() =~= old(regions).slot_owners.dom(),
609{
610    let tracked mut slot_own = regions.slot_owners.tracked_remove(frame_to_index(paddr));
611    let tracked perm = regions.slots.tracked_borrow(frame_to_index(paddr));
612    let tracked mut inner_perms = slot_own.take_inner_perms();
613
614    let vaddr: Vaddr = frame_to_meta(paddr);
615    // SAFETY: `vaddr` points to a valid `MetaSlot` that will never be mutably borrowed, so taking
616    // an immutable reference to it is always safe.
617    let slot = PPtr::<MetaSlot>::from_addr(vaddr);
618
619    #[verus_spec(with Tracked(&mut inner_perms.ref_count))]
620    slot.borrow(Tracked(perm)).inc_ref_count();
621
622    proof {
623        admit();
624        slot_own.sync_inner(&inner_perms);
625        regions.slot_owners.tracked_insert(frame_to_index(paddr), slot_own);
626    }
627}
628
629} // verus!
630/*
631impl<M: AnyFrameMeta + ?Sized> Clone for Frame<M> {
632    fn clone(&self) -> Self {
633        // SAFETY: We have already held a reference to the frame.
634        unsafe { self.slot().inc_ref_count() };
635
636        Self {
637            ptr: self.ptr,
638            _marker: PhantomData,
639        }
640    }
641}*/
642/*
643impl<M: AnyFrameMeta + ?Sized> Drop for Frame<M> {
644    fn drop(&mut self) {
645        let last_ref_cnt = self.slot().ref_count.fetch_sub(1, Ordering::Release);
646        debug_assert!(last_ref_cnt != 0 && last_ref_cnt != REF_COUNT_UNUSED);
647
648        if last_ref_cnt == 1 {
649            // A fence is needed here with the same reasons stated in the implementation of
650            // `Arc::drop`: <https://doc.rust-lang.org/std/sync/struct.Arc.html#method.drop>.
651            core::sync::atomic::fence(Ordering::Acquire);
652
653            // SAFETY: this is the last reference and is about to be dropped.
654            unsafe { self.slot().drop_last_in_place() };
655
656            allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
657        }
658    }
659}
660*/
661/*
662impl<M: AnyFrameMeta> TryFrom<Frame<dyn AnyFrameMeta>> for Frame<M> {
663    type Error = Frame<dyn AnyFrameMeta>;
664
665    /// Tries converting a [`Frame<dyn AnyFrameMeta>`] into the statically-typed [`Frame`].
666    ///
667    /// If the usage of the frame is not the same as the expected usage, it will
668    /// return the dynamic frame itself as is.
669    fn try_from(dyn_frame: Frame<dyn AnyFrameMeta>) -> Result<Self, Self::Error> {
670        if (dyn_frame.dyn_meta() as &dyn core::any::Any).is::<M>() {
671            // SAFETY: The metadata is coerceable and the struct is transmutable.
672            Ok(unsafe { core::mem::transmute::<Frame<dyn AnyFrameMeta>, Frame<M>>(dyn_frame) })
673        } else {
674            Err(dyn_frame)
675        }
676    }
677}*/
678/*impl<M: AnyFrameMeta> From<Frame<M>> for Frame<dyn AnyFrameMeta> {
679    fn from(frame: Frame<M>) -> Self {
680        // SAFETY: The metadata is coerceable and the struct is transmutable.
681        unsafe { core::mem::transmute(frame) }
682    }
683}*/
684/*impl<M: AnyUFrameMeta> From<Frame<M>> for UFrame {
685    fn from(frame: Frame<M>) -> Self {
686        // SAFETY: The metadata is coerceable and the struct is transmutable.
687        unsafe { core::mem::transmute(frame) }
688    }
689}*/
690/*impl From<UFrame> for Frame<FrameMeta> {
691    fn from(frame: UFrame) -> Self {
692        // SAFETY: The metadata is coerceable and the struct is transmutable.
693        unsafe { core::mem::transmute(frame) }
694    }
695}*/
696/*impl TryFrom<Frame<FrameMeta>> for UFrame {
697    type Error = Frame<FrameMeta>;
698
699    /// Tries converting a [`Frame<dyn AnyFrameMeta>`] into [`UFrame`].
700    ///
701    /// If the usage of the frame is not the same as the expected usage, it will
702    /// return the dynamic frame itself as is.
703    fn try_from(dyn_frame: Frame<FrameMeta>) -> Result<Self, Self::Error> {
704        if dyn_frame.dyn_meta().is_untyped() {
705            // SAFETY: The metadata is coerceable and the struct is transmutable.
706            Ok(unsafe { core::mem::transmute::<Frame<FrameMeta>, UFrame>(dyn_frame) })
707        } else {
708            Err(dyn_frame)
709        }
710    }
711}*/