1use core::marker::PhantomData;
2
3use vstd::prelude::*;
4
5use vstd::{modes::tracked_swap, simple_pptr::PointsTo};
6use vstd_extra::{ghost_tree::*, ownership::*};
7
8use crate::specs::{
9 arch::*,
10 mm::{
11 frame::{
12 mapping::{frame_to_index, index_to_meta, meta_to_index},
13 meta_owners::PageUsage,
14 meta_region_owners::MetaRegionOwners,
15 },
16 page_table::{node::entry_view::*, *},
17 },
18};
19
20use crate::arch::mm::PagingConsts;
21use crate::mm::{
22 Paddr, PagingConstsTrait, PagingLevel, Vaddr,
23 frame::meta::{
24 MetaSlot, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED, mapping::meta_to_frame,
25 },
26 page_prop::PageProperty,
27 page_table::*,
28};
29
30verus! {
31
32pub ghost struct FrameEntryState {
38 pub mapped_pa: usize,
39 pub prop: PageProperty,
40}
41
42pub tracked enum EntryOwnerKind<C: PageTableConfig> {
43 Node(NodeOwner<C>),
44 Frame(ghost FrameEntryState),
45 Borrowed(ghost Set<Mapping>),
55 Absent,
56}
57
58pub tracked struct EntryOwner<C: PageTableConfig> {
59 pub kind: EntryOwnerKind<C>,
60 pub ghost path: TreePath<NR_ENTRIES>,
61 pub ghost parent_level: PagingLevel,
62}
63
64impl<C: PageTableConfig> EntryOwner<C> {
65 #[verifier::inline]
66 pub open spec fn is_node(self) -> bool {
67 self.kind is Node
68 }
69
70 #[verifier::inline]
71 pub open spec fn is_frame(self) -> bool {
72 self.kind is Frame
73 }
74
75 #[verifier::inline]
76 pub open spec fn is_absent(self) -> bool {
77 self.kind is Absent
78 }
79
80 #[verifier::inline]
81 pub open spec fn is_borrowed(self) -> bool {
82 self.kind is Borrowed
83 }
84
85 pub open spec fn node(self) -> NodeOwner<C> {
86 self.kind->Node_0
87 }
88
89 pub open spec fn frame(self) -> FrameEntryState {
90 self.kind->Frame_0
91 }
92
93 pub open spec fn frame_is_tracked(self) -> bool
94 recommends
95 self.is_frame(),
96 {
97 C::tracked(
98 C::item_from_raw_spec(self.frame().mapped_pa, self.parent_level, self.frame().prop),
99 )
100 }
101
102 pub open spec fn borrowed(self) -> Set<Mapping> {
103 self.kind->Borrowed_0
104 }
105
106 pub open spec fn new_absent(path: TreePath<NR_ENTRIES>, parent_level: PagingLevel) -> Self {
107 EntryOwner { kind: EntryOwnerKind::Absent, path, parent_level }
108 }
109
110 pub open spec fn new_frame(
111 paddr: Paddr,
112 path: TreePath<NR_ENTRIES>,
113 parent_level: PagingLevel,
114 prop: PageProperty,
115 ) -> Self {
116 EntryOwner {
117 kind: EntryOwnerKind::Frame(FrameEntryState { mapped_pa: paddr, prop }),
118 path,
119 parent_level,
120 }
121 }
122
123 pub open spec fn new_node(node: NodeOwner<C>, path: TreePath<NR_ENTRIES>) -> Self {
124 EntryOwner {
125 kind: EntryOwnerKind::Node(node),
126 path,
127 parent_level: (node.level + 1) as PagingLevel,
128 }
129 }
130
131 pub open spec fn new_borrowed(
134 path: TreePath<NR_ENTRIES>,
135 parent_level: PagingLevel,
136 mappings: Set<Mapping>,
137 ) -> Self {
138 EntryOwner { kind: EntryOwnerKind::Borrowed(mappings), path, parent_level }
139 }
140
141 pub proof fn tracked_new_borrowed(
142 path: TreePath<NR_ENTRIES>,
143 parent_level: PagingLevel,
144 mappings: Set<Mapping>,
145 ) -> tracked Self
146 returns
147 Self::new_borrowed(path, parent_level, mappings),
148 {
149 Self { kind: EntryOwnerKind::Borrowed(mappings), path, parent_level }
150 }
151
152 pub proof fn tracked_new_absent(
153 path: TreePath<NR_ENTRIES>,
154 parent_level: PagingLevel,
155 ) -> tracked Self
156 returns
157 Self::new_absent(path, parent_level),
158 {
159 Self { kind: EntryOwnerKind::Absent, path, parent_level }
160 }
161
162 pub proof fn tracked_take_node(tracked &mut self) -> (tracked res: NodeOwner<C>)
163 requires
164 old(self).kind is Node,
165 ensures
166 res == old(self).node(),
167 *final(self) == (EntryOwner { kind: EntryOwnerKind::Absent, ..*old(self) }),
168 {
169 let tracked mut tmp = EntryOwnerKind::Absent;
170 tracked_swap(&mut self.kind, &mut tmp);
171 match tmp {
172 EntryOwnerKind::Node(node) => node,
173 _ => { proof_from_false() },
174 }
175 }
176
177 pub proof fn tracked_put_node(tracked &mut self, tracked node: NodeOwner<C>)
178 ensures
179 *final(self) == (EntryOwner { kind: EntryOwnerKind::Node(node), ..*old(self) }),
180 {
181 self.kind = EntryOwnerKind::Node(node);
182 }
183
184 pub proof fn tracked_borrow_node(tracked &self) -> (tracked res: &NodeOwner<C>)
185 requires
186 self.kind is Node,
187 ensures
188 *res == self.node(),
189 {
190 match self.kind {
191 EntryOwnerKind::Node(ref node) => node,
192 _ => { proof_from_false() },
193 }
194 }
195
196 pub proof fn tracked_borrow_mut_node(tracked &mut self) -> (tracked res: &mut NodeOwner<C>)
197 requires
198 old(self).kind is Node,
199 ensures
200 *res == old(self).node(),
201 *final(self) == (EntryOwner { kind: EntryOwnerKind::Node(*final(res)), ..*old(self) }),
202 {
203 match self.kind {
204 EntryOwnerKind::Node(ref mut node) => node,
205 _ => { proof_from_false() },
206 }
207 }
208
209 pub proof fn tracked_set_frame_prop(tracked &mut self, prop: PageProperty)
210 requires
211 old(self).kind is Frame,
212 ensures
213 *final(self) == (EntryOwner {
214 kind: EntryOwnerKind::Frame(FrameEntryState { prop, ..old(self).frame() }),
215 ..*old(self)
216 }),
217 {
218 let ghost old_frame = self.frame();
219 self.kind = EntryOwnerKind::Frame(FrameEntryState { prop, ..old_frame });
220 }
221
222 pub proof fn tracked_new_frame(
223 paddr: Paddr,
224 path: TreePath<NR_ENTRIES>,
225 parent_level: PagingLevel,
226 prop: PageProperty,
227 ) -> tracked Self
228 returns
229 Self::new_frame(paddr, path, parent_level, prop),
230 {
231 Self {
232 kind: EntryOwnerKind::Frame(FrameEntryState { mapped_pa: paddr, prop }),
233 path,
234 parent_level,
235 }
236 }
237
238 pub broadcast axiom fn axiom_frame_is_tracked_iff_not_mmio(entry: Self)
244 requires
245 entry.is_frame(),
246 entry.inv_base(),
247 ensures
248 #[trigger] entry.frame_is_tracked()
249 != crate::specs::mm::frame::meta_owners::is_mmio_paddr(entry.frame().mapped_pa),
250 ;
251
252 pub proof fn tracked_new_node(
253 tracked node: NodeOwner<C>,
254 path: TreePath<NR_ENTRIES>,
255 ) -> tracked Self
256 returns
257 Self::new_node(node, path),
258 {
259 Self {
260 parent_level: (node.level + 1) as PagingLevel,
261 kind: EntryOwnerKind::Node(node),
262 path,
263 }
264 }
265
266 pub proof fn tracked_new_untracked_frame(
275 paddr: Paddr,
276 parent_level: PagingLevel,
277 prop: PageProperty,
278 ) -> (tracked res: Self)
279 requires
280 valid_frame_paddr(paddr),
281 1 <= parent_level < NR_LEVELS,
282 paddr % page_size(parent_level) == 0,
283 paddr + page_size(parent_level) <= MAX_PADDR,
284 C::raw_item_well_formed(paddr, parent_level, prop),
285 C::E::new_page_req(paddr, parent_level, prop),
286 !C::tracked(C::item_from_raw_spec(paddr, parent_level, prop)),
287 ensures
288 res.is_frame(),
289 res.frame().mapped_pa == paddr,
290 res.frame().prop == prop,
291 !res.frame_is_tracked(),
292 res.parent_level == parent_level,
293 res.path.inv(),
294 res.inv_base(),
295 crate::mm::page_table::Child::<C>::Frame(paddr, parent_level, prop).wf(res),
296 {
297 Self {
298 kind: EntryOwnerKind::Frame(FrameEntryState { mapped_pa: paddr, prop }),
299 path: TreePath(Seq::empty()),
300 parent_level,
301 }
302 }
303
304 pub open spec fn match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
305 &&& valid_frame_paddr(pte.paddr())
306 &&& !pte.is_present() ==> {
307 &&& self.is_absent()
308 &&& parent_level > 1 ==> !pte.is_last(parent_level)
309 }
310 &&& pte.is_present() && !pte.is_last(parent_level) ==> {
311 &&& self.is_node()
312 &&& meta_to_frame(self.node().meta_vaddr()) == pte.paddr()
313 }
314 &&& pte.is_present() && pte.is_last(parent_level) ==> {
315 &&& self.is_frame()
316 &&& self.frame().mapped_pa == pte.paddr()
317 &&& self.frame().prop == pte.prop()
318 }
319 }
320
321 pub open spec fn borrowed_match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
329 &&& self.is_borrowed()
330 &&& valid_frame_paddr(pte.paddr())
331 &&& pte.is_present()
332 &&& !pte.is_last(parent_level)
333 }
334
335 pub proof fn absent_match_pte(owner: Self, pte: C::E, parent_level: PagingLevel)
337 requires
338 owner.is_absent(),
339 pte == C::E::new_absent_spec(),
340 valid_frame_paddr(pte.paddr()),
341 ensures
342 owner.match_pte(pte, parent_level),
343 {
344 C::E::lemma_page_table_entry_properties();
345 }
346
347 pub proof fn last_pte_implies_frame_match(self, pte: C::E, parent_level: PagingLevel)
348 requires
349 self.inv(),
350 self.match_pte(pte, parent_level),
351 1 < parent_level,
352 pte.is_last(parent_level),
353 ensures
354 self.is_frame(),
355 self.frame().mapped_pa == pte.paddr(),
356 self.frame().prop == pte.prop(),
357 {
358 }
359
360 pub proof fn huge_frame_split_child_at(self, regions: MetaRegionOwners, idx: usize)
361 requires
362 self.inv(),
363 self.is_frame(),
364 regions.inv(),
365 1 < self.parent_level < NR_LEVELS,
366 idx < NR_ENTRIES,
367 ensures
368 self.frame().mapped_pa + idx * page_size((self.parent_level - 1) as PagingLevel)
369 < MAX_PADDR,
370 ((self.frame().mapped_pa + idx * page_size(
371 (self.parent_level - 1) as PagingLevel,
372 )) as Paddr) % page_size((self.parent_level - 1) as PagingLevel) == 0,
373 ((self.frame().mapped_pa + idx * page_size(
374 (self.parent_level - 1) as PagingLevel,
375 )) as Paddr) + page_size((self.parent_level - 1) as PagingLevel) <= MAX_PADDR,
376 ((self.frame().mapped_pa + idx * page_size(
377 (self.parent_level - 1) as PagingLevel,
378 )) as Paddr) % PAGE_SIZE == 0,
379 {
380 let pa = self.frame().mapped_pa;
381 let child_pa = (pa + idx * page_size((self.parent_level - 1) as PagingLevel)) as Paddr;
382 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
383 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
384 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_level1();
385 vstd::arithmetic::power2::lemma2_to64();
386 if self.parent_level == 2 {
387 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(1, 2);
388 assert(child_pa + page_size(1) <= MAX_PADDR) by {
389 assert(idx * 4096 + 4096 <= 2097152);
390 };
391 } else {
392 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_va_align_page_size(pa, 2);
393 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(idx as int, page_size(2) as int);
394 vstd::arithmetic::div_mod::lemma_add_mod_noop(
395 pa as int,
396 (idx * page_size(2)) as int,
397 page_size(2) as int,
398 );
399 }
400 }
401
402 pub proof fn frame_sub_pages_valid_preserved_at_own_slot(
405 self,
406 r0: MetaRegionOwners,
407 r1: MetaRegionOwners,
408 )
409 requires
410 self.inv(),
411 r0.inv(),
412 self.is_frame(),
413 self.parent_level <= NR_LEVELS,
414 self.frame_sub_pages_valid(r0),
415 r0.slots == r1.slots,
416 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
417 forall|i: int|
418 #![trigger r1.slot_owners[i]]
419 i != frame_to_index(self.meta_slot_paddr()->0) && r0.slot_owners.contains_key(i)
420 ==> r0.slot_owners[i] == r1.slot_owners[i],
421 ensures
422 self.frame_sub_pages_valid(r1),
423 {
424 if self.parent_level > 1 {
425 let pa = self.frame().mapped_pa;
426 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
427 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
428 assert forall|j: usize|
429 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
430 0 < j < nr_pages implies {
431 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
432 &&& r1.slots.contains_key(sub_idx)
433 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
434 &&& r1.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
435 &&& r1.slot_owners[sub_idx].ref_count() > 0
436 &&& r1.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
437 }
438 } by {
439 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
440 let pa_plus_int: int = pa + j * PAGE_SIZE;
445 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
446 self.parent_level);
447 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
448 self.parent_level,
449 );
450 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
451 j as int,
452 pa as int,
453 PAGE_SIZE as int,
454 );
455 }
457 }
458 }
459
460 pub open spec fn frame_sub_pages_valid(self, regions: MetaRegionOwners) -> bool {
473 self.is_frame() && self.parent_level > 1 ==> {
474 let pa = self.frame().mapped_pa;
475 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
476 forall|j: usize|
477 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
478 0 < j < nr_pages ==> {
479 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
480 &&& regions.slots.contains_key(
483 sub_idx,
484 )
485 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
489 &&& regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
490 &&& regions.slot_owners[sub_idx].ref_count() > 0
491 &&& regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
492 }
493 }
494 }
495 }
496
497 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
498 if self.is_node() {
499 let idx = frame_to_index(self.meta_slot_paddr()->0);
500 &&& regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
501 &&& 0 < regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX
502 &&& regions.slot_owners[idx].slot_vaddr == self.node().meta_vaddr()
503 &&& regions.slots[idx].value().wf(regions.slot_owners[idx])
504 &&& regions.slot_owners[idx].paths_in_pt == set![self.path]
505 &&& self.node().metaregion_sound_node(regions)
506 } else if self.is_frame() {
507 let idx = frame_to_index(self.meta_slot_paddr()->0);
508 &&& regions.slots.contains_key(idx)
509 &&& regions.slots[idx].addr() == index_to_meta(idx)
510 &&& regions.slots[idx].is_init()
511 &&& regions.slots[idx].value().wf(regions.slot_owners[idx])
512 &&& regions.slot_owners[idx].usage !is PageTable
513 &&& regions.slot_owners[idx].usage !is MMIO ==> {
518 &&& regions.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
519 &&& regions.slot_owners[idx].ref_count()
520 > 0
521 &&& regions.slot_owners[idx].ref_count() <= REF_COUNT_MAX
526 }
527 &&& regions.slot_owners[idx].paths_in_pt.contains(self.path)
528 &&& self.frame_sub_pages_valid(regions)
529 } else {
530 true
531 }
532 }
533
534 pub proof fn lemma_active_entry_not_in_free_pool(
537 entry: Self,
538 regions: MetaRegionOwners,
539 free_idx: int,
540 )
541 requires
542 regions.inv(),
543 entry.inv(),
544 entry.is_node(),
545 entry.metaregion_sound(regions),
546 regions.slots.contains_key(free_idx),
547 regions.slot_owners[free_idx].ref_count() == REF_COUNT_UNUSED,
548 ensures
549 frame_to_index(entry.meta_slot_paddr()->0) != free_idx,
550 {
551 let idx = frame_to_index(entry.meta_slot_paddr().unwrap());
552 if idx == free_idx {
553 assert(false);
554 }
555 }
556
557 pub open spec fn meta_slot_paddr(self) -> Option<Paddr> {
558 if self.is_node() {
559 Some(meta_to_frame(self.node().meta_vaddr()))
560 } else if self.is_frame() {
561 Some(self.frame().mapped_pa)
562 } else {
563 None
564 }
565 }
566
567 pub open spec fn meta_slot_paddr_neq(self, other: Self) -> bool {
568 self.meta_slot_paddr() is Some ==> other.meta_slot_paddr() is Some
569 ==> self.meta_slot_paddr()->0 != other.meta_slot_paddr()->0
570 }
571
572 pub proof fn metaregion_sound_slot_owners_only(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
576 requires
577 self.inv(),
578 self.metaregion_sound(r0),
579 r0.slot_owners == r1.slot_owners,
580 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
581 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
582 ensures
583 self.metaregion_sound(r1),
584 {
585 }
586
587 pub proof fn metaregion_sound_one_slot_changed(
590 self,
591 r0: MetaRegionOwners,
592 r1: MetaRegionOwners,
593 changed_idx: int,
594 )
595 requires
596 self.inv(),
597 self.metaregion_sound(r0),
598 forall|i: int|
599 #![trigger r1.slot_owners[i]]
600 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
601 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
602 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
604 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
605 self.meta_slot_paddr() is Some ==> frame_to_index(self.meta_slot_paddr()->0)
606 != changed_idx,
607 self.is_frame() && self.parent_level > 1 ==> {
611 let pa = self.frame().mapped_pa;
612 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
613 forall|j: usize|
614 0 < j < nr_pages ==> {
615 let sub_idx = #[trigger] frame_to_index((pa + j * PAGE_SIZE) as usize);
616 sub_idx != changed_idx || r1.slot_owners[sub_idx].usage is MMIO || (
617 r1.slots.contains_key(sub_idx) && r1.slot_owners[sub_idx].ref_count()
618 != REF_COUNT_UNUSED && r1.slot_owners[sub_idx].ref_count() > 0
619 && r1.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX)
620 }
621 },
622 ensures
623 self.metaregion_sound(r1),
624 {
625 }
626
627 pub proof fn metaregion_sound_paths_in_pt_changed(
630 self,
631 r0: MetaRegionOwners,
632 r1: MetaRegionOwners,
633 changed_idx: int,
634 )
635 requires
636 self.inv(),
637 r0.inv(),
638 self.metaregion_sound(r0),
639 r0.slots == r1.slots,
640 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
641 forall|i: int|
643 #![trigger r1.slot_owners[i]]
644 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
645 r1.slot_owners[changed_idx].same_permissions(r0.slot_owners[changed_idx]),
647 r1.slot_owners[changed_idx].slot_vaddr == r0.slot_owners[changed_idx].slot_vaddr,
648 r1.slot_owners[changed_idx].usage == r0.slot_owners[changed_idx].usage,
649 self.is_node() && self.meta_slot_paddr() is Some && frame_to_index(
651 self.meta_slot_paddr()->0,
652 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt == set![self.path],
653 self.is_frame() && self.meta_slot_paddr() is Some && frame_to_index(
655 self.meta_slot_paddr()->0,
656 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt.contains(self.path),
657 self.is_frame() && self.parent_level > 1 ==> {
660 let pa = self.frame().mapped_pa;
661 let sub_level = (self.parent_level - 1) as PagingLevel;
662 forall|j: int|
663 0 < j < NR_ENTRIES ==> {
664 let sub_idx = #[trigger] frame_to_index(
665 (pa + j * page_size(sub_level)) as usize,
666 );
667 sub_idx != changed_idx || r1.slot_owners[changed_idx].paths_in_pt.is_empty()
668 }
669 },
670 ensures
671 self.metaregion_sound(r1),
672 {
673 if self.meta_slot_paddr() is Some {
674 let eidx = frame_to_index(self.meta_slot_paddr().unwrap());
675 if self.is_frame() {
678 if self.parent_level > 1 {
681 let pa = self.frame().mapped_pa;
682 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
683 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
684 assert forall|j: usize|
685 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
686 0 < j < nr_pages implies {
687 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
688 &&& r1.slots.contains_key(sub_idx)
689 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
690 &&& r1.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
691 &&& r1.slot_owners[sub_idx].ref_count() > 0
692 &&& r1.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
693 }
694 } by {
695 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
696 }
698 }
699 }
700 }
701 }
702
703 pub proof fn same_paddr_implies_same_path(self, other: Self, regions: MetaRegionOwners)
706 requires
707 self.meta_slot_paddr() is Some,
708 self.meta_slot_paddr() == other.meta_slot_paddr(),
709 regions.slot_owner(self.meta_slot_paddr()->0).paths_in_pt == set![self.path],
710 regions.slot_owner(other.meta_slot_paddr()->0).paths_in_pt == set![other.path],
711 ensures
712 self.path == other.path,
713 {
714 assert(set![self.path].contains(other.path));
715 }
716
717 pub proof fn metaregion_sound_rc_value_changed(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
720 requires
721 self.inv(),
722 r0.inv(),
723 self.metaregion_sound(r0),
724 self.meta_slot_paddr() is Some,
725 r0.slots == r1.slots,
726 ({
727 let idx = frame_to_index(self.meta_slot_paddr()->0);
728 &&& r1.slot_owners.contains_key(idx)
729 &&& r1.slot_owners[idx].ref_count_perm.id()
730 == r0.slot_owners[idx].ref_count_perm.id()
731 &&& r1.slot_owners[idx].ref_count() != REF_COUNT_UNUSED
732 &&& r1.slot_owners[idx].ref_count()
733 > 0
734 &&& r1.slot_owners[idx].ref_count() <= REF_COUNT_MAX
736 &&& r1.slot_owners[idx].storage_perm() == r0.slot_owners[idx].storage_perm()
737 &&& r1.slot_owners[idx].vtable_ptr_perm() == r0.slot_owners[idx].vtable_ptr_perm()
738 &&& r1.slot_owners[idx].in_list_perm == r0.slot_owners[idx].in_list_perm
739 &&& r1.slot_owners[idx].slot_vaddr == r0.slot_owners[idx].slot_vaddr
740 &&& r1.slot_owners[idx].paths_in_pt
741 == r0.slot_owners[idx].paths_in_pt
742 &&& r1.slot_owners[idx].usage == r0.slot_owners[idx].usage
745 }),
746 forall|i: int|
748 #![trigger r1.slot_owners[i]]
749 i != frame_to_index(self.meta_slot_paddr()->0) && r0.slot_owners.contains_key(i)
750 ==> r0.slot_owners[i] == r1.slot_owners[i],
751 ensures
752 self.metaregion_sound(r1),
753 {
754 if self.is_frame() && self.parent_level > 1 {
755 let pa = self.frame().mapped_pa;
756 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
757 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
758 assert forall|j: usize|
759 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
760 0 < j < nr_pages implies {
761 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
762 &&& r1.slots.contains_key(sub_idx)
763 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
764 &&& r1.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
765 &&& r1.slot_owners[sub_idx].ref_count() > 0
766 }
767 } by {
768 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
769 let pa_plus_int: int = pa + j * PAGE_SIZE;
770 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
771 self.parent_level);
772 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
773 self.parent_level,
774 );
775 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
777 j as int,
778 pa as int,
779 PAGE_SIZE as int,
780 );
781 }
782 }
783 }
784
785 pub proof fn nodes_different_paths_different_addrs(self, other: Self, regions: MetaRegionOwners)
788 requires
789 self.is_node(),
790 other.is_node(),
791 self.meta_slot_paddr() is Some ==> regions.slot_owner(
792 self.meta_slot_paddr()->0,
793 ).paths_in_pt == set![self.path],
794 other.meta_slot_paddr() is Some ==> regions.slot_owner(
795 other.meta_slot_paddr()->0,
796 ).paths_in_pt == set![other.path],
797 self.path != other.path,
798 ensures
799 self.node().meta_vaddr() != other.node().meta_vaddr(),
800 {
801 let slot_vaddr = self.node().meta_vaddr();
802 let other_addr = other.node().meta_vaddr();
803 let self_idx = meta_to_index(slot_vaddr);
804 let other_idx = meta_to_index(other_addr);
805
806 if slot_vaddr == other_addr {
807 assert(set![self.path].contains(other.path));
808 assert(false); }
810 }
811
812 pub proof fn nodes_different_path_lengths_neq_slot(self, other: Self, regions: MetaRegionOwners)
819 requires
820 self.is_node(),
821 other.is_node(),
822 self.metaregion_sound(regions),
823 other.metaregion_sound(regions),
824 self.path.len() != other.path.len(),
825 ensures
826 self.meta_slot_paddr_neq(other),
827 {
828 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
829 let other_idx = frame_to_index(other.meta_slot_paddr().unwrap());
830 if self_idx == other_idx {
831 assert(set![self.path].contains(other.path));
832 assert(false);
833 }
834 }
835}
836
837impl<C: PageTableConfig> EntryOwner<C> {
838 pub open spec fn inv_base(self) -> bool {
841 &&& self.is_node() ==> {
842 &&& self.node().inv()
843 &&& self.parent_level == self.node().level + 1
844 }
845 &&& self.is_frame() ==> {
846 &&& 1 <= self.parent_level < NR_LEVELS
851 &&& valid_frame_paddr(self.frame().mapped_pa)
852 &&& self.frame().mapped_pa % page_size(self.parent_level) == 0
853 &&& self.frame().mapped_pa + page_size(self.parent_level) <= MAX_PADDR
854 &&& C::raw_item_well_formed(
855 self.frame().mapped_pa,
856 self.parent_level,
857 self.frame().prop,
858 )
859 &&& C::E::new_page_req(self.frame().mapped_pa, self.parent_level, self.frame().prop)
860 }
861 &&& self.is_borrowed() ==> { true }
862 &&& self.path.inv()
863 }
864}
865
866impl<C: PageTableConfig> Inv for EntryOwner<C> {
867 open spec fn inv(self) -> bool {
868 self.inv_base()
869 }
870}
871
872impl<C: PageTableConfig> View for EntryOwner<C> {
873 type V = EntryView<C>;
874
875 open spec fn view(&self) -> <Self as View>::V {
876 if self.is_frame() {
877 let frame = self.frame();
878 EntryView::Leaf {
879 leaf: LeafPageTableEntryView {
880 map_va: vaddr(self.path) as int,
881 map_to_pa: frame.mapped_pa as int,
884 level: self.path.len() as u8,
885 prop: frame.prop,
886 phantom: PhantomData,
887 },
888 }
889 } else if self.is_node() {
890 let node = self.node();
891 EntryView::Intermediate {
892 node: IntermediatePageTableEntryView {
893 map_va: vaddr(self.path) as int,
894 map_to_pa: meta_to_frame(node.meta_vaddr()) as int,
897 level: self.path.len() as u8,
898 phantom: PhantomData,
899 },
900 }
901 } else {
902 EntryView::Absent
903 }
904 }
905}
906
907impl<C: PageTableConfig> InvView for EntryOwner<C> {
908 proof fn view_preserves_inv(self) {
909 }
913}
914
915impl<'a, 'rcu, C: PageTableConfig> OwnerOf for Entry<'a, 'rcu, C> {
916 type Owner = EntryOwner<C>;
917
918 open spec fn wf(self, owner: Self::Owner) -> bool {
919 &&& self.idx < NR_ENTRIES
920 &&& owner.match_pte(self.pte, owner.parent_level)
921 &&& valid_frame_paddr(self.pte.paddr())
922 }
923}
924
925}