ostd/specs/mm/frame/
meta_specs.rs1use 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 REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED, get_slot_spec,
15 mapping::{
16 frame_to_index, frame_to_meta, frame_to_meta_spec, index_to_frame,
17 lemma_paddr_to_meta_biinjective, meta_addr, meta_to_frame_spec,
18 },
19};
20use crate::mm::frame::*;
21use crate::mm::{Paddr, PagingLevel, Vaddr};
22use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
23use crate::specs::arch::mm::{MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
24use crate::specs::mm::frame::meta_owners::MetadataInnerPerms;
25use crate::specs::mm::frame::meta_region_owners::{MetaRegionModel, MetaRegionOwners};
26
27use core::marker::PhantomData;
28
29verus! {
30
31impl MetaSlot {
32 #[verus_spec(res =>
34 with
35 Tracked(perm): Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>,
36 requires
37 perm.value() == self,
38 addr == perm.addr(),
39 ensures
40 res.ptr.addr() == addr,
41 res.addr() == addr,
42 )]
43 pub fn cast_slot<M: AnyFrameMeta + Repr<MetaSlotStorage>>(&self, addr: usize) -> ReprPtr<
44 MetaSlot,
45 Metadata<M>,
46 > {
47 ReprPtr::<MetaSlot, Metadata<M>> { ptr: PPtr::from_addr(addr), _T: PhantomData }
48 }
49
50 pub open spec fn get_from_unused_inner_perms_spec(
51 as_unique: bool,
52 perms: MetadataInnerPerms,
53 ) -> bool {
54 &&& perms.ref_count.value() == (if as_unique {
55 REF_COUNT_UNIQUE as u64
56 } else {
57 1u64
58 })
59 &&& perms.in_list.value() == 0
60 &&& perms.storage.is_init()
61 &&& perms.vtable_ptr.is_init()
62 }
63
64 pub open spec fn get_from_unused_spec(
70 paddr: Paddr,
71 as_unique: bool,
72 pre: MetaRegionOwners,
73 post: MetaRegionOwners,
74 ) -> bool
75 recommends
76 paddr % PAGE_SIZE == 0,
77 paddr < MAX_PADDR,
78 pre.inv(),
79 {
80 let idx = frame_to_index(paddr);
81 {
82 &&& post.slot_owners.dom() =~= pre.slot_owners.dom()
83 &&& MetaSlot::get_from_unused_inner_perms_spec(
84 as_unique,
85 post.slot_owners[idx].inner_perms,
86 )
87 &&& post.slot_owners[idx].usage == PageUsage::Frame
88 &&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
89 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
90 &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
91 &&& pre.slot_owners[idx].inner_perms.ref_count.value()
92 == REF_COUNT_UNUSED
93 }
97 }
98
99 pub open spec fn slot_perm_extracted_spec(
103 paddr: Paddr,
104 pre: MetaRegionOwners,
105 post: MetaRegionOwners,
106 ) -> bool {
107 post.slots =~= pre.slots.remove(frame_to_index(paddr))
108 }
109
110 pub open spec fn slot_perm_reparked_spec(
117 paddr: Paddr,
118 pre: MetaRegionOwners,
119 post: MetaRegionOwners,
120 ) -> bool {
121 let idx = frame_to_index(paddr);
122 &&& post.slots.dom() =~= pre.slots.dom()
123 &&& forall|k: usize|
124 #![trigger post.slots[k]]
125 k != idx && pre.slots.contains_key(k) ==> post.slots[k] == pre.slots[k]
126 }
127
128 pub open spec fn live_frame_obligations_ok_spec(
134 paddr: Paddr,
135 pre: MetaRegionOwners,
136 post: MetaRegionOwners,
137 ) -> bool {
138 &&& post.frame_obligations =~= pre.frame_obligations.insert(frame_to_index(paddr))
139 }
140
141 pub open spec fn live_frame_obligations_err_spec(
144 pre: MetaRegionOwners,
145 post: MetaRegionOwners,
146 ) -> bool {
147 &&& post.frame_obligations =~= pre.frame_obligations
148 }
149
150 pub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
151 paddr: Paddr,
152 metadata: M,
153 as_unique: bool,
154 ptr: PPtr<MetaSlot>,
155 perm: simple_pptr::PointsTo<MetaSlot>,
156 ) -> bool {
157 &&& ptr.addr() == frame_to_meta(paddr)
158 &&& perm.addr() == frame_to_meta(paddr)
159 &&& perm.is_init()
160 &&& perm.pptr() == ptr
161 }
162
163 pub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool {
164 rc_perm.value() >= REF_COUNT_MAX
165 }
166
167 pub open spec fn frame_paddr_safety_cond(perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
168 &&& FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end
169 &&& perm.addr() % META_SLOT_SIZE == 0
170 }
171
172 pub open spec fn get_from_in_use_panic_cond(paddr: Paddr, regions: MetaRegionOwners) -> bool {
173 let idx = frame_to_index(paddr);
174 let pre_perms = regions.slot_owners[idx].inner_perms.ref_count.value();
175 pre_perms + 1 >= REF_COUNT_MAX
176 }
177
178 pub open spec fn get_from_in_use_success(
179 paddr: Paddr,
180 pre: MetaRegionOwners,
181 post: MetaRegionOwners,
182 ) -> bool
183 recommends
184 paddr % PAGE_SIZE == 0,
185 paddr < MAX_PADDR,
186 pre.inv(),
187 {
188 let idx = frame_to_index(paddr);
189 let pre_perms = pre.slot_owners[idx].inner_perms.ref_count.value();
190 {
191 &&& post.slot_owners[idx].inner_perms.ref_count.value() == pre_perms + 1
192 &&& post.slot_owners[idx].inner_perms.ref_count.id()
193 == pre.slot_owners[idx].inner_perms.ref_count.id()
194 &&& post.slot_owners[idx].inner_perms.storage
195 == pre.slot_owners[idx].inner_perms.storage
196 &&& post.slot_owners[idx].inner_perms.vtable_ptr
197 == pre.slot_owners[idx].inner_perms.vtable_ptr
198 &&& post.slot_owners[idx].inner_perms.in_list
199 == pre.slot_owners[idx].inner_perms.in_list
200 &&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
201 &&& post.slot_owners[idx].usage == pre.slot_owners[idx].usage
202 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
203 &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
204 }
205 }
206
207 pub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool {
208 &&& (owner.inner_perms.ref_count.value() == 0 || owner.inner_perms.ref_count.value()
209 == REF_COUNT_UNIQUE)
210 &&& owner.inner_perms.storage.is_init()
211 &&& owner.inner_perms.in_list.value()
212 == 0
213 &&& owner.paths_in_pt.is_empty()
221 }
222
223 pub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> (MetaSlotModel)
224 recommends
225 pre.inv(),
226 pre.status == MetaSlotStatus::SHARED,
227 {
228 MetaSlotModel { ref_count: (pre.ref_count + 1) as u64, ..pre }
229 }
230}
231
232impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
233 pub open spec fn from_raw_spec(paddr: Paddr) -> Self {
234 Frame::<M> {
235 ptr: PPtr::<MetaSlot>(frame_to_meta(paddr), PhantomData),
236 _marker: PhantomData,
237 }
238 }
239}
240
241pub broadcast proof fn lemma_meta_addr_to_index(i: usize)
248 requires
249 i < MAX_NR_PAGES,
250 ensures
251 #[trigger] frame_to_index(meta_to_frame_spec(meta_addr(i))) == i,
252{
253 assert(MAX_NR_PAGES == 0x80000 && PAGE_SIZE == 4096 && MAX_PADDR == 0x8000_0000
254 && META_SLOT_SIZE == 64) by (compute_only);
255
256 let p = index_to_frame(i);
257 assert(i * PAGE_SIZE < MAX_PADDR) by (nonlinear_arith)
258 requires
259 i < 0x80000,
260 PAGE_SIZE == 4096,
261 MAX_PADDR == 0x8000_0000,
262 ;
263 assert(p == i * PAGE_SIZE);
264 assert(p % PAGE_SIZE == 0) by (nonlinear_arith)
265 requires
266 p == i * PAGE_SIZE,
267 PAGE_SIZE == 4096,
268 ;
269 assert(p / PAGE_SIZE == i) by (nonlinear_arith)
270 requires
271 p == i * PAGE_SIZE,
272 PAGE_SIZE == 4096,
273 ;
274 assert(meta_addr(i) == frame_to_meta_spec(p));
276 lemma_paddr_to_meta_biinjective(p);
278 assert(meta_to_frame_spec(meta_addr(i)) == p);
279 assert(frame_to_index(p) == i);
280}
281
282}