ostd/specs/mm/frame/
meta_specs.rs

1use vstd::atomic::*;
2use vstd::atomic::*;
3use vstd::cell;
4use vstd::prelude::*;
5use vstd::simple_pptr::{self, PPtr};
6
7use vstd_extra::cast_ptr::*;
8use vstd_extra::ownership::*;
9
10use super::meta_owners::{
11    MetaSlotModel, MetaSlotOwner, MetaSlotStatus, MetaSlotStorage, Metadata, PageUsage,
12};
13use crate::mm::frame::meta::{
14    get_slot_spec,
15    mapping::{frame_to_index, frame_to_meta},
16    REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
17};
18use crate::mm::frame::*;
19use crate::mm::{Paddr, PagingLevel, Vaddr};
20use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
21use crate::specs::arch::mm::{MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
22use crate::specs::mm::frame::meta_owners::MetadataInnerPerms;
23use crate::specs::mm::frame::meta_region_owners::{MetaRegionModel, MetaRegionOwners};
24
25use core::marker::PhantomData;
26
27verus! {
28
29impl MetaSlot {
30
31    pub open spec fn get_from_unused_inner_perms_spec(as_unique: bool, perms: MetadataInnerPerms) -> bool
32    {
33        &&& perms.ref_count.value() == (if as_unique { REF_COUNT_UNIQUE as u64 } else { 1u64 })
34        &&& perms.in_list.value() == 0
35        &&& perms.storage.is_init()
36        &&& perms.vtable_ptr.is_init()
37    }
38
39    pub open spec fn get_from_unused_spec(
40        paddr: Paddr,
41        as_unique: bool,
42        pre: MetaRegionOwners,
43        post: MetaRegionOwners,
44    ) -> bool
45        recommends
46            paddr % PAGE_SIZE == 0,
47            paddr < MAX_PADDR,
48            pre.inv(),
49    {
50        let idx = frame_to_index(paddr);
51        {
52            &&& post.slots =~= pre.slots.remove(idx)
53            &&& MetaSlot::get_from_unused_inner_perms_spec(as_unique, post.slot_owners[idx].inner_perms)
54            &&& post.slot_owners[idx].usage == PageUsage::Frame
55            &&& post.slot_owners[idx].raw_count == pre.slot_owners[idx].raw_count
56            &&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
57            &&& post.slot_owners[idx].path_if_in_pt == pre.slot_owners[idx].path_if_in_pt
58            &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
59        }
60    }
61
62    pub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
63        paddr: Paddr,
64        metadata: M,
65        as_unique: bool,
66        ptr: PPtr<MetaSlot>,
67        perm: PointsTo<MetaSlot, Metadata<M>>,
68    ) -> bool {
69        &&& ptr.addr() == frame_to_meta(paddr)
70        &&& perm.addr() == frame_to_meta(paddr)
71        &&& MetaSlot::get_from_unused_inner_perms_spec(as_unique, perm.inner_perms)
72    }
73
74    pub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool {
75        rc_perm.value() >= REF_COUNT_MAX
76    }
77
78    pub open spec fn frame_paddr_safety_cond(perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
79        &&& FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end
80        &&& perm.addr() % META_SLOT_SIZE == 0
81    }
82
83    pub open spec fn get_from_in_use_panic_cond(paddr: Paddr, regions: MetaRegionOwners) -> bool {
84        let idx = frame_to_index(paddr);
85        let pre_perms = regions.slot_owners[idx].inner_perms.ref_count.value();
86        pre_perms + 1 >= REF_COUNT_MAX
87    }
88
89    pub open spec fn get_from_in_use_success(paddr: Paddr, pre: MetaRegionOwners, post: MetaRegionOwners) -> bool
90        recommends
91            paddr % PAGE_SIZE == 0,
92            paddr < MAX_PADDR,
93            pre.inv(),
94    {
95        let idx = frame_to_index(paddr);
96        let pre_perms = pre.slot_owners[idx].inner_perms.ref_count.value();
97        {
98            &&& post.slot_owners[idx].inner_perms.ref_count.value() == pre_perms + 1
99            &&& post.slot_owners[idx].inner_perms.ref_count.id() == pre.slot_owners[idx].inner_perms.ref_count.id()
100            &&& post.slot_owners[idx].inner_perms.storage == pre.slot_owners[idx].inner_perms.storage
101            &&& post.slot_owners[idx].inner_perms.vtable_ptr == pre.slot_owners[idx].inner_perms.vtable_ptr
102            &&& post.slot_owners[idx].inner_perms.in_list == pre.slot_owners[idx].inner_perms.in_list
103            &&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
104            &&& post.slot_owners[idx].usage == pre.slot_owners[idx].usage
105            &&& post.slot_owners[idx].raw_count == pre.slot_owners[idx].raw_count
106            &&& post.slot_owners[idx].path_if_in_pt == pre.slot_owners[idx].path_if_in_pt
107            &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
108        }
109    }
110
111    pub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool {
112        &&& (owner.inner_perms.ref_count.value() == 0
113            || owner.inner_perms.ref_count.value() == REF_COUNT_UNIQUE)
114        &&& owner.inner_perms.storage.is_init()
115        &&& owner.inner_perms.in_list.value() == 0
116        &&& owner.raw_count == 0
117    }
118
119    pub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> (MetaSlotModel)
120        recommends
121            pre.inv(),
122            pre.status == MetaSlotStatus::SHARED,
123    {
124        MetaSlotModel { ref_count: (pre.ref_count + 1) as u64, ..pre }
125    }
126}
127
128impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
129    pub open spec fn from_raw_spec(paddr: Paddr) -> Self {
130        Frame::<M> {
131            ptr: PPtr::<MetaSlot>(frame_to_meta(paddr), PhantomData),
132            _marker: PhantomData,
133        }
134    }
135}
136
137} // verus!