1use vstd::atomic::*;
6use vstd::cell::pcell_maybe_uninit;
7use vstd::prelude::*;
8use vstd::simple_pptr::*;
9
10use vstd_extra::cast_ptr::{self, Repr};
11use vstd_extra::ghost_tree::TreePath;
12use vstd_extra::ownership::*;
13
14use super::*;
15use crate::mm::frame::meta::MetaSlot;
16use crate::mm::frame::AnyFrameMeta;
17use crate::mm::PagingLevel;
18use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
19use crate::specs::arch::mm::NR_ENTRIES;
20use crate::specs::mm::frame::linked_list::linked_list_owners::StoredLink;
21use crate::specs::mm::frame::mapping::META_SLOT_SIZE;
22
23verus! {
24
25#[allow(non_camel_case_types)]
26pub enum MetaSlotStatus {
27 UNUSED,
28 UNIQUE,
29 SHARED,
30 OVERFLOW,
31 UNDER_CONSTRUCTION,
32}
33
34pub enum PageState {
35 Unused,
36 Typed,
37 Untyped,
38}
39
40#[repr(u8)]
41#[derive(Debug, PartialEq, Clone, Copy)]
42pub enum PageUsage {
43 #[allow(dead_code)]
46 Unused,
47 #[allow(dead_code)]
49 Reserved,
50 Frame,
52 PageTable,
54 Meta,
56 Kernel,
58}
59
60impl PageUsage {
61 pub open spec fn as_u8_spec(&self) -> u8 {
62 match self {
63 PageUsage::Unused => 0,
64 PageUsage::Reserved => 1,
65 PageUsage::Frame => 32,
66 PageUsage::PageTable => 64,
67 PageUsage::Meta => 65,
68 PageUsage::Kernel => 66,
69 }
70 }
71
72 #[verifier::external_body]
73 #[verifier::when_used_as_spec(as_u8_spec)]
74 pub fn as_u8(&self) -> (res: u8)
75 ensures
76 res == self.as_u8_spec(),
77 {
78 *self as u8
79 }
80
81 #[vstd::contrib::auto_spec]
82 pub fn as_state(&self) -> (res: PageState) {
83 match &self {
84 PageUsage::Unused => PageState::Unused,
85 PageUsage::Frame => PageState::Untyped,
86 _ => PageState::Typed,
87 }
88 }
89}
90
91pub const REF_COUNT_UNUSED: u64 = u64::MAX;
92
93pub const REF_COUNT_UNIQUE: u64 = u64::MAX - 1;
94
95pub const REF_COUNT_MAX: u64 = i64::MAX as u64;
96
97pub struct StoredPageTablePageMeta {
98 pub nr_children: pcell_maybe_uninit::PCell<u16>,
99 pub stray: pcell_maybe_uninit::PCell<bool>,
100 pub level: PagingLevel,
101 pub lock: PAtomicU8,
102}
103
104pub enum MetaSlotStorage {
105 Empty([u8; 39]),
106 Untyped,
107 FrameLink(StoredLink),
108 PTNode(StoredPageTablePageMeta),
109}
110
111impl AnyFrameMeta for MetaSlotStorage {
115 uninterp spec fn vtable_ptr(&self) -> usize;
116}
117
118impl Repr<MetaSlotStorage> for MetaSlotStorage {
119 type Perm = ();
120
121 open spec fn wf(slot: MetaSlotStorage, perm: ()) -> bool {
122 true
123 }
124
125 open spec fn to_repr_spec(self, perm: ()) -> (MetaSlotStorage, ()) {
126 (self, ())
127 }
128
129 fn to_repr(self, Tracked(perm): Tracked<&mut ()>) -> MetaSlotStorage {
130 self
131 }
132
133 open spec fn from_repr_spec(slot: MetaSlotStorage, perm: ()) -> Self {
134 slot
135 }
136
137 fn from_repr(slot: MetaSlotStorage, Tracked(perm): Tracked<&()>) -> Self {
138 slot
139 }
140
141 fn from_borrowed<'a>(slot: &'a MetaSlotStorage, Tracked(perm): Tracked<&'a ()>) -> &'a Self {
142 slot
143 }
144
145 proof fn from_to_repr(self, perm: ()) {
146 }
147
148 proof fn to_from_repr(slot: MetaSlotStorage, perm: ()) {
149 }
150
151 proof fn to_repr_wf(self, perm: ()) {
152 }
153}
154
155impl MetaSlotStorage {
156 pub open spec fn get_link_spec(self) -> Option<StoredLink> {
157 match self {
158 MetaSlotStorage::FrameLink(link) => Some(link),
159 _ => None,
160 }
161 }
162
163 #[verifier::when_used_as_spec(get_link_spec)]
164 pub fn get_link(self) -> (res: Option<StoredLink>)
165 ensures
166 res == self.get_link_spec(),
167 {
168 match self {
169 MetaSlotStorage::FrameLink(link) => Some(link),
170 _ => None,
171 }
172 }
173
174 pub open spec fn get_node_spec(self) -> Option<StoredPageTablePageMeta> {
175 match self {
176 MetaSlotStorage::PTNode(node) => Some(node),
177 _ => None,
178 }
179 }
180
181 #[verifier::when_used_as_spec(get_node_spec)]
182 pub fn get_node(self) -> (res: Option<StoredPageTablePageMeta>)
183 ensures
184 res == self.get_node_spec(),
185 {
186 match self {
187 MetaSlotStorage::PTNode(node) => Some(node),
188 _ => None,
189 }
190 }
191}
192
193pub tracked struct MetadataInnerPerms {
194 pub storage: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
195 pub ref_count: PermissionU64,
196 pub vtable_ptr: vstd::simple_pptr::PointsTo<usize>,
197 pub in_list: PermissionU64,
198}
199
200pub tracked struct MetaSlotOwner {
201 pub inner_perms: MetadataInnerPerms,
202 pub self_addr: usize,
203 pub usage: PageUsage,
204 pub raw_count: usize,
205 pub ghost paths_in_pt: Set<TreePath<NR_ENTRIES>>,
210}
211
212impl Inv for MetaSlotOwner {
213 open spec fn inv(self) -> bool {
214 &&& self.inner_perms.ref_count.value() == REF_COUNT_UNUSED ==> {
215 &&& self.raw_count == 0
216 &&& self.inner_perms.storage.is_uninit()
217 &&& self.inner_perms.vtable_ptr.is_uninit()
218 &&& self.inner_perms.in_list.value() == 0
219 }
220 &&& self.inner_perms.ref_count.value() == REF_COUNT_UNIQUE ==> {
221 &&& self.inner_perms.vtable_ptr.is_init()
222 &&& self.inner_perms.storage.is_init()
223 &&& self.inner_perms.in_list.value() == 0
224 }
225 &&& 0 < self.inner_perms.ref_count.value() <= REF_COUNT_MAX ==> {
226 &&& self.inner_perms.vtable_ptr.is_init()
227 }
228 &&& REF_COUNT_MAX <= self.inner_perms.ref_count.value() < REF_COUNT_UNIQUE ==> { false }
229 &&& self.inner_perms.ref_count.value() == 0 ==> {
230 &&& self.inner_perms.in_list.value() == 0
231 }
232 &&& FRAME_METADATA_RANGE.start <= self.self_addr < FRAME_METADATA_RANGE.end
233 &&& self.self_addr % META_SLOT_SIZE == 0
234 }
235}
236
237pub ghost struct MetaSlotModel {
238 pub status: MetaSlotStatus,
239 pub storage: MemContents<MetaSlotStorage>,
240 pub ref_count: u64,
241 pub vtable_ptr: MemContents<usize>,
242 pub in_list: u64,
243 pub self_addr: usize,
244 pub usage: PageUsage,
245}
246
247impl Inv for MetaSlotModel {
248 open spec fn inv(self) -> bool {
249 match self.ref_count {
250 REF_COUNT_UNUSED => {
251 &&& self.vtable_ptr.is_uninit()
252 &&& self.in_list == 0
253 },
254 REF_COUNT_UNIQUE => { &&& self.vtable_ptr.is_init() },
255 0 => {
256 &&& self.in_list == 0
257 },
258 _ if self.ref_count < REF_COUNT_MAX => { &&& self.vtable_ptr.is_init() },
259 _ => { false },
260 }
261 }
262}
263
264impl View for MetaSlotOwner {
265 type V = MetaSlotModel;
266
267 open spec fn view(&self) -> Self::V {
268 let storage = self.inner_perms.storage.mem_contents();
269 let ref_count = self.inner_perms.ref_count.value();
270 let vtable_ptr = self.inner_perms.vtable_ptr.mem_contents();
271 let in_list = self.inner_perms.in_list.value();
272 let self_addr = self.self_addr;
273 let usage = self.usage;
274 let status = match ref_count {
275 REF_COUNT_UNUSED => MetaSlotStatus::UNUSED,
276 REF_COUNT_UNIQUE => MetaSlotStatus::UNIQUE,
277 0 => MetaSlotStatus::UNDER_CONSTRUCTION,
278 _ if ref_count < REF_COUNT_MAX => MetaSlotStatus::SHARED,
279 _ => MetaSlotStatus::OVERFLOW,
280 };
281 MetaSlotModel { status, storage, ref_count, vtable_ptr, in_list, self_addr, usage }
282 }
283}
284
285impl InvView for MetaSlotOwner {
286 proof fn view_preserves_inv(self) { }
287}
288
289impl OwnerOf for MetaSlot {
290 type Owner = MetaSlotOwner;
291
292 open spec fn wf(self, owner: Self::Owner) -> bool {
293 &&& self.storage.id() == owner.inner_perms.storage.id()
294 &&& self.ref_count.id() == owner.inner_perms.ref_count.id()
295 &&& self.vtable_ptr == owner.inner_perms.vtable_ptr.pptr()
296 &&& self.in_list.id() == owner.inner_perms.in_list.id()
297 }
298}
299
300impl ModelOf for MetaSlot {
301
302}
303
304impl MetaSlotOwner {
305 pub axiom fn take_inner_perms(tracked &mut self) -> (tracked res: MetadataInnerPerms)
306 ensures
307 res == old(self).inner_perms,
308 final(self).self_addr == old(self).self_addr,
309 final(self).usage == old(self).usage,
310 final(self).raw_count == old(self).raw_count,
311 final(self).paths_in_pt == old(self).paths_in_pt;
312
313 pub axiom fn sync_inner(tracked &mut self, inner_perms: &MetadataInnerPerms)
314 ensures *final(self) == (Self { inner_perms: *inner_perms, ..*old(self) });
315}
316
317pub struct Metadata<M: AnyFrameMeta> {
318 pub metadata: M,
319 pub ref_count: u64,
320 pub vtable_ptr: MemContents<usize>,
321 pub in_list: u64,
322}
323
324impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Metadata<M> {
325 pub uninterp spec fn metadata_from_inner_perms(perm: pcell_maybe_uninit::PointsTo<MetaSlotStorage>) -> M;
329
330 pub uninterp spec fn inner_perms_from_metadata(
334 m: M,
335 base: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
336 ) -> pcell_maybe_uninit::PointsTo<MetaSlotStorage>;
337
338 pub axiom fn metadata_perms_inverse(
342 m: M,
343 base: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
344 )
345 ensures
346 Self::metadata_from_inner_perms(Self::inner_perms_from_metadata(m, base)) == m,
347 Self::inner_perms_from_metadata(m, base).id() == base.id();
348
349 pub axiom fn inner_perms_from_metadata_roundtrip(
350 perm: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
351 )
352 ensures
353 Self::inner_perms_from_metadata(Self::metadata_from_inner_perms(perm), perm) == perm;
354}
355
356pub uninterp spec fn perm_u64_with(p: PermissionU64, v: u64) -> PermissionU64;
362
363pub axiom fn perm_u64_with_value(p: PermissionU64, v: u64)
364 ensures
365 perm_u64_with(p, v).value() == v,
366 perm_u64_with(p, v).id() == p.id();
367
368pub axiom fn perm_u64_with_identity(p: PermissionU64)
370 ensures perm_u64_with(p, p.value()) == p;
371
372pub uninterp spec fn pptr_usize_with(
373 p: vstd::simple_pptr::PointsTo<usize>,
374 c: MemContents<usize>,
375) -> vstd::simple_pptr::PointsTo<usize>;
376
377pub axiom fn pptr_usize_with_value(
378 p: vstd::simple_pptr::PointsTo<usize>,
379 c: MemContents<usize>,
380)
381 ensures
382 pptr_usize_with(p, c).mem_contents() == c,
383 pptr_usize_with(p, c).pptr() == p.pptr();
384
385pub axiom fn pptr_usize_with_identity(p: vstd::simple_pptr::PointsTo<usize>)
387 ensures pptr_usize_with(p, p.mem_contents()) == p;
388
389pub uninterp spec fn meta_slot_from_perm(perm: MetadataInnerPerms) -> MetaSlot;
392
393pub axiom fn meta_slot_from_perm_ids(perm: MetadataInnerPerms)
394 ensures
395 meta_slot_from_perm(perm).storage.id() == perm.storage.id(),
396 meta_slot_from_perm(perm).ref_count.id() == perm.ref_count.id(),
397 meta_slot_from_perm(perm).vtable_ptr == perm.vtable_ptr.pptr(),
398 meta_slot_from_perm(perm).in_list.id() == perm.in_list.id();
399
400pub axiom fn meta_slot_eq_by_ids(a: MetaSlot, b: MetaSlot)
404 ensures
405 (a.storage.id() == b.storage.id()
406 && a.ref_count.id() == b.ref_count.id()
407 && a.vtable_ptr == b.vtable_ptr
408 && a.in_list.id() == b.in_list.id())
409 ==> a == b;
410
411impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Repr<MetaSlot> for Metadata<M> {
412 type Perm = MetadataInnerPerms;
413
414 open spec fn wf(r: MetaSlot, perm: MetadataInnerPerms) -> bool {
415 &&& perm.storage.id() == r.storage.id()
416 &&& perm.ref_count.id() == r.ref_count.id()
417 &&& perm.vtable_ptr.pptr() == r.vtable_ptr
418 &&& perm.in_list.id() == r.in_list.id()
419 }
420
421 open spec fn to_repr_spec(self, perm: MetadataInnerPerms) -> (MetaSlot, MetadataInnerPerms) {
422 let new_perm = MetadataInnerPerms {
423 storage: Self::inner_perms_from_metadata(self.metadata, perm.storage),
424 ref_count: perm_u64_with(perm.ref_count, self.ref_count),
425 vtable_ptr: pptr_usize_with(perm.vtable_ptr, self.vtable_ptr),
426 in_list: perm_u64_with(perm.in_list, self.in_list),
427 };
428 (meta_slot_from_perm(new_perm), new_perm)
429 }
430
431 #[verifier::external_body]
432 fn to_repr(self, Tracked(perm): Tracked<&mut MetadataInnerPerms>) -> MetaSlot {
433 unimplemented!()
434 }
435
436 open spec fn from_repr_spec(r: MetaSlot, perm: MetadataInnerPerms) -> Self {
437 Metadata {
438 metadata: Self::metadata_from_inner_perms(perm.storage),
439 ref_count: perm.ref_count.value(),
440 vtable_ptr: perm.vtable_ptr.mem_contents(),
441 in_list: perm.in_list.value(),
442 }
443 }
444
445 #[verifier::external_body]
446 fn from_repr(r: MetaSlot, Tracked(perm): Tracked<&MetadataInnerPerms>) -> Self {
447 unimplemented!()
448 }
449
450 #[verifier::external_body]
451 fn from_borrowed<'a>(r: &'a MetaSlot, Tracked(perm): Tracked<&'a MetadataInnerPerms>) -> &'a Self {
452 unimplemented!()
453 }
454
455 proof fn from_to_repr(self, perm: MetadataInnerPerms) {
456 Self::metadata_perms_inverse(self.metadata, perm.storage);
457 perm_u64_with_value(perm.ref_count, self.ref_count);
458 perm_u64_with_value(perm.in_list, self.in_list);
459 pptr_usize_with_value(perm.vtable_ptr, self.vtable_ptr);
460 let (r, np) = self.to_repr_spec(perm);
461 assert(Self::from_repr_spec(r, np) =~= self);
462 }
463
464 proof fn to_from_repr(r: MetaSlot, perm: MetadataInnerPerms) {
465 Self::inner_perms_from_metadata_roundtrip(perm.storage);
467 perm_u64_with_identity(perm.ref_count);
468 perm_u64_with_identity(perm.in_list);
469 pptr_usize_with_identity(perm.vtable_ptr);
470 let md = Self::from_repr_spec(r, perm);
479 let (r2, np2) = md.to_repr_spec(perm);
480 assert(np2 =~= perm);
481 meta_slot_from_perm_ids(np2);
483 meta_slot_eq_by_ids(r2, r);
484 assert(r2 == r);
485 }
486
487 proof fn to_repr_wf(self, perm: MetadataInnerPerms) {
488 let (r, np) = self.to_repr_spec(perm);
489 meta_slot_from_perm_ids(np);
490 Self::metadata_perms_inverse(self.metadata, perm.storage);
491 perm_u64_with_value(perm.ref_count, self.ref_count);
492 perm_u64_with_value(perm.in_list, self.in_list);
493 pptr_usize_with_value(perm.vtable_ptr, self.vtable_ptr);
494 }
496}
497
498pub type MetaPerm<M: AnyFrameMeta + Repr<MetaSlotStorage>> = cast_ptr::PointsTo<MetaSlot, Metadata<M>>;
503
504}