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    mem::ManuallyDrop,
54    sync::atomic::{AtomicUsize, Ordering},
55};
56
57//pub use allocator::GlobalFrameAllocator;
58use meta::REF_COUNT_UNUSED;
59pub use segment::Segment;
60
61// Re-export commonly used types
62use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
63pub use frame_ref::FrameRef;
64pub use linked_list::{CursorMut, Link, LinkedList};
65pub use meta::mapping::{
66    frame_to_index, frame_to_index_spec, frame_to_meta, meta_to_frame, META_SLOT_SIZE,
67};
68pub use meta::{AnyFrameMeta, GetFrameError, MetaSlot, MetaSlotStorage, StoredPageTablePageMeta};
69pub use unique::{UniqueFrame, UniqueFrameOwner};
70
71use crate::mm::page_table::{PageTableConfig, PageTablePageMeta};
72
73use vstd_extra::cast_ptr::*;
74use vstd_extra::ownership::*;
75use vstd_extra::undroppable::*;
76
77use crate::mm::{kspace::LINEAR_MAPPING_BASE_VADDR, Paddr, PagingLevel, Vaddr, MAX_PADDR};
78use crate::specs::arch::{
79    kspace::VMALLOC_BASE_VADDR,
80    mm::{MAX_NR_PAGES, PAGE_SIZE},
81};
82use crate::specs::mm::frame::meta_owners::MetaSlotOwner;
83use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
84
85verus! {
86
87/// A permission token for frame metadata.
88///
89/// [`Frame<M>`] the high-level representation of the low-level pointer
90/// to the [`super::meta::MetaSlot`].
91pub type MetaPerm<M> = cast_ptr::PointsTo<MetaSlot, M>;
92
93/// A smart pointer to a frame.
94///
95/// A frame is a contiguous range of bytes in physical memory. The [`Frame`]
96/// type is a smart pointer to a frame that is reference-counted.
97///
98/// Frames are associated with metadata. The type of the metadata `M` is
99/// determines the kind of the frame. If `M` implements [`AnyUFrameMeta`], the
100/// frame is a untyped frame. Otherwise, it is a typed frame.
101#[repr(transparent)]
102#[rustc_has_incoherent_inherent_impls]
103pub struct Frame<M: AnyFrameMeta> {
104    pub ptr: PPtr<MetaSlot>,
105    pub _marker: PhantomData<M>,
106}
107
108impl<M: AnyFrameMeta> Clone for Frame<M> {
109    fn clone(&self) -> Self {
110        Self { ptr: PPtr::<MetaSlot>::from_addr(self.ptr.0), _marker: PhantomData }
111    }
112}
113
114impl<M: AnyFrameMeta> Undroppable for Frame<M> {
115    type State = MetaRegionOwners;
116
117    open spec fn constructor_requires(self, s: Self::State) -> bool {
118        &&& s.slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
119        &&& !s.dropped_slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
120        &&& s.inv()
121    }
122
123    open spec fn constructor_ensures(self, s0: Self::State, s1: Self::State) -> bool {
124        &&& !s1.slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
125        &&& s1.dropped_slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
126        &&& s0.slot_owners == s1.slot_owners
127        &&& forall|i: usize|
128            i != frame_to_index(meta_to_frame(self.ptr.addr())) ==> s0.dropped_slots[i]
129                == s1.dropped_slots[i] && s0.slots[i] == s1.slots[i]
130        &&& s1.dropped_slots[frame_to_index(meta_to_frame(self.ptr.addr()))]
131            == s0.slots[frame_to_index(meta_to_frame(self.ptr.addr()))]
132        &&& s1.inv()
133    }
134
135    proof fn constructor_spec(self, tracked s: &mut Self::State) {
136        let meta_addr = self.ptr.addr();
137        let index = frame_to_index(meta_to_frame(meta_addr));
138        let tracked perm = s.slots.tracked_remove(index);
139        s.dropped_slots.tracked_insert(index, perm);
140    }
141}
142
143impl<M: AnyFrameMeta> cast_ptr::Repr<MetaSlot> for Frame<M> {
144    open spec fn wf(m: MetaSlot) -> bool {
145        true  /* Placeholder */
146
147    }
148
149    open spec fn to_repr_spec(self) -> MetaSlot {
150        arbitrary()  /* Placeholder */
151
152    }
153
154    open spec fn from_repr_spec(r: MetaSlot) -> Self {
155        arbitrary()  /* Placeholder */
156
157    }
158
159    #[verifier::external_body]
160    fn to_repr(self) -> (res: MetaSlot)
161        ensures
162            res == self.to_repr_spec(),
163    {
164        unimplemented!()
165    }
166
167    #[verifier::external_body]
168    fn from_repr(r: MetaSlot) -> (res: Self)
169        ensures
170            res == Self::from_repr_spec(r),
171    {
172        unimplemented!()
173    }
174
175    #[verifier::external_body]
176    fn from_borrowed<'a>(r: &'a MetaSlot) -> (res: &'a Self)
177        ensures
178            *res == Self::from_repr_spec(*r),
179    {
180        unimplemented!()
181    }
182
183    proof fn from_to_repr(self)
184        ensures
185            Self::from_repr(self.to_repr()) == self,
186    {
187        admit();
188    }
189
190    proof fn to_from_repr(r: MetaSlot)
191        ensures
192            Self::from_repr(r).to_repr() == r,
193    {
194        admit();
195    }
196
197    proof fn to_repr_wf(self)
198        ensures
199            Self::wf(self.to_repr()),
200    {
201        admit();
202    }
203}
204
205impl<M: AnyFrameMeta> Inv for Frame<M> {
206    open spec fn inv(self) -> bool {
207        &&& self.ptr.addr() % META_SLOT_SIZE() == 0
208        &&& FRAME_METADATA_RANGE().start <= self.ptr.addr() < FRAME_METADATA_RANGE().start
209            + MAX_NR_PAGES() * META_SLOT_SIZE()
210        &&& self.ptr.addr() < VMALLOC_BASE_VADDR() - LINEAR_MAPPING_BASE_VADDR()
211    }
212}
213
214impl<M: AnyFrameMeta> Frame<M> {
215    pub open spec fn paddr(self) -> usize {
216        meta_to_frame(self.ptr.addr())
217    }
218
219    pub open spec fn index(self) -> usize {
220        frame_to_index(self.paddr())
221    }
222
223    #[verifier::external_body]
224    pub fn meta_pt<'a, C: PageTableConfig>(
225        &'a self,
226        Tracked(p_slot): Tracked<&'a simple_pptr::PointsTo<MetaSlot>>,
227        owner:
228            MetaSlotOwner,
229        //        Tracked(p_inner): Tracked<&'a cell::PointsTo<MetaSlot>>,
230    ) -> (res: &'a PageTablePageMeta<C>)
231        requires
232            self.inv(),
233            p_slot.pptr() == self.ptr,
234            p_slot.is_init(),
235            p_slot.value().wf(owner),
236            is_variant(owner.view().storage.value(), "PTNode"),
237        ensures
238    //            PTNode(*res) == owner.view().storage.value(),
239
240    {
241        let slot = self.ptr.borrow(Tracked(p_slot));
242        unimplemented!()
243        //        slot.storage.borrow(owner.storage)
244
245    }
246}
247
248/*
249unsafe impl<M: AnyFrameMeta + ?Sized> Send for Frame<M> {}
250
251unsafe impl<M: AnyFrameMeta + ?Sized> Sync for Frame<M> {}
252
253impl<M: AnyFrameMeta + ?Sized> core::fmt::Debug for Frame<M> {
254    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
255        write!(f, "Frame({:#x})", self.start_paddr())
256    }
257}
258
259impl<M: AnyFrameMeta + ?Sized> PartialEq for Frame<M> {
260    fn eq(&self, other: &Self) -> bool {
261        self.start_paddr() == other.start_paddr()
262    }
263}
264impl<M: AnyFrameMeta + ?Sized> Eq for Frame<M> {}
265*/
266
267#[verus_verify]
268impl<'a, M: AnyFrameMeta> Frame<M> {
269    #[rustc_allow_incoherent_impl]
270    pub open spec fn from_unused_requires(
271        regions: MetaRegionOwners,
272        paddr: Paddr,
273        metadata: M,
274    ) -> bool {
275        &&& paddr % PAGE_SIZE() == 0
276        &&& paddr < MAX_PADDR()
277        &&& regions.slots.contains_key(frame_to_index(paddr))
278        &&& regions.slot_owners[frame_to_index(paddr)].usage is Unused
279        &&& regions.slot_owners[frame_to_index(paddr)].in_list.points_to(0)
280        &&& regions.slot_owners[frame_to_index(paddr)].self_addr == frame_to_meta(paddr)
281        &&& regions.inv()
282    }
283
284    #[rustc_allow_incoherent_impl]
285    pub open spec fn from_unused_ensures(
286        old_regions: MetaRegionOwners,
287        new_regions: MetaRegionOwners,
288        paddr: Paddr,
289        metadata: M,
290        r: Self,
291    ) -> bool {
292        &&& new_regions@ == MetaSlot::get_from_unused_spec::<M>(
293            paddr,
294            metadata,
295            false,
296            old_regions@,
297        ).1
298        &&& new_regions.inv()
299        &&& forall|paddr: Paddr| #[trigger]
300            old_regions.slots.contains_key(frame_to_index(paddr))
301                ==> new_regions.slots.contains_key(frame_to_index(paddr))
302    }
303
304    /// Gets a [`Frame`] with a specific usage from a raw, unused page.
305    ///
306    /// The caller should provide the initial metadata of the page.
307    ///
308    /// If the provided frame is not truly unused at the moment, it will return
309    /// an error. If wanting to acquire a frame that is already in use, use
310    /// [`Frame::from_in_use`] instead.
311    #[verus_spec(r =>
312        with
313            Tracked(regions): Tracked<&mut MetaRegionOwners>,
314        requires
315            Self::from_unused_requires(*old(regions), paddr, metadata),
316        ensures
317            r matches Ok(r) ==> Self::from_unused_ensures(*old(regions), *regions, paddr, metadata, r),
318    )]
319    #[rustc_allow_incoherent_impl]
320    #[verifier::external_body]
321    pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError> {
322        #[verus_spec(with Tracked(regions))]
323        let from_unused = MetaSlot::get_from_unused(paddr, metadata, false);
324        Ok(Self { ptr: from_unused?, _marker: PhantomData })
325    }
326
327    /// Gets the metadata of this page.
328    #[verus_spec(
329        with Tracked(perm) : Tracked<&'a PointsTo<MetaSlot, M>>,
330        requires
331            self.ptr.addr() == perm.addr(),
332            self.ptr == perm.points_to.pptr(),
333            perm.is_init(),
334            perm.wf(),
335        returns
336            perm.value(),
337    )]
338    #[rustc_allow_incoherent_impl]
339    pub fn meta(&self) -> &'a M {
340        // SAFETY: The type is tracked by the type system.
341        #[verus_spec(with Tracked(&perm.points_to))]
342        let slot = self.slot();
343
344        #[verus_spec(with Tracked(&perm.points_to))]
345        let ptr = slot.as_meta_ptr();
346
347        ptr.borrow(Tracked(perm))
348    }
349}
350
351#[verus_verify]
352impl<M: AnyFrameMeta> Frame<M> {
353    /// Gets a dynamically typed [`Frame`] from a raw, in-use page.
354    ///
355    /// If the provided frame is not in use at the moment, it will return an error.
356    ///
357    /// The returned frame will have an extra reference count to the frame.
358    #[verus_spec(
359        with Tracked(regions) : Tracked<&mut MetaRegionOwners>
360    )]
361    #[rustc_allow_incoherent_impl]
362    pub fn from_in_use(paddr: Paddr) -> Result<Self, GetFrameError> {
363        #[verus_spec(with Tracked(regions))]
364        let from_in_use = MetaSlot::get_from_in_use(paddr);
365        Ok(Self { ptr: from_in_use?, _marker: PhantomData })
366    }
367
368    #[rustc_allow_incoherent_impl]
369    pub open spec fn from_raw_requires(regions: MetaRegionOwners, paddr: Paddr) -> bool {
370        &&& paddr % PAGE_SIZE() == 0
371        //        &&& paddr < MAX_PADDR()
372        &&& !regions.slots.contains_key(frame_to_index(paddr))
373        &&& regions.dropped_slots.contains_key(frame_to_index(paddr))
374        &&& regions.inv()
375    }
376
377    #[rustc_allow_incoherent_impl]
378    pub open spec fn from_raw_ensures(
379        old_regions: MetaRegionOwners,
380        new_regions: MetaRegionOwners,
381        paddr: Paddr,
382        r: Self,
383    ) -> bool {
384        &&& new_regions.inv()
385        &&& new_regions.slots.contains_key(frame_to_index(paddr))
386        &&& !new_regions.dropped_slots.contains_key(frame_to_index(paddr))
387        &&& new_regions.slots[frame_to_index(paddr)] == old_regions.dropped_slots[frame_to_index(
388            paddr,
389        )]
390        &&& forall|i: usize|
391            #![trigger new_regions.slots[i], old_regions.slots[i]]
392            i != frame_to_index(paddr) ==> new_regions.slots[i] == old_regions.slots[i]
393        &&& forall|i: usize|
394            #![trigger new_regions.dropped_slots[i], old_regions.dropped_slots[i]]
395            i != frame_to_index(paddr) ==> new_regions.dropped_slots[i]
396                == old_regions.dropped_slots[i]
397        &&& new_regions.slot_owners == old_regions.slot_owners
398        &&& r.ptr == new_regions.slots[frame_to_index(paddr)].pptr()
399        &&& r.paddr() == paddr
400    }
401
402    #[rustc_allow_incoherent_impl]
403    pub open spec fn into_raw_requires(self, regions: MetaRegionOwners) -> bool {
404        &&& regions.slots.contains_key(self.index())
405        &&& !regions.dropped_slots.contains_key(self.index())
406        &&& regions.inv()
407    }
408
409    #[rustc_allow_incoherent_impl]
410    pub open spec fn into_raw_ensures(
411        self,
412        regions: MetaRegionOwners,
413        r: Paddr,
414        perm: MetaPerm<M>,
415    ) -> bool {
416        &&& r == meta_to_frame(self.ptr.addr())
417        &&& regions.slot_owners == regions.slot_owners
418        &&& regions.dropped_slots == regions.dropped_slots
419        &&& forall|i: usize|
420            #![trigger frame_to_index(self.ptr.addr()), regions.slots[i]]
421            i != frame_to_index(self.ptr.addr()) ==> regions.slots[i] == regions.slots[i]
422    }
423}
424
425#[verus_verify]
426impl<'a, M: AnyFrameMeta> Frame<M> {
427    /// Gets the physical address of the start of the frame.
428    #[verus_spec(
429        with Tracked(perm): Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>
430    )]
431    #[rustc_allow_incoherent_impl]
432    pub fn start_paddr(&self) -> Paddr
433        requires
434            perm.addr() == self.ptr.addr(),
435            perm.is_init(),
436            FRAME_METADATA_RANGE().start <= perm.addr() < FRAME_METADATA_RANGE().end,
437            perm.addr() % META_SLOT_SIZE() == 0,
438        returns
439            meta_to_frame(self.ptr.addr()),
440    {
441        #[verus_spec(with Tracked(perm))]
442        let slot = self.slot();
443
444        #[verus_spec(with Tracked(perm))]
445        slot.frame_paddr()
446    }
447
448    /// Gets the map level of this page.
449    ///
450    /// This is the level of the page table entry that maps the frame,
451    /// which determines the size of the frame.
452    ///
453    /// Currently, the level is always 1, which means the frame is a regular
454    /// page frame.
455    #[rustc_allow_incoherent_impl]
456    pub const fn map_level(&self) -> PagingLevel {
457        1
458    }
459
460    /// Gets the size of this page in bytes.
461    #[rustc_allow_incoherent_impl]
462    pub const fn size(&self) -> usize {
463        PAGE_SIZE()
464    }
465
466    /*    /// Gets the dyncamically-typed metadata of this frame.
467    ///
468    /// If the type is known at compile time, use [`Frame::meta`] instead.
469    pub fn dyn_meta(&self) -> FrameMeta {
470        // SAFETY: The metadata is initialized and valid.
471        unsafe { &*self.slot().dyn_meta_ptr() }
472    }*/
473    /// Gets the reference count of the frame.
474    ///
475    /// It returns the number of all references to the frame, including all the
476    /// existing frame handles ([`Frame`], [`Frame<dyn AnyFrameMeta>`]), and all
477    /// the mappings in the page table that points to the frame.
478    ///
479    /// # Safety
480    ///
481    /// The function is safe to call, but using it requires extra care. The
482    /// reference count can be changed by other threads at any time including
483    /// potentially between calling this method and acting on the result.
484    #[verus_spec(
485        with Tracked(slot_own): Tracked<&mut MetaSlotOwner>,
486            Tracked(slot_perm) : Tracked<& vstd::simple_pptr::PointsTo<MetaSlot>>
487    )]
488    #[rustc_allow_incoherent_impl]
489    pub fn reference_count(&self) -> u64
490        requires
491            slot_perm.pptr() == self.ptr,
492            slot_perm.is_init(),
493            old(slot_own).ref_count.is_for(slot_perm.value().ref_count),
494        returns
495            old(slot_own)@.ref_count,
496    {
497        #[verus_spec(with Tracked(slot_perm))]
498        let slot = self.slot();
499        slot.ref_count.load(Tracked(&slot_own.ref_count))
500    }
501
502    /// Borrows a reference from the given frame.
503    #[rustc_allow_incoherent_impl]
504    #[verus_spec(res =>
505        with Tracked(regions): Tracked<&mut MetaRegionOwners>,
506            Tracked(perm): Tracked<&MetaPerm<M>>,
507        requires
508            old(regions).inv(),
509            self.paddr() % PAGE_SIZE() == 0,
510            self.paddr() < MAX_PADDR(),
511            !old(regions).slots.contains_key(self.index()),
512            perm.points_to.pptr() == self.ptr,
513            perm.is_init(),
514            FRAME_METADATA_RANGE().start <= perm.points_to.addr() < FRAME_METADATA_RANGE().end,
515            perm.points_to.addr() % META_SLOT_SIZE() == 0,
516        ensures
517            regions.inv(),
518            res.inner@.ptr.addr() == self.ptr.addr(),
519    )]
520    #[verifier::external_body]
521    pub fn borrow(&self) -> FrameRef<'a, M> {
522        assert(regions.slot_owners.contains_key(self.index()));
523        // SAFETY: Both the lifetime and the type matches `self`.
524        #[verus_spec(with Tracked(&perm.points_to))]
525        let paddr = self.start_paddr();
526
527        #[verus_spec(with Tracked(regions), Tracked(perm))]
528        FrameRef::borrow_paddr(paddr)
529    }
530
531    /// Forgets the handle to the frame.
532    ///
533    /// This will result in the frame being leaked without calling the custom dropper.
534    ///
535    /// A physical address to the frame is returned in case the frame needs to be
536    /// restored using [`Frame::from_raw`] later. This is useful when some architectural
537    /// data structures need to hold the frame handle such as the page table.
538    #[verus_spec(r =>
539        with
540            Tracked(regions): Tracked<&mut MetaRegionOwners>,
541                -> frame_perm: Tracked<MetaPerm<M>>,
542        requires
543            Self::into_raw_requires(self, *old(regions)),
544        ensures
545            Self::into_raw_ensures(self, *regions, r, frame_perm@),
546    )]
547    #[rustc_allow_incoherent_impl]
548    pub fn into_raw(self) -> Paddr {
549        assert(regions.slots[self.index()].addr() == self.paddr()) by { admit() };
550
551        let tracked owner = regions.slot_owners.tracked_borrow(self.index());
552        let tracked perm = regions.slots.tracked_remove(self.index());
553
554        #[verus_spec(with Tracked(&perm))]
555        let paddr = self.start_paddr();
556
557        let tracked meta_perm = PointsTo::<MetaSlot, M>::new(Ghost(self.ptr.addr()), perm);
558
559        // TODO: implement ManuallyDrop
560        // let this = ManuallyDrop::new(self);
561
562        proof_with!(|= Tracked(meta_perm));
563        paddr
564    }
565
566    /// Restores a forgotten [`Frame`] from a physical address.
567    ///
568    /// # Safety
569    ///
570    /// The caller should only restore a `Frame` that was previously forgotten using
571    /// [`Frame::into_raw`].
572    ///
573    /// And the restoring operation should only be done once for a forgotten
574    /// [`Frame`]. Otherwise double-free will happen.
575    ///
576    /// Also, the caller ensures that the usage of the frame is correct. There's
577    /// no checking of the usage in this function.
578    #[rustc_allow_incoherent_impl]
579    #[verifier::external_body]
580    #[verus_spec(r =>
581        with
582            Tracked(regions): Tracked<&mut MetaRegionOwners>,
583            Tracked(perm): Tracked<&MetaPerm<M>>,
584        requires
585            Self::from_raw_requires(*old(regions), paddr),
586        ensures
587            Self::from_raw_ensures(*old(regions), *regions, paddr, r),
588    )]
589    pub fn from_raw(paddr: Paddr) -> Self {
590        let vaddr = frame_to_meta(paddr);
591        let ptr = PPtr::from_addr(vaddr);
592
593        proof {
594            regions.slots.tracked_insert(frame_to_index(paddr), perm.points_to);
595        }
596
597        Self { ptr, _marker: PhantomData }
598    }
599
600    #[verus_spec(
601        with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
602    )]
603    #[rustc_allow_incoherent_impl]
604    pub fn slot(&self) -> (slot: &'a MetaSlot)
605        requires
606            slot_perm.pptr() == self.ptr,
607            slot_perm.is_init(),
608        returns
609            slot_perm.value(),
610    {
611        // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
612        // mutably borrowed, so taking an immutable reference to it is safe.
613        self.ptr.borrow(Tracked(slot_perm))
614    }
615}
616
617} // verus!
618/*
619impl<M: AnyFrameMeta + ?Sized> Clone for Frame<M> {
620    fn clone(&self) -> Self {
621        // SAFETY: We have already held a reference to the frame.
622        unsafe { self.slot().inc_ref_count() };
623
624        Self {
625            ptr: self.ptr,
626            _marker: PhantomData,
627        }
628    }
629}*/
630/*
631impl<M: AnyFrameMeta + ?Sized> Drop for Frame<M> {
632    fn drop(&mut self) {
633        let last_ref_cnt = self.slot().ref_count.fetch_sub(1, Ordering::Release);
634        debug_assert!(last_ref_cnt != 0 && last_ref_cnt != REF_COUNT_UNUSED);
635
636        if last_ref_cnt == 1 {
637            // A fence is needed here with the same reasons stated in the implementation of
638            // `Arc::drop`: <https://doc.rust-lang.org/std/sync/struct.Arc.html#method.drop>.
639            core::sync::atomic::fence(Ordering::Acquire);
640
641            // SAFETY: this is the last reference and is about to be dropped.
642            unsafe { self.slot().drop_last_in_place() };
643
644            allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
645        }
646    }
647}
648*/
649/*
650impl<M: AnyFrameMeta> TryFrom<Frame<dyn AnyFrameMeta>> for Frame<M> {
651    type Error = Frame<dyn AnyFrameMeta>;
652
653    /// Tries converting a [`Frame<dyn AnyFrameMeta>`] into the statically-typed [`Frame`].
654    ///
655    /// If the usage of the frame is not the same as the expected usage, it will
656    /// return the dynamic frame itself as is.
657    fn try_from(dyn_frame: Frame<dyn AnyFrameMeta>) -> Result<Self, Self::Error> {
658        if (dyn_frame.dyn_meta() as &dyn core::any::Any).is::<M>() {
659            // SAFETY: The metadata is coerceable and the struct is transmutable.
660            Ok(unsafe { core::mem::transmute::<Frame<dyn AnyFrameMeta>, Frame<M>>(dyn_frame) })
661        } else {
662            Err(dyn_frame)
663        }
664    }
665}*/
666/*impl<M: AnyFrameMeta> From<Frame<M>> for Frame<dyn AnyFrameMeta> {
667    fn from(frame: Frame<M>) -> Self {
668        // SAFETY: The metadata is coerceable and the struct is transmutable.
669        unsafe { core::mem::transmute(frame) }
670    }
671}*/
672/*impl<M: AnyUFrameMeta> From<Frame<M>> for UFrame {
673    fn from(frame: Frame<M>) -> Self {
674        // SAFETY: The metadata is coerceable and the struct is transmutable.
675        unsafe { core::mem::transmute(frame) }
676    }
677}*/
678/*impl From<UFrame> for Frame<FrameMeta> {
679    fn from(frame: UFrame) -> Self {
680        // SAFETY: The metadata is coerceable and the struct is transmutable.
681        unsafe { core::mem::transmute(frame) }
682    }
683}*/
684/*impl TryFrom<Frame<FrameMeta>> for UFrame {
685    type Error = Frame<FrameMeta>;
686
687    /// Tries converting a [`Frame<dyn AnyFrameMeta>`] into [`UFrame`].
688    ///
689    /// If the usage of the frame is not the same as the expected usage, it will
690    /// return the dynamic frame itself as is.
691    fn try_from(dyn_frame: Frame<FrameMeta>) -> Result<Self, Self::Error> {
692        if dyn_frame.dyn_meta().is_untyped() {
693            // SAFETY: The metadata is coerceable and the struct is transmutable.
694            Ok(unsafe { core::mem::transmute::<Frame<FrameMeta>, UFrame>(dyn_frame) })
695        } else {
696            Err(dyn_frame)
697        }
698    }
699}*/
700/// Increases the reference count of the frame by one.
701///
702/// # Safety
703///
704/// The caller should ensure the following conditions:
705///  1. The physical address must represent a valid frame;
706///  2. The caller must have already held a reference to the frame.
707#[verifier::external_body]
708pub(in crate::mm) unsafe fn inc_frame_ref_count(paddr: Paddr) {
709    debug_assert!(paddr % PAGE_SIZE() == 0);
710
711    let vaddr: Vaddr = frame_to_meta(paddr);
712    // SAFETY: `vaddr` points to a valid `MetaSlot` that will never be mutably borrowed, so taking
713    // an immutable reference to it is always safe.
714    let slot = unsafe { &*(vaddr as *const MetaSlot) };
715
716    // SAFETY: We have already held a reference to the frame.
717    slot.inc_ref_count();
718}