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