Skip to main content

ostd/mm/frame/
unique.rs

1// SPDX-License-Identifier: MPL-2.0
2//! The unique frame pointer that is not shared with others.
3use vstd::atomic::PermissionU64;
4use vstd::prelude::*;
5use vstd::simple_pptr::{self, PPtr};
6
7use crate::specs::mm::frame::meta_owners::MetaSlotOwner;
8use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
9
10use vstd_extra::cast_ptr::*;
11use vstd_extra::drop_tracking::*;
12use vstd_extra::ownership::*;
13
14use super::Frame;
15use super::meta::{AnyFrameMeta, GetFrameError, MetaSlot, has_safe_slot};
16
17use core::{marker::PhantomData, sync::atomic::Ordering};
18
19use super::meta::mapping::{
20    META_SLOT_SIZE, frame_to_index, frame_to_meta, max_meta_slots, meta_addr, meta_to_frame,
21};
22use super::meta::{REF_COUNT_UNIQUE, REF_COUNT_UNUSED};
23use crate::mm::frame::MetaPerm;
24use crate::mm::{MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE, Paddr, PagingLevel};
25use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
26use crate::specs::arch::paging_consts::PagingConsts;
27use crate::specs::mm::frame::meta_owners::MetaSlotStorage;
28use crate::specs::mm::frame::meta_owners::Metadata;
29use crate::specs::mm::frame::meta_specs::lemma_meta_addr_to_index;
30use crate::specs::mm::frame::unique::UniqueFrameOwner;
31
32verus! {
33
34pub struct UniqueFrame<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> {
35    pub ptr: PPtr<MetaSlot>,
36    pub _marker: PhantomData<M>,
37}
38
39#[verifier::external]
40unsafe impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + Send> Send for UniqueFrame<M> {
41
42}
43
44#[verifier::external]
45unsafe impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + Sync> Sync for UniqueFrame<M> {
46
47}
48
49/*
50impl<M: AnyFrameMeta + ?Sized> core::fmt::Debug for UniqueFrame<M> {
51    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52        write!(f, "UniqueFrame({:#x})", self.start_paddr())
53    }
54}*/
55
56#[verus_verify]
57impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> UniqueFrame<M> {
58    /// Gets a [`UniqueFrame`] with a specific usage from a raw, unused page.
59    ///
60    /// The caller should provide the initial metadata of the page.
61    /// # Verified Properties
62    /// ## Preconditions
63    /// The page must be unused and the metadata region must be well-formed.
64    /// ## Postconditions
65    /// If the page is valid, the function returns a unique frame.
66    /// ## Safety
67    /// If `paddr` is misaligned or out of bounds, the function will return an error. If it returns a frame,
68    /// it also returns an owner for that frame, indicating that the caller now has exclusive ownership of it.
69    /// See [Safe Encapsulation] for more details.
70    #[verus_spec(res =>
71        with
72            Tracked(regions): Tracked<&mut MetaRegionOwners>,
73                -> owner: Tracked<Option<UniqueFrameOwner<M>>>,
74        requires
75            old(regions).slot_owners.contains_key(frame_to_index(paddr)),
76            old(regions).slot_owners[frame_to_index(paddr)].usage is Unused,
77            old(regions).inv(),
78        ensures
79            !has_safe_slot(paddr) ==> res is Err,
80            res is Ok ==> res.unwrap().wf(owner@.unwrap()),
81            // Creating a live value mints its pending-Drop obligation.
82            res is Ok ==> final(regions).frame_obligations =~= old(
83                regions,
84            ).frame_obligations.insert(frame_to_index(paddr)),
85            res is Err ==> final(regions).frame_obligations =~= old(regions).frame_obligations,
86            final(regions).inv(),
87    )]
88    pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError> {
89        #[verus_spec(with Tracked(regions))]
90        let from_unused = MetaSlot::get_from_unused(paddr, metadata, true);
91
92        if let Err(err) = from_unused {
93            proof_with!(|= Tracked(None));
94            Err(err)
95        } else {
96            let (ptr, Tracked(slot_perm)) = from_unused.unwrap();
97            let ghost idx = frame_to_index(paddr);
98
99            proof_decl! {
100                regions.slots.tracked_insert(idx, slot_perm);
101                let tracked owner = UniqueFrameOwner::<M>::tracked_from_unused_owner(regions, paddr);
102            }
103            proof {
104                // The freshly-created live value owes a Drop: mint it.
105                let tracked _ = regions.tracked_mint_frame_obligation(idx);
106            }
107
108            proof_with!(|= Tracked(Some(owner)));
109            Ok(Self { ptr, _marker: PhantomData })
110        }
111    }
112
113    pub open spec fn transmute_spec<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(
114        self,
115        transmuted: UniqueFrame<M1>,
116    ) -> bool {
117        &&& transmuted.ptr.addr() == self.ptr.addr()
118        &&& transmuted._marker == PhantomData::<M1>
119    }
120
121    #[verifier::external_body]
122    #[verus_spec(res =>
123        ensures
124            Self::transmute_spec(self, res),
125    )]
126    pub fn transmute<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(self) -> UniqueFrame<M1> {
127        unimplemented!()
128    }
129
130    /// Repurposes the frame with a new metadata.
131    /// # Verified Properties
132    /// ## Preconditions
133    /// - The caller must provide a valid owner for the frame, and the metadata region invariants must hold.
134    /// - The meta slot's reference count must be `REF_COUNT_UNIQUE`.
135    /// ## Postconditions
136    /// The function returns a new owner for the frame with the new metadata,
137    /// and the metadata region invariants are preserved.
138    /// ## Safety
139    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
140    /// and represents that the caller has exclusive ownership of the frame.
141    #[verus_spec(res =>
142        with
143            Tracked(owner): Tracked<UniqueFrameOwner<M>>,
144            Tracked(regions): Tracked<&mut MetaRegionOwners>,
145                -> new_owner: Tracked<UniqueFrameOwner<M1>>,
146        requires
147            self.wf(owner),
148            owner.inv(),
149            owner.global_inv(*old(regions)),
150            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].inner_perms.in_list.value() == 0,
151            old(regions).inv(),
152        ensures
153            res.wf(new_owner@),
154            new_owner@.meta_perm_of(*final(regions)).value().metadata == metadata,
155            final(regions).inv(),
156    )]
157    pub fn repurpose<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(
158        self,
159        metadata: M1,
160    ) -> UniqueFrame<M1> {
161        let ghost idx = frame_to_index(meta_to_frame(self.ptr.addr()));
162        proof {
163            lemma_meta_addr_to_index(owner.slot_index);
164        }
165        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
166        let tracked perm_ref = regions.slots.tracked_borrow(idx);
167
168        #[verus_spec(with Tracked(perm_ref))]
169        let slot = self.slot();
170
171        assert(slot_own.inv()) by {
172            assert(old(regions).slot_owners.contains_key(idx));
173            assert(old(regions).slot_owners[idx].inv());
174        }
175
176        // SAFETY: We are the sole owner and the metadata is initialized.
177        unsafe {
178            #[verus_spec(with Tracked(&mut slot_own))]
179            slot.drop_meta_in_place()
180        };
181
182        let tracked mut inner_perms = slot_own.take_inner_perms();
183
184        proof {
185            assert(inner_perms.storage.id() == perm_ref.value().storage.id());
186        }
187
188        let slot = self.ptr.borrow(Tracked(perm_ref));
189
190        unsafe {
191            #[verus_spec(with
192                Tracked(&mut inner_perms.storage),
193                Tracked(&mut inner_perms.vtable_ptr)
194            )]
195            slot.write_meta(metadata)
196        };
197
198        proof {
199            slot_own.sync_inner(&inner_perms);
200            regions.slot_owners.tracked_insert(idx, slot_own);
201        }
202
203        let tracked mut new_owner = UniqueFrameOwner::<M1>::tracked_from_unused_owner(
204            regions,
205            meta_to_frame(self.ptr.addr()),
206        );
207
208        // SAFETY: The metadata is initialized with type `M1`.
209        proof_with!(|= Tracked(new_owner));
210        self.transmute()
211    }
212
213    /// Gets the metadata of this page.
214    /// Note that this function body differs from the original, because `as_meta_ptr` returns
215    /// a `ReprPtr<MetaSlot, Metadata<M>>` instead of a `*M`. So in order to keep the immutable borrow, we
216    /// borrow the metadata value from that pointer.
217    /// # Verified Properties
218    /// ## Preconditions
219    /// The caller must provide a valid owner for the frame.
220    /// ## Postconditions
221    /// The function returns the metadata of the frame.
222    /// ## Safety
223    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
224    /// and represents that the caller has exclusive ownership of the frame.
225    #[verus_spec(l =>
226        with
227            Tracked(owner): Tracked<&'a UniqueFrameOwner<M>>,
228            Tracked(regions): Tracked<&'a MetaRegionOwners>,
229        requires
230            owner.inv(),
231            self.wf(*owner),
232            owner.global_inv(*regions),
233        ensures
234            owner.meta_perm_of(*regions).mem_contents().value().metadata == l,
235    )]
236    pub fn meta<'a>(&self) -> &'a M {
237        let tracked outer = regions.slots.tracked_borrow(owner.slot_index);
238        // SAFETY: The type is tracked by the type system.
239        #[verus_spec(with Tracked(outer))]
240        let slot = self.slot();
241
242        #[verus_spec(with Tracked(outer))]
243        let ptr = slot.as_meta_ptr();
244
245        let tracked tp = regions.borrow_typed_perm::<M>(owner.slot_index);
246        &ptr.borrow(Tracked(tp)).metadata
247    }
248
249    /// Gets the mutable metadata of this page.
250    /// Verified Properties
251    /// ## Preconditions
252    /// The caller must provide a valid owner for the frame.
253    /// ## Postconditions
254    /// The function returns the mutable metadata of the frame.
255    /// ## Safety
256    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
257    /// and represents that the caller has exclusive ownership of the frame. (See [Safe Encapsulation])
258    #[verus_spec(res =>
259        with
260            Tracked(owner): Tracked<&UniqueFrameOwner<M>>,
261            Tracked(regions): Tracked<&MetaRegionOwners>,
262        requires
263            owner.inv(),
264            old(self).wf(*owner),
265            owner.global_inv(*regions),
266        ensures
267            res.addr() == final(self).ptr.addr(),
268            res.ptr.addr() == final(self).ptr.addr(),
269            *final(self) == *old(self),
270    )]
271    pub fn meta_mut(&mut self) -> ReprPtr<MetaSlot, Metadata<M>> {
272        let tracked outer = regions.slots.tracked_borrow(owner.slot_index);
273        // SAFETY: The type is tracked by the type system.
274        // And we have the exclusive access to the metadata.
275        #[verus_spec(with Tracked(outer))]
276        let slot = self.slot();
277
278        #[verus_spec(with Tracked(outer))]
279        slot.as_meta_ptr()
280    }
281}
282
283#[verus_verify]
284impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + ?Sized> UniqueFrame<M> {
285    /// Gets the physical address of the start of the frame.
286    #[verus_spec(
287        with
288            Tracked(owner): Tracked<&UniqueFrameOwner<M>>,
289            Tracked(regions): Tracked<&MetaRegionOwners>,
290        requires
291            owner.inv(),
292            self.wf(*owner),
293            regions.inv(),
294        returns
295            meta_to_frame(self.ptr.addr()),
296    )]
297    pub fn start_paddr(&self) -> Paddr {
298        proof {
299            assert(regions.slot_owners.contains_key(owner.slot_index));
300        }
301        let tracked outer = regions.slots.tracked_borrow(owner.slot_index);
302        #[verus_spec(with Tracked(outer))]
303        let slot = self.slot();
304
305        #[verus_spec(with Tracked(outer))]
306        slot.frame_paddr()
307    }
308
309    /// Gets the paging level of this page.
310    ///
311    /// This is the level of the page table entry that maps the frame,
312    /// which determines the size of the frame.
313    ///
314    /// Currently, the level is always 1, which means the frame is a regular
315    /// page frame.
316    pub const fn level(&self) -> PagingLevel {
317        1
318    }
319
320    /// Gets the size of this page in bytes.
321    pub const fn size(&self) -> usize {
322        PAGE_SIZE
323    }
324
325    /*    /// Gets the dynamically-typed metadata of this frame.
326    ///
327    /// If the type is known at compile time, use [`Frame::meta`] instead.
328
329    #[verifier::external_body]
330    pub fn dyn_meta(&self) -> &M {
331        // SAFETY: The metadata is initialized and valid.
332        unsafe { &*self.slot().dyn_meta_ptr::<M>() }
333    }
334
335    /// Gets the dynamically-typed metadata of this frame.
336    ///
337    /// If the type is known at compile time, use [`Frame::meta`] instead.
338
339    #[verifier::external_body]
340    pub fn dyn_meta_mut(&mut self) -> &mut FrameMeta {
341        // SAFETY: The metadata is initialized and valid. We have the exclusive
342        // access to the frame.
343        unsafe { &mut *self.slot().dyn_meta_ptr() }
344    }*/
345    pub open spec fn into_raw_requires(self, regions: MetaRegionOwners) -> bool {
346        &&& regions.slot_owners.contains_key(
347            frame_to_index(meta_to_frame(self.ptr.addr())),
348        )
349        // `self` is a live value with a pending Drop; forgetting it (`MD::new`)
350        // discharges that obligation.
351        &&& regions.frame_obligations.count(frame_to_index(meta_to_frame(self.ptr.addr()))) > 0
352        &&& regions.inv()
353    }
354
355    pub open spec fn into_raw_ensures(
356        self,
357        old_regions: MetaRegionOwners,
358        regions: MetaRegionOwners,
359        r: Paddr,
360    ) -> bool {
361        &&& r == meta_to_frame(self.ptr.addr())
362        &&& regions.inv()
363        &&& regions.slots =~= old_regions.slots
364        &&& regions.slot_owners =~= old_regions.slot_owners
365        &&& regions.frame_obligations =~= old_regions.frame_obligations.remove(
366            frame_to_index(meta_to_frame(self.ptr.addr())),
367        )
368    }
369
370    /// Resets the frame to unused without up-calling the allocator.
371    ///
372    /// This is solely useful for the allocator implementation/testing and
373    /// is highly experimental. Usage of this function is discouraged.
374    ///
375    /// Usage of this function other than the allocator would actually leak
376    /// the frame since the allocator would not be aware of the frame.
377    //
378    // FIXME: We may have a better `Segment` and `UniqueSegment` design to
379    // allow the allocator hold the ownership of all the frames in a chunk
380    // instead of the head. Then this weird public API can be `#[cfg(ktest)]`.
381    #[verus_spec(
382        with
383            Tracked(owner): Tracked<UniqueFrameOwner<M>>,
384            Tracked(regions): Tracked<&mut MetaRegionOwners>,
385        requires
386            self.wf(owner),
387            owner.inv(),
388            old(regions).inv(),
389            old(regions).slot_owners.contains_key(owner.slot_index),
390            old(regions).slot_owners[owner.slot_index].self_addr == meta_addr(owner.slot_index),
391            old(regions).slot_owners[owner.slot_index].inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
392            old(regions).slot_owners[owner.slot_index].inner_perms.in_list.value() == 0,
393            old(regions).slot_owners[owner.slot_index].inner_perms.storage.is_init(),
394            old(regions).slot_owners[owner.slot_index].inner_perms.vtable_ptr.is_init(),
395            old(regions).slot_owners[owner.slot_index].paths_in_pt.is_empty(),
396        ensures
397            final(regions).inv(),
398    )]
399    pub fn reset_as_unused(self) {
400        let ghost idx = owner.slot_index;
401        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
402        let tracked perm_ref = regions.slots.tracked_borrow(idx);
403
404        #[verus_spec(with Tracked(perm_ref))]
405        let slot = self.slot();
406        slot.ref_count.store(Tracked(&mut slot_own.inner_perms.ref_count), 0);
407
408        // SAFETY: We are the sole owner and the reference count is 0.
409        // The slot is initialized.
410        unsafe {
411            #[verus_spec(with Tracked(&mut slot_own))]
412            slot.drop_last_in_place()
413        };
414
415        proof {
416            regions.slot_owners.tracked_insert(idx, slot_own);
417        }
418    }
419
420    /// Converts this frame into a raw physical address.
421    #[verus_spec(r =>
422        with
423            Tracked(owner): Tracked<&UniqueFrameOwner<M>>,
424            Tracked(regions): Tracked<&mut MetaRegionOwners>,
425        requires
426            Self::into_raw_requires(self, *old(regions)),
427            self.wf(*owner),
428            owner.inv(),
429            old(regions).inv(),
430            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
431        ensures
432            Self::into_raw_ensures(self, *old(regions), *final(regions), r),
433            final(regions).inv(),
434    )]
435    pub(crate) fn into_raw(self) -> Paddr {
436        #[verus_spec(with Tracked(owner), Tracked(&*regions))]
437        let paddr = self.start_paddr();
438
439        // `ManuallyDrop::new` consumes `self`'s pending-Drop obligation; the
440        // caller's `count > 0` precondition guarantees it is outstanding.
441        let _ = ManuallyDrop::new(self, Tracked(regions));
442
443        paddr
444    }
445
446    /// Restores a raw physical address back into a unique frame.
447    ///
448    /// # Safety
449    ///
450    /// The caller must ensure that the physical address is valid and points to
451    /// a forgotten frame that was previously casted by [`Self::into_raw`].
452    #[verus_spec(res =>
453        with
454            Tracked(regions): Tracked<&mut MetaRegionOwners>,
455            Tracked(meta_own): Tracked<M::Owner>,
456        requires
457            paddr < MAX_PADDR,
458            paddr % PAGE_SIZE == 0,
459            old(regions).inv(),
460            old(regions).slot_owners.contains_key(frame_to_index(paddr)),
461            old(regions).slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
462        ensures
463            res.0.ptr.addr() == frame_to_meta(paddr),
464            res.0.wf(res.1@),
465            res.1@.meta_own == meta_own,
466            res.1@.slot_index == frame_to_index(paddr),
467            final(regions).inv(),
468            final(regions).slots == old(regions).slots,
469            // `from_raw` reconstitutes a live value (`slot_owners` unchanged,
470            // `raw_count` dormant) and MINTS its pending-Drop obligation.
471            final(regions).slot_owners =~= old(regions).slot_owners,
472            final(regions).frame_obligations =~= old(regions).frame_obligations.insert(
473                frame_to_index(paddr),
474            ),
475    )]
476    pub(crate) unsafe fn from_raw(paddr: Paddr) -> (Self, Tracked<UniqueFrameOwner<M>>) {
477        let vaddr = frame_to_meta(paddr);
478        let ptr = vstd::simple_pptr::PPtr::<MetaSlot>::from_addr(vaddr);
479
480        proof {
481            // The reconstituted value owes a Drop: mint its obligation.
482            let tracked _ = regions.tracked_mint_frame_obligation(frame_to_index(paddr));
483        }
484
485        let tracked owner = UniqueFrameOwner { meta_own, slot_index: frame_to_index(paddr) };
486
487        (Self { ptr, _marker: PhantomData }, Tracked(owner))
488    }
489
490    #[verifier::external_body]
491    #[verus_spec(
492        with
493            Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>,
494        requires
495            slot_perm.pptr() == self.ptr,
496            slot_perm.is_init(),
497        returns
498            slot_perm.value(),
499    )]
500    pub fn slot<'a>(&self) -> &'a MetaSlot {
501        unimplemented!()
502        // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
503        // mutably borrowed, so taking an immutable reference to it is safe.
504        //        unsafe { &*self.ptr }
505
506    }
507}
508
509/*
510impl<M: AnyFrameMeta + ?Sized> Drop for UniqueFrame<M> {
511    fn drop(&mut self) {
512        self.slot().ref_count.store(0, Ordering::Relaxed);
513        // SAFETY: We are the sole owner and the reference count is 0.
514        // The slot is initialized.
515        unsafe { self.slot().drop_last_in_place() };
516
517        super::allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
518    }
519} */
520
521impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + ?Sized> UniqueFrame<M> {
522    #[verus_spec(
523        with
524            Tracked(owner): Tracked<UniqueFrameOwner<M>>,
525            Tracked(regions): Tracked<&mut MetaRegionOwners>,
526        requires
527            old(self).wf(owner),
528            owner.inv(),
529            old(regions).slot_owners.contains_key(owner.slot_index),
530            old(regions).slot_owners[owner.slot_index].self_addr == meta_addr(owner.slot_index),
531            old(regions).slot_owners[owner.slot_index].inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
532            old(regions).slot_owners[owner.slot_index].inner_perms.in_list.value() == 0,
533            old(regions).slot_owners[owner.slot_index].inner_perms.storage.is_init(),
534            old(regions).slot_owners[owner.slot_index].inner_perms.vtable_ptr.is_init(),
535            old(regions).inv(),
536            old(regions).slot_owners[owner.slot_index].paths_in_pt.is_empty(),
537            old(regions).frame_obligations.count(owner.slot_index) > 0,
538        ensures
539            final(regions).inv(),
540            final(regions).slots =~= old(regions).slots,
541            forall|i: usize| #![trigger final(regions).slot_owners[i]]
542                i != owner.slot_index ==> final(regions).slot_owners[i]
543                    == old(regions).slot_owners[i],
544            final(regions).frame_obligations =~= old(regions).frame_obligations.remove(
545                owner.slot_index,
546            ),
547    )]
548    pub(crate) fn drop(&mut self) {
549        let ghost idx = owner.slot_index;
550
551        proof {
552            // Running `Drop` discharges the value's pending-Drop obligation.
553            let tracked redeem_tok = vstd_extra::drop_tracking::DropObligation::tracked_mint(idx);
554            regions.tracked_redeem_frame_obligation(redeem_tok);
555        }
556
557        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
558        let tracked perm_ref = regions.slots.tracked_borrow(idx);
559
560        // SAFETY: We are the sole owner and the reference count is 0.
561        // The slot is initialized.
562        #[verus_spec(with Tracked(perm_ref))]
563        let slot = self.slot();
564
565        unsafe {
566            #[verus_spec(with Tracked(&mut slot_own))]
567            slot.drop_last_in_place()
568        };
569
570        proof {
571            regions.slot_owners.tracked_insert(idx, slot_own);
572        }
573
574        //        super::allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
575    }
576}
577
578#[verus_verify]
579impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
580    /// Converts a unique frame into a shared one by setting ref_count = 1.
581    /// Inherent sibling of `From<UniqueFrame<M>> for Frame<M>`: freed from
582    /// the trait-signature straitjacket, this version can thread the tracked
583    /// `MetaRegionOwners` via `verus_spec`.
584    #[verus_spec(res =>
585        with
586            Tracked(owner): Tracked<UniqueFrameOwner<M>>,
587            Tracked(regions): Tracked<&mut MetaRegionOwners>,
588        requires
589            unique.wf(owner),
590            owner.inv(),
591            old(regions).inv(),
592        ensures
593            final(regions).slots == old(regions).slots,
594            final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
595    )]
596    pub fn from_unique(unique: UniqueFrame<M>) -> Self {
597        let ghost idx = frame_to_index(meta_to_frame(unique.ptr.addr()));
598        proof {
599            broadcast use crate::mm::frame::meta::mapping::group_page_meta;
600
601            lemma_meta_addr_to_index(owner.slot_index);
602            regions.inv_implies_correct_addr(meta_to_frame(unique.ptr.addr()));
603            assert(idx == owner.slot_index);
604            assert(regions.slots[idx].addr() == unique.ptr.addr());
605            assert(regions.slots[idx].pptr() == unique.ptr);
606        }
607        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
608        let tracked slot_perm = regions.slots.tracked_borrow(idx);
609        let tracked mut inner_perms = slot_own.take_inner_perms();
610
611        #[verus_spec(with Tracked(&slot_perm))]
612        let slot = unique.slot();
613        slot.ref_count.store(Tracked(&mut inner_perms.ref_count), 1);
614
615        proof {
616            slot_own.sync_inner(&inner_perms);
617            regions.slot_owners.tracked_insert(idx, slot_own);
618        }
619
620        // UniqueFrame and Frame have identical layout (ptr + PhantomData),
621        // so reconstructing Frame from unique's ptr preserves the handle.
622        Frame { ptr: unique.ptr, _marker: PhantomData }
623    }
624}
625
626#[verus_verify]
627impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> UniqueFrame<M> {
628    /// Tries to convert a shared frame into a unique one by CAS'ing ref_count
629    /// from 1 to `REF_COUNT_UNIQUE`. Inherent sibling of
630    /// `TryFrom<Frame<M>> for UniqueFrame<M>`.
631    #[verus_spec(res =>
632        with
633            Tracked(regions): Tracked<&mut MetaRegionOwners>,
634        requires
635            frame.inv(),
636            old(regions).inv(),
637        ensures
638            final(regions).slots == old(regions).slots,
639            final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
640    )]
641    pub fn try_from_shared(frame: Frame<M>) -> Result<Self, Frame<M>> {
642        let ghost idx = frame_to_index(meta_to_frame(frame.ptr.addr()));
643        proof {
644            broadcast use crate::mm::frame::meta::mapping::group_page_meta;
645
646            regions.inv_implies_correct_addr(meta_to_frame(frame.ptr.addr()));
647            assert(regions.slots[idx].addr() == frame.ptr.addr());
648            assert(regions.slots[idx].pptr() == frame.ptr);
649        }
650        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
651        let tracked slot_perm = regions.slots.tracked_borrow(idx);
652        let tracked mut inner_perms = slot_own.take_inner_perms();
653
654        #[verus_spec(with Tracked(&slot_perm))]
655        let slot = frame.slot();
656        let res = slot.ref_count.compare_exchange(
657            Tracked(&mut inner_perms.ref_count),
658            1,
659            REF_COUNT_UNIQUE,
660        );
661
662        proof {
663            slot_own.sync_inner(&inner_perms);
664            regions.slot_owners.tracked_insert(idx, slot_own);
665        }
666
667        match res {
668            // Frame and UniqueFrame share layout; construct directly.
669            Ok(_) => Ok(UniqueFrame { ptr: frame.ptr, _marker: PhantomData }),
670            Err(_) => Err(frame),
671        }
672    }
673}
674
675impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> From<UniqueFrame<M>> for Frame<M> {
676    #[verifier::external_body]
677    fn from(unique: UniqueFrame<M>) -> Self {
678        Frame::from_unique(unique)
679    }
680}
681
682impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> TryFrom<Frame<M>> for UniqueFrame<M> {
683    type Error = Frame<M>;
684
685    /// Tries to get a unique frame from a shared frame.
686    ///
687    /// If the reference count is not 1, the frame is returned back.
688    #[verifier::external_body]
689    fn try_from(frame: Frame<M>) -> Result<Self, Self::Error> {
690        UniqueFrame::try_from_shared(frame)
691    }
692}
693
694} // verus!