ostd/specs/mm/frame/
meta_specs.rs1use core::marker::PhantomData;
2
3use vstd::prelude::*;
4
5use vstd::{
6 atomic::*,
7 simple_pptr::{self, PPtr},
8};
9use vstd_extra::{cast_ptr::*, ownership::*};
10
11use crate::specs::{
12 arch::*,
13 mm::frame::{
14 mapping::{frame_to_index, index_to_meta},
15 meta_region_owners::MetaRegionOwners,
16 },
17};
18
19use crate::mm::{
20 Paddr, PagingLevel, Vaddr,
21 frame::{
22 meta::{
23 META_SLOT_SIZE, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
24 mapping::{frame_to_meta, meta_to_frame},
25 },
26 *,
27 },
28 kspace::FRAME_METADATA_RANGE,
29};
30
31use super::meta_owners::{
32 MetaSlotModel, MetaSlotOwner, MetaSlotStatus, MetaSlotStorage, PageUsage,
33};
34
35verus! {
36
37global layout MetaSlot is size == 64, align == 8;
38
39impl MetaSlot {
40 pub proof fn lemma_layout()
41 ensures
42 core::mem::size_of::<MetaSlot>() == META_SLOT_SIZE,
43 vstd::layout::size_of::<MetaSlot>() == META_SLOT_SIZE,
44 {
45 broadcast use VERUS_layout_of_MetaSlot;
46
47 }
48
49 pub open spec fn get_from_unused_owner_spec(as_unique: bool, owner: MetaSlotOwner) -> bool {
50 &&& owner.ref_count() == (if as_unique {
51 REF_COUNT_UNIQUE as u64
52 } else {
53 1u64
54 })
55 &&& owner.in_list_perm.value() == 0
56 &&& owner.storage_perm().is_init()
57 &&& owner.vtable_ptr_perm().is_init()
58 }
59
60 pub open spec fn get_from_unused_spec(
62 paddr: Paddr,
63 as_unique: bool,
64 pre: MetaRegionOwners,
65 post: MetaRegionOwners,
66 ) -> bool {
67 let idx = frame_to_index(paddr);
68 let pre_owner = pre.slot_owners[idx];
69 let post_owner = post.slot_owners[idx];
70 {
71 &&& pre_owner.ref_count() == REF_COUNT_UNUSED
72 &&& MetaSlot::get_from_unused_owner_spec(as_unique, post_owner)
73 &&& post_owner.usage is Frame
74 &&& post_owner.slot_vaddr == pre_owner.slot_vaddr
75 &&& post_owner.paths_in_pt == pre_owner.paths_in_pt
76 &&& post =~= pre.insert_slot_owner(paddr, post_owner)
77 }
78 }
79
80 pub open spec fn get_node_from_unused_spec(
88 paddr: Paddr,
89 pre: MetaRegionOwners,
90 post: MetaRegionOwners,
91 ) -> bool {
92 let idx = frame_to_index(paddr);
93 {
94 &&& post.slot_owners.dom() =~= pre.slot_owners.dom()
95 &&& MetaSlot::get_from_unused_owner_spec(false, post.slot_owners[idx])
96 &&& post.slot_owners[idx].usage is PageTable
97 &&& post.slot_owners[idx].slot_vaddr == pre.slot_owners[idx].slot_vaddr
98 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
99 &&& forall|i: int| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
100 &&& pre.slot_owners[idx].ref_count() == REF_COUNT_UNUSED
101 }
102 }
103
104 pub open spec fn slot_perm_reparked_spec(
107 paddr: Paddr,
108 pre: MetaRegionOwners,
109 post: MetaRegionOwners,
110 ) -> bool {
111 let idx = frame_to_index(paddr);
112 &&& post.slots.dom() =~= pre.slots.dom()
113 &&& forall|k: int|
114 #![trigger post.slots[k]]
115 k != idx && pre.contains(k) ==> post.slots[k] == pre.slots[k]
116 }
117
118 pub open spec fn live_frame_obligations_ok_spec(
124 paddr: Paddr,
125 pre: MetaRegionOwners,
126 post: MetaRegionOwners,
127 ) -> bool {
128 &&& post.frame_obligations =~= pre.frame_obligations.insert(frame_to_index(paddr))
129 }
130
131 pub open spec fn live_frame_obligations_err_spec(
134 pre: MetaRegionOwners,
135 post: MetaRegionOwners,
136 ) -> bool {
137 &&& post.frame_obligations =~= pre.frame_obligations
138 }
139
140 pub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
141 paddr: Paddr,
142 metadata: M,
143 as_unique: bool,
144 ptr: PPtr<MetaSlot>,
145 perm: simple_pptr::PointsTo<MetaSlot>,
146 ) -> bool {
147 &&& ptr.addr() == frame_to_meta(paddr)
148 &&& perm.addr() == frame_to_meta(paddr)
149 &&& perm.is_init()
150 &&& perm.pptr() == ptr
151 }
152
153 pub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool {
154 rc_perm.value() >= REF_COUNT_MAX
155 }
156
157 pub open spec fn frame_paddr_safety_cond(perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
158 &&& FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end
159 &&& perm.addr() % META_SLOT_SIZE == 0
160 }
161
162 pub open spec fn get_from_in_use_success(
163 paddr: Paddr,
164 pre: MetaRegionOwners,
165 post: MetaRegionOwners,
166 ) -> bool {
167 let idx = frame_to_index(paddr);
168 let pre_perms = pre.slot_owners[idx].ref_count();
169 {
170 &&& post.slot_owners[idx].ref_count() == pre_perms + 1
171 &&& post.slot_owners[idx].ref_count_perm.id()
172 == pre.slot_owners[idx].ref_count_perm.id()
173 &&& post.slot_owners[idx].storage_perm() == pre.slot_owners[idx].storage_perm()
174 &&& post.slot_owners[idx].vtable_ptr_perm() == pre.slot_owners[idx].vtable_ptr_perm()
175 &&& post.slot_owners[idx].in_list_perm == pre.slot_owners[idx].in_list_perm
176 &&& post.slot_owners[idx].slot_vaddr == pre.slot_owners[idx].slot_vaddr
177 &&& post.slot_owners[idx].usage == pre.slot_owners[idx].usage
178 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
179 &&& forall|i: int| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
180 }
181 }
182
183 pub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool {
184 &&& (owner.ref_count() == 0 || owner.ref_count() == REF_COUNT_UNIQUE)
185 &&& owner.storage_perm().is_init()
186 &&& owner.in_list_perm.value() == 0
187 &&& owner.paths_in_pt.is_empty()
188 }
189
190 pub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> (MetaSlotModel)
191 recommends
192 pre.status == MetaSlotStatus::SHARED,
193 {
194 MetaSlotModel { ref_count: (pre.ref_count + 1) as u64, ..pre }
195 }
196}
197
198impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
199 pub open spec fn from_raw_spec(paddr: Paddr) -> Self {
200 Frame::<M> {
201 ptr: PPtr::<MetaSlot>(frame_to_meta(paddr), PhantomData),
202 _marker: PhantomData,
203 }
204 }
205}
206
207}