1use 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#[verus_verify]
57impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> UniqueFrame<M> {
58 #[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 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 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 #[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 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 proof_with!(|= Tracked(new_owner));
210 self.transmute()
211 }
212
213 #[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 #[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 #[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 #[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 #[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 pub const fn level(&self) -> PagingLevel {
317 1
318 }
319
320 pub const fn size(&self) -> usize {
322 PAGE_SIZE
323 }
324
325 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 &&& 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 #[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 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 #[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 let _ = ManuallyDrop::new(self, Tracked(regions));
442
443 paddr
444 }
445
446 #[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 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 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 }
507}
508
509impl<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 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 #[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 }
576}
577
578#[verus_verify]
579impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
580 #[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 Frame { ptr: unique.ptr, _marker: PhantomData }
623 }
624}
625
626#[verus_verify]
627impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> UniqueFrame<M> {
628 #[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 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 #[verifier::external_body]
689 fn try_from(frame: Frame<M>) -> Result<Self, Self::Error> {
690 UniqueFrame::try_from_shared(frame)
691 }
692}
693
694}