1use vstd::prelude::*;
6
7use vstd::{atomic::*, cell::pcell_maybe_uninit, simple_pptr::*};
8use vstd_extra::{
9 cast_ptr::{self, Repr},
10 ghost_tree::TreePath,
11 ownership::*,
12};
13
14use crate::specs::{arch::NR_ENTRIES, mm::frame::linked_list::linked_list_owners::StoredLink};
15
16use crate::mm::{
17 Paddr, PagingLevel, Vaddr,
18 frame::{
19 AnyFrameMeta,
20 meta::{
21 META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
22 mapping::meta_to_frame,
23 },
24 },
25 kspace::FRAME_METADATA_RANGE,
26};
27
28use super::*;
29
30verus! {
31
32#[allow(non_camel_case_types)]
33pub ghost enum MetaSlotStatus {
34 UNUSED,
35 UNIQUE,
36 SHARED,
37 OVERFLOW,
38 UNDER_CONSTRUCTION,
39}
40
41pub ghost enum PageUsage {
42 Unused,
45 Reserved,
47 Frame,
49 PageTable,
51 Meta,
53 Kernel,
55 MMIO,
59}
60
61pub uninterp spec fn is_mmio_paddr(pa: Paddr) -> bool;
66
67pub broadcast axiom fn axiom_mmio_usage_iff_mmio_paddr(slot: MetaSlotOwner)
73 ensures
74 (#[trigger] slot.usage == PageUsage::MMIO) <==> is_mmio_paddr(
75 meta_to_frame(slot.slot_vaddr),
76 ),
77;
78
79pub axiom fn axiom_mmio_paddr_huge_page_closed(pa: Paddr, page_size: usize, offset: usize)
86 requires
87 pa % page_size == 0,
88 offset < page_size,
89 ensures
90 is_mmio_paddr((pa + offset) as Paddr) == is_mmio_paddr(pa),
91;
92
93pub struct StoredPageTablePageMeta {
94 pub nr_children: pcell_maybe_uninit::PCell<u16>,
95 pub stray: pcell_maybe_uninit::PCell<bool>,
96 pub level: PagingLevel,
97 pub lock: PAtomicU8,
98}
99
100pub enum MetaSlotStorage {
101 Empty([u8; 39]),
102 Untyped,
103 FrameLink(StoredLink),
104 PTNode(StoredPageTablePageMeta),
105}
106
107unsafe impl AnyFrameMeta for MetaSlotStorage {
111 uninterp spec fn vtable_ptr(&self) -> usize;
112}
113
114impl Repr<MetaSlotStorage> for MetaSlotStorage {
115 type Perm = ();
116
117 open spec fn wf(slot: MetaSlotStorage, perm: ()) -> bool {
118 true
119 }
120
121 open spec fn to_repr_spec(self, perm: ()) -> (MetaSlotStorage, ()) {
122 (self, ())
123 }
124
125 fn to_repr(self, Tracked(perm): Tracked<&mut ()>) -> MetaSlotStorage {
126 self
127 }
128
129 open spec fn from_repr_spec(slot: MetaSlotStorage, perm: ()) -> Self {
130 slot
131 }
132
133 fn from_repr(slot: MetaSlotStorage, Tracked(perm): Tracked<&()>) -> Self {
134 slot
135 }
136
137 fn from_borrowed<'a>(slot: &'a MetaSlotStorage, Tracked(perm): Tracked<&'a ()>) -> &'a Self {
138 slot
139 }
140
141 proof fn from_to_repr(self, perm: ()) {
142 }
143
144 proof fn to_from_repr(slot: MetaSlotStorage, perm: ()) {
145 }
146
147 proof fn to_repr_wf(self, perm: ()) {
148 }
149}
150
151impl MetaSlotStorage {
152 pub open spec fn get_link_spec(self) -> Option<StoredLink> {
153 match self {
154 MetaSlotStorage::FrameLink(link) => Some(link),
155 _ => None,
156 }
157 }
158
159 #[verifier::when_used_as_spec(get_link_spec)]
160 pub fn get_link(self) -> (res: Option<StoredLink>)
161 ensures
162 res == self.get_link_spec(),
163 {
164 match self {
165 MetaSlotStorage::FrameLink(link) => Some(link),
166 _ => None,
167 }
168 }
169
170 pub open spec fn get_node_spec(self) -> Option<StoredPageTablePageMeta> {
171 match self {
172 MetaSlotStorage::PTNode(node) => Some(node),
173 _ => None,
174 }
175 }
176
177 #[verifier::when_used_as_spec(get_node_spec)]
178 pub fn get_node(self) -> (res: Option<StoredPageTablePageMeta>)
179 ensures
180 res == self.get_node_spec(),
181 {
182 match self {
183 MetaSlotStorage::PTNode(node) => Some(node),
184 _ => None,
185 }
186 }
187}
188
189pub tracked struct MetadataInnerPerms {
190 pub storage: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
191 pub ref_count: PermissionU64,
192 pub vtable_ptr: vstd::simple_pptr::PointsTo<usize>,
193 pub in_list: PermissionU64,
194}
195
196pub tracked struct MetaSlotOwner {
197 pub inner_perms: MetadataInnerPerms,
198 pub ghost slot_vaddr: Vaddr,
199 pub ghost usage: PageUsage,
200 pub ghost paths_in_pt: Set<TreePath<NR_ENTRIES>>,
205}
206
207impl Inv for MetaSlotOwner {
208 open spec fn inv(self) -> bool {
209 &&& self.inner_perms.ref_count.value() == REF_COUNT_UNUSED ==> {
221 &&& self.inner_perms.storage.is_uninit()
222 &&& self.inner_perms.vtable_ptr.is_uninit()
223 &&& self.inner_perms.in_list.value() == 0
224 &&& (self.usage != PageUsage::MMIO ==> self.paths_in_pt.is_empty())
225 }
226 &&& self.inner_perms.ref_count.value() == REF_COUNT_UNIQUE ==> {
227 &&& self.inner_perms.vtable_ptr.is_init()
228 &&& self.inner_perms.storage.is_init()
229 &&& (self.usage != PageUsage::MMIO ==> self.paths_in_pt.is_empty())
234 }
235 &&& 0 < self.inner_perms.ref_count.value() <= REF_COUNT_MAX ==> {
246 &&& self.inner_perms.vtable_ptr.is_init()
247 &&& self.inner_perms.storage.is_init()
248 &&& self.inner_perms.in_list.value() == 0
249 }
250 &&& REF_COUNT_MAX < self.inner_perms.ref_count.value() < REF_COUNT_UNIQUE ==> { false }
251 &&& self.inner_perms.ref_count.value() == 0 ==> {
252 &&& self.inner_perms.in_list.value() == 0
253 }
254 &&& FRAME_METADATA_RANGE.start <= self.slot_vaddr < FRAME_METADATA_RANGE.end
255 &&& self.slot_vaddr % META_SLOT_SIZE == 0
256 }
257}
258
259pub ghost struct MetaSlotModel {
260 pub status: MetaSlotStatus,
261 pub storage: MemContents<MetaSlotStorage>,
262 pub ref_count: u64,
263 pub vtable_ptr: MemContents<usize>,
264 pub in_list: u64,
265 pub slot_vaddr: Vaddr,
266 pub usage: PageUsage,
267}
268
269impl Inv for MetaSlotModel {
270 open spec fn inv(self) -> bool {
271 match self.ref_count {
272 REF_COUNT_UNUSED => {
273 &&& self.vtable_ptr.is_uninit()
274 &&& self.in_list == 0
275 },
276 REF_COUNT_UNIQUE => { &&& self.vtable_ptr.is_init() },
277 0 => { &&& self.in_list == 0 },
278 _ if self.ref_count <= REF_COUNT_MAX => { &&& self.vtable_ptr.is_init() },
279 _ => { false },
280 }
281 }
282}
283
284impl View for MetaSlotOwner {
285 type V = MetaSlotModel;
286
287 open spec fn view(&self) -> Self::V {
288 let storage = self.inner_perms.storage.mem_contents();
289 let ref_count = self.inner_perms.ref_count.value();
290 let vtable_ptr = self.inner_perms.vtable_ptr.mem_contents();
291 let in_list = self.inner_perms.in_list.value();
292 let slot_vaddr = self.slot_vaddr;
293 let usage = self.usage;
294 let status = match ref_count {
295 REF_COUNT_UNUSED => MetaSlotStatus::UNUSED,
296 REF_COUNT_UNIQUE => MetaSlotStatus::UNIQUE,
297 0 => MetaSlotStatus::UNDER_CONSTRUCTION,
298 _ if ref_count <= REF_COUNT_MAX => MetaSlotStatus::SHARED,
299 _ => MetaSlotStatus::OVERFLOW,
300 };
301 MetaSlotModel { status, storage, ref_count, vtable_ptr, in_list, slot_vaddr, usage }
302 }
303}
304
305impl InvView for MetaSlotOwner {
306 proof fn view_preserves_inv(self) {
307 }
308}
309
310impl OwnerOf for MetaSlot {
311 type Owner = MetaSlotOwner;
312
313 open spec fn wf(self, owner: Self::Owner) -> bool {
314 &&& self.storage.id() == owner.inner_perms.storage.id()
315 &&& self.ref_count.id() == owner.inner_perms.ref_count.id()
316 &&& self.vtable_ptr == owner.inner_perms.vtable_ptr.pptr()
317 &&& self.in_list.id() == owner.inner_perms.in_list.id()
318 }
319}
320
321impl MetaSlotOwner {
322 pub proof fn tracked_borrow_mut_inner_perms(tracked &mut self) -> (tracked res:
323 &mut MetadataInnerPerms)
324 ensures
325 *res == old(self).inner_perms,
326 *final(self) == (Self { inner_perms: *final(res), ..*old(self) }),
327 {
328 &mut self.inner_perms
329 }
330}
331
332pub struct Metadata<M: AnyFrameMeta + Repr<MetaSlotStorage>> {
333 pub metadata: M,
334 pub ref_count: u64,
335 pub vtable_ptr: MemContents<usize>,
336 pub in_list: u64,
337}
338
339impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Metadata<M> {
340 pub uninterp spec fn metadata_from_inner_perms(
344 perm: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
345 ) -> M;
346
347 pub uninterp spec fn inner_perms_from_metadata(
351 m: M,
352 base: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
353 ) -> pcell_maybe_uninit::PointsTo<MetaSlotStorage>;
354
355 pub axiom fn metadata_perms_inverse(m: M, base: pcell_maybe_uninit::PointsTo<MetaSlotStorage>)
359 ensures
360 Self::metadata_from_inner_perms(Self::inner_perms_from_metadata(m, base)) == m,
361 Self::inner_perms_from_metadata(m, base).id() == base.id(),
362 Self::inner_perms_from_metadata(m, base).is_init(),
363 ;
364
365 pub axiom fn inner_perms_from_metadata_roundtrip(
366 perm: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
367 )
368 ensures
369 Self::inner_perms_from_metadata(Self::metadata_from_inner_perms(perm), perm) == perm,
370 ;
371
372 #[verifier::external_body]
380 pub proof fn switch_perm_to_inner_perms_from_metadata(
381 tracked perm: &mut pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
382 m: M,
383 )
384 requires
385 old(perm).is_init(),
386 ensures
387 *final(perm) == Self::inner_perms_from_metadata(m, *old(perm)),
388 {
389 }
390
391 pub exec fn write_metadata_into_storage(
395 cell: &pcell_maybe_uninit::PCell<MetaSlotStorage>,
396 Tracked(perm): Tracked<&mut pcell_maybe_uninit::PointsTo<MetaSlotStorage>>,
397 metadata: M,
398 )
399 requires
400 cell.id() == old(perm).id(),
401 ensures
402 final(perm).id() == old(perm).id(),
403 final(perm).is_init(),
404 Self::metadata_from_inner_perms(*final(perm)) == metadata,
405 {
406 cell.write(Tracked(perm), MetaSlotStorage::Untyped);
410 proof {
411 let ghost base = *perm;
412 Self::switch_perm_to_inner_perms_from_metadata(perm, metadata);
413 Self::metadata_perms_inverse(metadata, base);
414 }
415 }
416}
417
418pub uninterp spec fn perm_u64_with(p: PermissionU64, v: u64) -> PermissionU64;
424
425pub axiom fn perm_u64_with_value(p: PermissionU64, v: u64)
426 ensures
427 perm_u64_with(p, v).value() == v,
428 perm_u64_with(p, v).id() == p.id(),
429;
430
431pub axiom fn perm_u64_with_identity(p: PermissionU64)
433 ensures
434 perm_u64_with(p, p.value()) == p,
435;
436
437pub uninterp spec fn pptr_usize_with(
438 p: vstd::simple_pptr::PointsTo<usize>,
439 c: MemContents<usize>,
440) -> vstd::simple_pptr::PointsTo<usize>;
441
442pub axiom fn pptr_usize_with_value(p: vstd::simple_pptr::PointsTo<usize>, c: MemContents<usize>)
443 ensures
444 pptr_usize_with(p, c).mem_contents() == c,
445 pptr_usize_with(p, c).pptr() == p.pptr(),
446;
447
448pub axiom fn pptr_usize_with_identity(p: vstd::simple_pptr::PointsTo<usize>)
450 ensures
451 pptr_usize_with(p, p.mem_contents()) == p,
452;
453
454pub uninterp spec fn meta_slot_from_perm(perm: MetadataInnerPerms) -> MetaSlot;
457
458pub axiom fn meta_slot_from_perm_ids(perm: MetadataInnerPerms)
459 ensures
460 meta_slot_from_perm(perm).storage.id() == perm.storage.id(),
461 meta_slot_from_perm(perm).ref_count.id() == perm.ref_count.id(),
462 meta_slot_from_perm(perm).vtable_ptr == perm.vtable_ptr.pptr(),
463 meta_slot_from_perm(perm).in_list.id() == perm.in_list.id(),
464;
465
466pub axiom fn meta_slot_eq_by_ids(a: MetaSlot, b: MetaSlot)
470 ensures
471 (a.storage.id() == b.storage.id() && a.ref_count.id() == b.ref_count.id() && a.vtable_ptr
472 == b.vtable_ptr && a.in_list.id() == b.in_list.id()) ==> a == b,
473;
474
475impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Repr<MetaSlot> for Metadata<M> {
476 type Perm = MetadataInnerPerms;
477
478 open spec fn wf(r: MetaSlot, perm: MetadataInnerPerms) -> bool {
479 &&& perm.storage.id() == r.storage.id()
480 &&& perm.ref_count.id() == r.ref_count.id()
481 &&& perm.vtable_ptr.pptr() == r.vtable_ptr
482 &&& perm.in_list.id() == r.in_list.id()
483 }
484
485 open spec fn to_repr_spec(self, perm: MetadataInnerPerms) -> (MetaSlot, MetadataInnerPerms) {
486 let new_perm = MetadataInnerPerms {
487 storage: Self::inner_perms_from_metadata(self.metadata, perm.storage),
488 ref_count: perm_u64_with(perm.ref_count, self.ref_count),
489 vtable_ptr: pptr_usize_with(perm.vtable_ptr, self.vtable_ptr),
490 in_list: perm_u64_with(perm.in_list, self.in_list),
491 };
492 (meta_slot_from_perm(new_perm), new_perm)
493 }
494
495 #[verifier::external_body]
496 fn to_repr(self, Tracked(perm): Tracked<&mut MetadataInnerPerms>) -> MetaSlot {
497 unimplemented!()
498 }
499
500 open spec fn from_repr_spec(r: MetaSlot, perm: MetadataInnerPerms) -> Self {
501 Metadata {
502 metadata: Self::metadata_from_inner_perms(perm.storage),
503 ref_count: perm.ref_count.value(),
504 vtable_ptr: perm.vtable_ptr.mem_contents(),
505 in_list: perm.in_list.value(),
506 }
507 }
508
509 #[verifier::external_body]
510 fn from_repr(r: MetaSlot, Tracked(perm): Tracked<&MetadataInnerPerms>) -> Self {
511 unimplemented!()
512 }
513
514 #[verifier::external_body]
515 fn from_borrowed<'a>(
516 r: &'a MetaSlot,
517 Tracked(perm): Tracked<&'a MetadataInnerPerms>,
518 ) -> &'a Self {
519 unimplemented!()
520 }
521
522 proof fn from_to_repr(self, perm: MetadataInnerPerms) {
523 Self::metadata_perms_inverse(self.metadata, perm.storage);
524 perm_u64_with_value(perm.ref_count, self.ref_count);
525 perm_u64_with_value(perm.in_list, self.in_list);
526 pptr_usize_with_value(perm.vtable_ptr, self.vtable_ptr);
527 let (r, np) = self.to_repr_spec(perm);
528 }
529
530 proof fn to_from_repr(r: MetaSlot, perm: MetadataInnerPerms) {
531 Self::inner_perms_from_metadata_roundtrip(perm.storage);
533 perm_u64_with_identity(perm.ref_count);
534 perm_u64_with_identity(perm.in_list);
535 pptr_usize_with_identity(perm.vtable_ptr);
536 let md = Self::from_repr_spec(r, perm);
545 let (r2, np2) = md.to_repr_spec(perm);
546 meta_slot_from_perm_ids(np2);
548 meta_slot_eq_by_ids(r2, r);
549 }
550
551 proof fn to_repr_wf(self, perm: MetadataInnerPerms) {
552 let (r, np) = self.to_repr_spec(perm);
553 meta_slot_from_perm_ids(np);
554 Self::metadata_perms_inverse(self.metadata, perm.storage);
555 perm_u64_with_value(perm.ref_count, self.ref_count);
556 perm_u64_with_value(perm.in_list, self.in_list);
557 pptr_usize_with_value(perm.vtable_ptr, self.vtable_ptr);
558 }
560}
561
562pub type MetaPerm<M > =
567 cast_ptr::PointsTo<MetaSlot, Metadata<M>>;
568
569}