1use core::ops::{Deref, Range};
2
3use vstd::prelude::*;
4
5use vstd::{arithmetic::power2::pow2, seq::*, seq_lib::*, set_lib::*};
6use vstd_extra::{drop_tracking::*, ghost_tree::*, ownership::*, prelude::TreeNodeValue};
7
8use crate::specs::{
9 arch::*,
10 mm::{
11 frame::{mapping::frame_to_index, meta_region_owners::MetaRegionOwners},
12 page_table::{
13 cursor::page_size_lemmas::{
14 lemma_page_size_divides, lemma_page_size_ge_page_size, lemma_page_size_spec_values,
15 },
16 *,
17 },
18 },
19};
20
21use crate::mm::{
22 Paddr, PagingConstsTrait, PagingLevel, Vaddr,
23 frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
24 page_size,
25 page_table::{EntryOwner, EntryOwnerKind, PageTableEntryTrait, PageTableGuard},
26};
27
28verus! {
29
30broadcast use group_ghost_tree_lemmas;
31
32#[verifier::inline]
33pub open spec fn vaddr_shift_bits<const L: usize>(idx: int) -> nat
34 recommends
35 0 < L,
36 idx < L,
37{
38 (12 + 9 * (L - 1 - idx)) as nat
39}
40
41#[verifier::inline]
42pub open spec fn vaddr_shift<const L: usize>(idx: int) -> usize
43 recommends
44 0 < L,
45 idx < L,
46{
47 pow2(vaddr_shift_bits::<L>(idx)) as usize
48}
49
50#[verifier::inline]
51pub open spec fn vaddr_make<const L: usize>(idx: int, offset: usize) -> usize
52 recommends
53 0 < L,
54 idx < L,
55 0 <= offset < 512,
56{
57 (vaddr_shift::<L>(idx) * offset) as usize
58}
59
60pub open spec fn rec_vaddr(path: TreePath<NR_ENTRIES>, idx: int) -> usize
61 decreases path.len() - idx,
62 when 0 <= idx <= path.len()
63{
64 if idx == path.len() {
65 0
66 } else {
67 let offset = path[idx] as usize;
68 (vaddr_make::<NR_LEVELS>(idx, offset) + rec_vaddr(path, idx + 1)) as usize
69 }
70}
71
72pub open spec fn vaddr(path: TreePath<NR_ENTRIES>) -> usize {
73 rec_vaddr(path, 0)
74}
75
76pub open spec fn vaddr_at(path: TreePath<NR_ENTRIES>, leading_bits: int) -> usize {
83 (vaddr(path) + leading_bits * 0x1_0000_0000_0000int) as usize
84}
85
86pub open spec fn vaddr_of<C: PageTableConfig>(path: TreePath<NR_ENTRIES>) -> usize {
92 vaddr_at(path, C::LEADING_BITS_spec() as int)
93}
94
95#[verifier::spinoff_prover]
99pub proof fn lemma_vaddr_strict_bound(path: TreePath<NR_ENTRIES>)
100 requires
101 path.inv(),
102 path.len() <= INC_LEVELS - 1,
103 ensures
104 vaddr(path) < 0x1_0000_0000_0000int,
105{
106 vstd::arithmetic::power2::lemma2_to64();
107 vstd::arithmetic::power2::lemma2_to64_rest();
108 if path.len() == 0 {
109 } else if path.len() == 1 {
110 let i0 = path[0];
111 assert(rec_vaddr(path, 1) == 0);
112 } else if path.len() == 2 {
113 let i0 = path[0];
114 let i1 = path[1];
115 assert(rec_vaddr(path, 2) == 0);
116 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1 as usize) as usize);
117 } else if path.len() == 3 {
118 let i0 = path[0];
119 let i1 = path[1];
120 let i2 = path[2];
121 assert(rec_vaddr(path, 3) == 0);
122 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2 as usize) as usize);
123 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
124 NR_LEVELS,
125 >(2, i2 as usize)) as usize);
126 } else {
127 let i0 = path[0];
128 let i1 = path[1];
129 let i2 = path[2];
130 let i3 = path[3];
131 assert(rec_vaddr(path, 4) == 0);
132 assert(rec_vaddr(path, 3) == vaddr_make::<NR_LEVELS>(3, i3 as usize) as usize);
133 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<
134 NR_LEVELS,
135 >(3, i3 as usize)) as usize);
136 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
137 NR_LEVELS,
138 >(2, i2 as usize) + vaddr_make::<NR_LEVELS>(3, i3 as usize)) as usize);
139 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + vaddr_make::<
140 NR_LEVELS,
141 >(1, i1 as usize) + vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<NR_LEVELS>(
142 3,
143 i3 as usize,
144 )) as usize);
145 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2 + 0x1000usize
146 * i3 < 0x1_0000_0000_0000int) by (nonlinear_arith)
147 requires
148 i0 < 512,
149 i1 < 512,
150 i2 < 512,
151 i3 < 512,
152 ;
153 }
154}
155
156pub proof fn lemma_vaddr_top_index_cell(path: TreePath<NR_ENTRIES>)
160 requires
161 path.inv(),
162 1 <= path.len() <= INC_LEVELS - 1,
163 ensures
164 (path[0]) * 0x80_0000_0000int <= vaddr(path),
165 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= (path[0] + 1)
166 * 0x80_0000_0000int,
167{
168 broadcast use TreePath::lemma_index_satisfies_elem_inv;
169
170 lemma_page_size_spec_values();
171 vstd::arithmetic::power2::lemma2_to64();
172 vstd::arithmetic::power2::lemma2_to64_rest();
173 let i0 = path[0];
174 if path.len() == 1 {
175 assert(rec_vaddr(path, 1) == 0);
176 } else if path.len() == 2 {
177 let i1 = path[1];
178 assert(rec_vaddr(path, 2) == 0);
179 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1 as usize) as usize);
180 } else if path.len() == 3 {
181 let i1 = path[1];
182 let i2 = path[2];
183 assert(rec_vaddr(path, 3) == 0);
184 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2 as usize) as usize);
185 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
186 NR_LEVELS,
187 >(2, i2 as usize)) as usize);
188 } else {
189 let i1 = path[1];
190 let i2 = path[2];
191 let i3 = path[3];
192 assert(rec_vaddr(path, 4) == 0);
193 assert(rec_vaddr(path, 3) == vaddr_make::<NR_LEVELS>(3, i3 as usize) as usize);
194 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<
195 NR_LEVELS,
196 >(3, i3 as usize)) as usize);
197 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
198 NR_LEVELS,
199 >(2, i2 as usize) + vaddr_make::<NR_LEVELS>(3, i3 as usize)) as usize);
200 assert(0x80_0000_0000int * i0 + 0x4000_0000int * i1 + 0x20_0000int * i2 + 0x1000int * i3
201 + 0x1000int <= (i0 + 1) * 0x80_0000_0000int) by (nonlinear_arith)
202 requires
203 i1 < 512,
204 i2 < 512,
205 i3 < 512,
206 ;
207 }
208}
209
210pub proof fn lemma_vaddr_of_eq_int<C: PageTableConfig>(path: TreePath<NR_ENTRIES>)
214 requires
215 path.inv(),
216 path.len() <= INC_LEVELS - 1,
217 ensures
218 vaddr_of::<C>(path) == vaddr(path) + C::LEADING_BITS_spec() as int * 0x1_0000_0000_0000int,
219{
220 C::lemma_page_table_config_constant_properties();
221 lemma_vaddr_strict_bound(path);
222}
223
224pub proof fn page_size_monotonic(a: PagingLevel, b: PagingLevel)
226 requires
227 1 <= a <= b <= NR_LEVELS + 1,
228 ensures
229 page_size(a) <= page_size(b),
230{
231 if a == b {
232 } else {
233 let ps_a = page_size(a);
234 let ps_b = page_size(b);
235
236 lemma_page_size_ge_page_size(b);
237
238 lemma_page_size_divides(a, b);
239
240 assert(ps_a <= ps_b) by {
241 if ps_b < ps_a {
242 vstd::arithmetic::div_mod::lemma_small_mod(ps_b as nat, ps_a as nat);
243 assert(false);
244 }
245 }
246 }
247}
248
249pub proof fn sibling_paths_disjoint<C: PageTableConfig>(
256 prefix: TreePath<NR_ENTRIES>,
257 j: int,
258 k: int,
259 size: usize,
260)
261 requires
262 prefix.inv(),
263 prefix.len() < INC_LEVELS - 1,
264 0 <= j,
265 0 <= k,
266 j < NR_ENTRIES,
267 k < NR_ENTRIES,
268 j != k,
269 size == page_size((INC_LEVELS - prefix.len() - 1) as PagingLevel),
270 ensures
271 vaddr(prefix.push_tail(j)) + size <= vaddr(prefix.push_tail(k)) || vaddr(
272 prefix.push_tail(k),
273 ) + size <= vaddr(prefix.push_tail(j)),
274{
275 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, j);
276 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, k);
277 let s = size as int;
278 let vp = vaddr(prefix) as int;
279 let vj = vaddr(prefix.push_tail(j)) as int;
280 let vk = vaddr(prefix.push_tail(k)) as int;
281 if j < k {
282 assert(vj + s <= vk) by (nonlinear_arith)
283 requires
284 vj == vp + j * s,
285 vk == vp + k * s,
286 j < k,
287 s >= 0,
288 ;
289 } else {
290 assert(vk + s <= vj) by (nonlinear_arith)
291 requires
292 vj == vp + j * s,
293 vk == vp + k * s,
294 k < j,
295 s >= 0,
296 ;
297 }
298}
299
300impl<C: PageTableConfig, const L: usize> TreeNodeValue<L> for EntryOwner<C> {
301 open spec fn default(lv: nat) -> Self {
302 Self {
303 kind: EntryOwnerKind::Absent,
304 path: TreePath::new(Seq::empty()),
305 parent_level: (INC_LEVELS - lv) as PagingLevel,
306 }
307 }
308
309 proof fn lemma_default_preserves_inv() {
310 }
311
312 open spec fn la_inv(self, lv: nat) -> bool {
313 self.is_node() ==> lv < L - 1
314 }
315
316 proof fn lemma_default_preserves_la_inv() {
317 }
318
319 open spec fn rel_children(self, i: int, child: Option<Self>) -> bool {
322 true
323 }
324
325 proof fn lemma_default_preserves_rel_children(self, lv: nat) {
326 }
327}
328
329pub const INC_LEVELS: usize = NR_LEVELS + 1;
330
331pub type OwnerSubtree<C> = TreeNode<EntryOwner<C>, NR_ENTRIES, INC_LEVELS>;
341
342pub open spec fn allocated_empty_node_owner<C: PageTableConfig>(
351 owner: OwnerSubtree<C>,
352 level: PagingLevel,
353) -> bool {
354 &&& owner.inv()
355 &&& owner.value().is_node()
356 &&& owner.value().path == TreePath::<NR_ENTRIES>::new(Seq::empty())
357 &&& owner.value().parent_level == (level + 1) as PagingLevel
358 &&& owner.value().node().level
359 == level
360 &&& owner.level() == (INC_LEVELS - level - 1) as nat
365 &&& owner.value().node().inv()
366 &&& !owner.value().node().children_perm.value().all(|child: C::E| child.is_present())
367 &&& forall|i: int|
368 0 <= i < NR_ENTRIES ==> {
369 &&& #[trigger] owner.has_child(i)
370 &&& owner.child(i).value().is_absent()
371 &&& owner.child(i).value().inv()
372 &&& owner.child(i).value().path == owner.value().path.push_tail(i)
373 }
374 &&& forall|i: int|
375 #![auto]
376 0 <= i < NR_ENTRIES ==> owner.child(i).value().match_pte(
377 owner.value().node().children_perm.value()[i],
378 owner.child(i).value().parent_level,
379 )
380 &&& forall|i: int|
381 #![auto]
382 0 <= i < NR_ENTRIES ==> owner.child(i).value().parent_level
383 == owner.value().node().level
384 &&& forall|j: int|
389 0 <= j < NR_ENTRIES ==> #[trigger] owner.value().node().children_perm.value()[j]
390 == C::E::new_absent_spec()
391}
392
393pub open spec fn allocated_empty_node_grandchildren_none<C: PageTableConfig>(
401 owner: OwnerSubtree<C>,
402) -> bool {
403 forall|i: int, j: int|
404 0 <= i < NR_ENTRIES && 0 <= j < NR_ENTRIES ==> !#[trigger] owner.child(i).has_child(j)
405}
406
407pub proof fn rebase_freshly_allocated_children_at<C: PageTableConfig>(
412 tracked owner: &mut OwnerSubtree<C>,
413 new_path: TreePath<NR_ENTRIES>,
414 i: usize,
415)
416 requires
417 i <= NR_ENTRIES,
418 old(owner).children().len() == NR_ENTRIES,
419 new_path.inv(),
420 forall|j: int| i <= j < NR_ENTRIES ==> (#[trigger] old(owner).children()[j]) is Some,
421 ensures
422 final(owner).value() == old(owner).value(),
423 final(owner).level() == old(owner).level(),
424 final(owner).children().len() == NR_ENTRIES,
425 forall|j: int|
426 0 <= j < i ==> (#[trigger] final(owner).children()[j]) == old(owner).children()[j],
427 forall|j: int|
428 i <= j < NR_ENTRIES ==> {
429 let c_old = old(owner).child(j);
430 let c_new = (#[trigger] final(owner).children()[j])->0;
431 &&& final(owner).has_child(j)
432 &&& c_new.value() == EntryOwner { path: new_path.push_tail(j), ..c_old.value() }
433 &&& c_new.level() == c_old.level()
434 &&& c_new.children() == c_old.children()
435 },
436 decreases NR_ENTRIES - i,
437{
438 if i < NR_ENTRIES {
439 let tracked mut child_value = owner.tracked_borrow_mut_child(
440 i as int,
441 ).tracked_borrow_mut_value();
442 child_value.path = new_path.push_tail(i as int);
443 rebase_freshly_allocated_children_at(owner, new_path, (i + 1) as usize);
444 }
445}
446
447pub proof fn rebase_freshly_allocated_children<C: PageTableConfig>(
457 tracked owner: &mut OwnerSubtree<C>,
458 new_path: TreePath<NR_ENTRIES>,
459)
460 requires
461 old(owner).children().len() == NR_ENTRIES,
462 new_path.inv(),
463 forall|i: int| 0 <= i < NR_ENTRIES ==> (#[trigger] old(owner).children()[i]) is Some,
464 ensures
465 final(owner).value() == old(owner).value(),
466 final(owner).level() == old(owner).level(),
467 final(owner).children().len() == NR_ENTRIES,
468 forall|i: int|
469 0 <= i < NR_ENTRIES ==> {
470 let c_old = old(owner).child(i);
471 let c_new = (#[trigger] final(owner).children()[i])->0;
472 &&& final(owner).has_child(i)
473 &&& c_new.value() == EntryOwner { path: new_path.push_tail(i), ..c_old.value() }
474 &&& c_new.level() == c_old.level()
475 &&& c_new.children() == c_old.children()
476 },
477{
478 rebase_freshly_allocated_children_at(owner, new_path, 0);
479}
480
481pub proof fn fresh_node_subtree_satisfies<C: PageTableConfig>(
490 node: OwnerSubtree<C>,
491 path: TreePath<NR_ENTRIES>,
492 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
493)
494 requires
495 node.inv(),
496 node.level() < INC_LEVELS - 1,
497 f(node.value(), path),
498 forall|i: int| 0 <= i < NR_ENTRIES ==> #[trigger] node.has_child(i),
499 forall|i: int, j: int|
500 0 <= i < NR_ENTRIES && 0 <= j < NR_ENTRIES ==> !#[trigger] node.child(i).has_child(j),
501 forall|i: int|
502 0 <= i < NR_ENTRIES ==> #[trigger] f(node.child(i).value(), path.push_tail(i)),
503 ensures
504 node.subtree_satisfies(path, f),
505{
506 assert forall|i: int|
507 0 <= i < node.children().len() && #[trigger] node.has_child(i) implies node.child(
508 i,
509 ).subtree_satisfies(path.push_tail(i), f) by {
510 assert(node.child(i).inv());
513 };
514}
515
516pub tracked struct PageTableOwner<C: PageTableConfig>(pub OwnerSubtree<C>);
523
524impl<C: PageTableConfig> PageTableOwner<C> {
525 pub open spec fn pt_edge_at(parent: OwnerSubtree<C>, i: int) -> bool {
527 &&& parent.has_child(i)
528 &&& parent.child(i).value().path.len() == parent.value().node().tree_level
529 + 1
530 &&& (parent.child(i).value().match_pte(
538 parent.value().node().children_perm.value()[i],
539 parent.value().node().level,
540 ) || (parent.value().node().level == NR_LEVELS && C::LEADING_BITS_spec() == 0
541 && parent.child(i).value().borrowed_match_pte(
542 parent.value().node().children_perm.value()[i],
543 parent.value().node().level,
544 )))
545 &&& parent.child(i).value().path == parent.value().path.push_tail(i)
546 &&& parent.child(i).value().parent_level == parent.value().node().level
547 }
548
549 pub open spec fn pt_inv_at_depth(self, depth: nat) -> bool
553 decreases depth,
554 {
555 if depth == 0 {
556 true
557 } else if self.0.value().is_node() {
558 forall|i: int|
559 #![trigger self.0.has_child(i)]
560 0 <= i < NR_ENTRIES ==> Self::pt_edge_at(self.0, i) && PageTableOwner(
561 self.0.child(i),
562 ).pt_inv_at_depth((depth - 1) as nat)
563 } else {
564 forall|i: int|
565 #![trigger self.0.has_child(i)]
566 0 <= i < NR_ENTRIES ==> !self.0.has_child(i)
567 }
568 }
569
570 pub open spec fn pt_inv(self) -> bool {
575 &&& self.0.inv()
576 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level()) as nat)
577 }
578
579 pub proof fn pt_inv_unroll(self, i: int)
580 requires
581 self.pt_inv(),
582 self.0.value().is_node(),
583 0 <= i < NR_ENTRIES,
584 ensures
585 Self::pt_edge_at(self.0, i),
586 PageTableOwner(self.0.child(i)).pt_inv(),
587 {
588 let depth = (INC_LEVELS - self.0.level()) as nat;
591 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::la_inv(
592 self.0.value(),
593 self.0.level(),
594 ));
595 }
596
597 pub proof fn pt_inv_non_node(self, i: int)
598 requires
599 self.pt_inv(),
600 !self.0.value().is_node(),
601 0 <= i < NR_ENTRIES,
602 ensures
603 !self.0.has_child(i),
604 {
605 }
606
607 pub proof fn non_node_pt_inv_at_depth(self, depth: nat)
611 requires
612 !self.0.value().is_node(),
613 forall|j: int| 0 <= j < NR_ENTRIES ==> !#[trigger] self.0.has_child(j),
614 ensures
615 self.pt_inv_at_depth(depth),
616 decreases depth,
617 {
618 }
619
620 #[verifier::spinoff_prover]
629 pub proof fn allocated_empty_node_pt_inv(owner: OwnerSubtree<C>)
630 requires
631 owner.inv(),
632 owner.value().is_node(),
633 owner.children().len() == NR_ENTRIES,
634 forall|i: int|
635 0 <= i < NR_ENTRIES ==> {
636 &&& #[trigger] owner.has_child(i)
637 &&& owner.child(i).value().is_absent()
638 &&& owner.child(i).value().path.len() == owner.value().node().tree_level + 1
639 &&& owner.child(i).value().match_pte(
640 owner.value().node().children_perm.value()[i],
641 owner.value().node().level,
642 )
643 &&& owner.child(i).value().path == owner.value().path.push_tail(i)
644 &&& owner.child(i).value().parent_level == owner.value().node().level
645 },
646 allocated_empty_node_grandchildren_none(owner),
647 ensures
648 PageTableOwner(owner).pt_inv(),
649 {
650 let depth = (INC_LEVELS - owner.level()) as nat;
651 assert forall|i: int| 0 <= i < NR_ENTRIES implies #[trigger] owner.has_child(i)
655 && Self::pt_edge_at(owner, i) && PageTableOwner(owner.child(i)).pt_inv_at_depth(
656 (depth - 1) as nat,
657 ) by {
658 let child = owner.child(i);
659 assert(owner.has_child(i));
664 PageTableOwner(child).non_node_pt_inv_at_depth((depth - 1) as nat);
667 };
668 }
669
670 pub open spec fn top_level_indices_absent(self) -> bool {
675 let range = C::TOP_LEVEL_INDEX_RANGE();
676 self.0.value().is_node() ==> forall|i: int|
677 #![trigger self.0.has_child(i)]
678 0 <= i < NR_ENTRIES && !(range.start <= i < range.end) ==> self.0.has_child(i)
679 && self.0.child(i).value().is_absent()
680 }
681
682 pub open spec fn view_rec_node_children(self, path: TreePath<NR_ENTRIES>) -> Seq<Set<Mapping>>
683 decreases INC_LEVELS - path.len(), 0nat,
684 when self.0.inv() && path.len() < INC_LEVELS - 1
685 {
686 self.0.children().map(
687 |i, child: Option<OwnerSubtree<C>>|
688 if child is Some {
689 PageTableOwner(child->0).view_rec(path.push_tail(i))
690 } else {
691 Set::empty()
692 },
693 )
694 }
695
696 pub open spec fn view_rec(self, path: TreePath<NR_ENTRIES>) -> Set<Mapping>
697 decreases INC_LEVELS - path.len(), 1nat,
698 when self.0.inv() && path.len() <= INC_LEVELS - 1
699 {
700 if self.0.value().is_frame() {
701 let va = vaddr_of::<C>(path);
702 let pt_level = INC_LEVELS - path.len();
703 let page_size = page_size(pt_level as PagingLevel);
704
705 set![Mapping {
706 va_range: Range { start: va as int, end: va + page_size },
707 pa_range: Range {
708 start: self.0.value().frame().mapped_pa,
709 end: (self.0.value().frame().mapped_pa + page_size) as Paddr,
710 },
711 page_size: page_size,
712 property: self.0.value().frame().prop,
713 }]
714 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
715 self.view_rec_node_children(path).to_set().flatten()
716 } else {
717 set![]
718 }
719 }
720
721 pub broadcast proof fn lemma_view_rec_contains_intro(
722 self,
723 path: TreePath<NR_ENTRIES>,
724 m: Mapping,
725 i: int,
726 )
727 requires
728 self.0.inv(),
729 path.len() < INC_LEVELS - 1,
730 self.0.value().is_node(),
731 0 <= i < self.0.children().len(),
732 self.0.has_child(i),
733 #[trigger] PageTableOwner(self.0.children()[i]->0).view_rec(path.push_tail(i)).contains(
734 m,
735 ),
736 ensures
737 self.view_rec(path).contains(m),
738 {
739 broadcast use vstd::seq_lib::group_seq_properties;
740
741 let mapped = self.view_rec_node_children(path);
742 assert(mapped.to_set().contains(mapped[i]));
743 }
744
745 pub broadcast proof fn lemma_view_rec_contains(self, path: TreePath<NR_ENTRIES>)
746 requires
747 self.0.inv(),
748 path.len() < INC_LEVELS - 1,
749 self.0.value().is_node(),
750 ensures
751 #![trigger self.view_rec(path)]
752 forall|m: Mapping|
753 #![trigger self.view_rec(path).contains(m)]
754 self.view_rec(path).contains(m) ==> exists|i: int|
755 #![trigger self.0.children()[i]]
756 0 <= i < self.0.children().len() && self.0.children()[i] is Some
757 && PageTableOwner(self.0.children()[i]->0).view_rec(
758 path.push_tail(i),
759 ).contains(m),
760 {
761 broadcast use vstd::seq_lib::group_seq_properties;
762
763 }
764
765 pub proof fn view_rec_contains_choose(self, path: TreePath<NR_ENTRIES>, m: Mapping) -> (i: int)
766 requires
767 self.0.inv(),
768 path.len() < INC_LEVELS - 1,
769 self.view_rec(path).contains(m),
770 self.0.value().is_node(),
771 ensures
772 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
773 self.0.children()[i]->0,
774 ).view_rec(path.push_tail(i)).contains(m),
775 {
776 broadcast use PageTableOwner::group_lemmas;
777
778 choose|i: int|
779 #![auto]
780 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
781 self.0.children()[i].unwrap(),
782 ).view_rec(path.push_tail(i)).contains(m)
783 }
784
785 #[verifier::rlimit(200)]
787 pub proof fn lemma_vaddr_push_tail_eq(path: TreePath<NR_ENTRIES>, i: int)
788 requires
789 path.inv(),
790 path.len() < INC_LEVELS - 1,
791 0 <= i < NR_ENTRIES,
792 ensures
793 vaddr(path.push_tail(i)) == vaddr(path) + i * page_size(
794 (INC_LEVELS - path.len() - 1) as PagingLevel,
795 ),
796 vaddr(path) + (i + 1) * page_size((INC_LEVELS - path.len() - 1) as PagingLevel)
797 <= usize::MAX,
798 {
799 broadcast use {
800 TreePath::lemma_push_tail_len,
801 TreePath::lemma_push_tail_preserves_inv,
802 TreePath::lemma_index_satisfies_elem_inv,
803 };
804
805 lemma_page_size_spec_values();
806 lemma_vaddr_strict_bound(path);
807 vstd::arithmetic::power2::lemma2_to64();
808 vstd::arithmetic::power2::lemma2_to64_rest();
809 let pt = path.push_tail(i);
810 if path.len() >= 1 {
811 }
812 if path.len() == 0 {
813 assert(rec_vaddr(pt, 1) == 0);
814 assert(vaddr_make::<NR_LEVELS>(0, i as usize) == 0x80_0000_0000usize * i) by (compute);
815 assert(0x80_0000_0000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
816 requires
817 i < 512,
818 ;
819 } else if path.len() == 1 {
820 let i0 = path[0];
821 assert(vaddr_make::<NR_LEVELS>(0, i0 as usize) == 0x80_0000_0000usize * i0);
822 assert(rec_vaddr(pt, 2) == 0);
823 } else if path.len() == 2 {
824 let i0 = path[0];
825 let i1 = path[1];
826 assert(rec_vaddr(path, 2) == 0);
827 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1 as usize) as usize);
828 assert(rec_vaddr(pt, 3) == 0);
829 assert(rec_vaddr(pt, 2) == vaddr_make::<NR_LEVELS>(2, i as usize) as usize);
830 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
831 NR_LEVELS,
832 >(2, i as usize)) as usize);
833 } else {
834 let i0 = path[0];
835 let i1 = path[1];
836 let i2 = path[2];
837 assert(rec_vaddr(path, 3) == 0);
838 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2 as usize) as usize);
839 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
840 NR_LEVELS,
841 >(2, i2 as usize)) as usize);
842 assert(vaddr_make::<NR_LEVELS>(1, i1 as usize) == 0x4000_0000usize * i1) by (compute);
843 assert(rec_vaddr(pt, 4) == 0);
844 assert(rec_vaddr(pt, 3) == vaddr_make::<NR_LEVELS>(3, i as usize) as usize);
845 assert(rec_vaddr(pt, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<
846 NR_LEVELS,
847 >(3, i as usize)) as usize);
848 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
849 NR_LEVELS,
850 >(2, i2 as usize) + vaddr_make::<NR_LEVELS>(3, i as usize)) as usize);
851 assert(vaddr_make::<NR_LEVELS>(3, i as usize) == 0x1000usize * i) by (compute);
852 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
853 + 0x1000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
854 requires
855 i0 < 512,
856 i1 < 512,
857 i2 < 512,
858 i < 512,
859 ;
860 }
861 }
862
863 pub proof fn view_rec_vaddr_range(self, path: TreePath<NR_ENTRIES>, m: Mapping)
864 requires
865 self.pt_inv(),
866 path.inv(),
867 path.len() <= INC_LEVELS - 1,
868 path.len() == self.0.level(),
869 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
870 self.view_rec(path).contains(m),
871 ensures
872 vaddr_of::<C>(path) <= m.va_range.start,
873 m.va_range.start < m.va_range.end,
874 m.va_range.end <= vaddr_of::<C>(path) + page_size(
875 (INC_LEVELS - path.len()) as PagingLevel,
876 ),
877 decreases INC_LEVELS - path.len(),
878 {
879 broadcast use PageTableOwner::group_lemmas;
880
881 lemma_page_size_spec_values();
882 if self.0.value().is_frame() {
883 let frame = self.0.value().frame();
884 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
885 let expected = Mapping {
886 va_range: Range {
887 start: vaddr_of::<C>(path) as int,
888 end: vaddr_of::<C>(path) + page_size(pt_level),
889 },
890 pa_range: Range {
891 start: frame.mapped_pa,
892 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
893 },
894 page_size: page_size(pt_level),
895 property: frame.prop,
896 };
897 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
898 let i = choose|i: int|
899 #![trigger self.0.children()[i]]
900 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
901 self.0.children()[i].unwrap(),
902 ).view_rec(path.push_tail(i)).contains(m);
903 self.pt_inv_unroll(i);
904 let child = PageTableOwner(self.0.children()[i].unwrap());
905 child.view_rec_vaddr_range(path.push_tail(i), m);
906 Self::lemma_vaddr_push_tail_eq(path, i);
907
908 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel) as int;
909 assert((i + 1) * child_ps <= 512 * child_ps) by (nonlinear_arith)
910 requires
911 0 <= i < 512,
912 child_ps >= 0,
913 ;
914 lemma_vaddr_of_eq_int::<C>(path.push_tail(i));
915 assert(i * child_ps + child_ps == (i + 1) * child_ps) by (nonlinear_arith);
916 }
917 }
918
919 pub proof fn view_rec_top_index_va_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping, t: int)
925 requires
926 self.pt_inv(),
927 path.inv(),
928 1 <= path.len() <= INC_LEVELS - 1,
929 path.len() == self.0.level(),
930 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
931 path[0] < t,
932 self.view_rec(path).contains(m),
933 ensures
934 (path[0]) * 0x80_0000_0000int + C::LEADING_BITS_spec() * 0x1_0000_0000_0000int
935 <= m.va_range.start,
936 m.va_range.start < m.va_range.end,
937 m.va_range.end <= t * 0x80_0000_0000int + C::LEADING_BITS_spec()
938 * 0x1_0000_0000_0000int,
939 {
940 self.view_rec_vaddr_range(path, m);
941 lemma_vaddr_of_eq_int::<C>(path);
942 lemma_vaddr_top_index_cell(path);
943 }
950
951 pub proof fn pt_inv_implies_path_correct(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
959 requires
960 PageTableOwner(subtree).pt_inv(),
961 subtree.value().path == path,
962 ensures
963 subtree.subtree_satisfies(path, Self::path_correct_pred()),
964 decreases INC_LEVELS - subtree.level(),
965 {
966 if subtree.level() < INC_LEVELS - 1 {
968 assert forall|i: int|
969 0 <= i < subtree.children().len() && (
970 #[trigger] subtree.children()[i]) is Some implies subtree.children()[i].unwrap().subtree_satisfies(
971 path.push_tail(i), Self::path_correct_pred()) by {
972 if subtree.value().is_node() {
973 PageTableOwner(subtree).pt_inv_unroll(i);
974 Self::pt_inv_implies_path_correct(
976 subtree.children()[i].unwrap(),
977 path.push_tail(i),
978 );
979 } else {
980 PageTableOwner(subtree).pt_inv_non_node(i);
982 }
983 };
984 }
985 }
986
987 pub proof fn no_frame_with_path_rec(
997 self,
998 path: TreePath<NR_ENTRIES>,
999 removed_path: TreePath<NR_ENTRIES>,
1000 ambient: Set<Mapping>,
1001 )
1002 requires
1003 self.pt_inv(),
1004 path.inv(),
1005 path.len() <= INC_LEVELS - 1,
1006 path.len() == self.0.level(),
1007 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1008 self.0.value().path == path,
1009 self.0.subtree_satisfies(path, Self::path_correct_pred()),
1010 forall|mm: Mapping|
1011 #![trigger self.view_rec(path).contains(mm)]
1012 self.view_rec(path).contains(mm) ==> ambient.contains(mm),
1013 forall|mm: Mapping|
1014 #![trigger ambient.contains(mm)]
1015 ambient.contains(mm) ==> mm.va_range.start != vaddr_of::<C>(removed_path),
1016 ensures
1017 self.0.subtree_satisfies(
1018 path,
1019 |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1020 e.is_frame() ==> e.path != removed_path,
1021 ),
1022 decreases INC_LEVELS - path.len(),
1023 {
1024 broadcast use PageTableOwner::group_lemmas;
1025
1026 let g = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1027 e.is_frame() ==> e.path != removed_path;
1028
1029 if self.0.value().is_frame() {
1031 let frame = self.0.value().frame();
1032 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1033 let expected = Mapping {
1034 va_range: Range {
1035 start: vaddr_of::<C>(path) as int,
1036 end: vaddr_of::<C>(path) + page_size(pt_level),
1037 },
1038 pa_range: Range {
1039 start: frame.mapped_pa,
1040 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1041 },
1042 page_size: page_size(pt_level),
1043 property: frame.prop,
1044 };
1045 assert(self.view_rec(path).contains(expected));
1046
1047 }
1048 if self.0.level() < INC_LEVELS - 1 {
1049 assert forall|i: int|
1050 0 <= i < self.0.children().len() && (
1051 #[trigger] self.0.children()[i]) is Some implies self.0.children()[i].unwrap().subtree_satisfies(
1052 path.push_tail(i), g) by {
1053 if self.0.value().is_node() {
1054 self.pt_inv_unroll(i);
1055 let child = PageTableOwner(self.0.children()[i].unwrap());
1056 child.no_frame_with_path_rec(path.push_tail(i), removed_path, ambient);
1059 } else {
1060 PageTableOwner(self.0).pt_inv_non_node(i);
1061 }
1062 };
1063 }
1064 }
1065
1066 pub proof fn view_rec_disjoint_vaddrs(
1067 self,
1068 path: TreePath<NR_ENTRIES>,
1069 m1: Mapping,
1070 m2: Mapping,
1071 )
1072 requires
1073 self.pt_inv(),
1074 path.inv(),
1075 path.len() <= INC_LEVELS - 1,
1076 path.len() == self.0.level(),
1077 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1078 self.view_rec(path).contains(m1),
1079 self.view_rec(path).contains(m2),
1080 m1 != m2,
1081 ensures
1082 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start,
1083 decreases INC_LEVELS - path.len(),
1084 {
1085 broadcast use PageTableOwner::group_lemmas;
1086 broadcast use group_set_properties;
1087
1088 if self.0.value().is_frame() {
1089 } else if self.0.value().is_node() {
1090 let i1 = self.view_rec_contains_choose(path, m1);
1091 let i2 = self.view_rec_contains_choose(path, m2);
1092
1093 if i1 == i2 {
1094 self.pt_inv_unroll(i1);
1095 PageTableOwner(self.0.children()[i1].unwrap()).view_rec_disjoint_vaddrs(
1096 path.push_tail(i1),
1097 m1,
1098 m2,
1099 );
1100 } else {
1101 self.pt_inv_unroll(i1);
1102 self.pt_inv_unroll(i2);
1103 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel);
1104 PageTableOwner(self.0.children()[i1].unwrap()).view_rec_vaddr_range(
1105 path.push_tail(i1),
1106 m1,
1107 );
1108 PageTableOwner(self.0.children()[i2].unwrap()).view_rec_vaddr_range(
1109 path.push_tail(i2),
1110 m2,
1111 );
1112 if i1 < i2 {
1113 sibling_paths_disjoint::<C>(path, i1, i2, child_ps);
1114 } else {
1115 sibling_paths_disjoint::<C>(path, i2, i1, child_ps);
1116 }
1117 lemma_vaddr_of_eq_int::<C>(path.push_tail(i1));
1121 lemma_vaddr_of_eq_int::<C>(path.push_tail(i2));
1122 }
1123 }
1124 }
1125
1126 pub proof fn view_rec_mapping_page_size(self, path: TreePath<NR_ENTRIES>)
1133 requires
1134 self.pt_inv(),
1135 path.len() <= INC_LEVELS - 1,
1136 path.len() == self.0.level(),
1137 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1138 ensures
1139 forall|m: Mapping| #[trigger]
1140 self.view_rec(path).contains(m)
1141 ==> set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size),
1142 decreases INC_LEVELS - path.len(),
1143 {
1144 broadcast use PageTableOwner::group_lemmas;
1145
1146 if self.0.value().is_frame() {
1147 lemma_page_size_spec_values();
1148 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
1149 assert forall|m: Mapping| #[trigger]
1150 self.view_rec(path).contains(
1151 m,
1152 ) implies set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size) by {
1153 let i = choose|i: int|
1154 #![trigger self.0.children()[i]]
1155 0 <= i < self.0.children().len() && self.0.children()[i] is Some
1156 && PageTableOwner(self.0.children()[i].unwrap()).view_rec(
1157 path.push_tail(i),
1158 ).contains(m);
1159 self.pt_inv_unroll(i);
1160 let child = self.0.children()[i].unwrap();
1161 PageTableOwner(child).view_rec_mapping_page_size(path.push_tail(i));
1162 };
1163 }
1164 }
1165
1166 #[verifier::rlimit(200)]
1173 proof fn lemma_vaddr_path_alignment_and_bound(path: TreePath<NR_ENTRIES>)
1174 requires
1175 path.inv(),
1176 path.len() <= INC_LEVELS - 1,
1177 1 <= INC_LEVELS - path.len() <= NR_LEVELS,
1178 ensures
1179 vaddr(path) % page_size((INC_LEVELS - path.len()) as PagingLevel) == 0,
1180 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= usize::MAX,
1181 {
1182 lemma_page_size_spec_values();
1183 vstd::arithmetic::power2::lemma2_to64();
1184 vstd::arithmetic::power2::lemma2_to64_rest();
1185 broadcast use TreePath::lemma_index_satisfies_elem_inv;
1186 if path.len() == 0 {
1198 assert(rec_vaddr(path, 0) == 0);
1199 } else if path.len() == 1 {
1200 let i0 = path[0];
1201 assert(rec_vaddr(path, 1) == 0);
1202 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + rec_vaddr(
1203 path,
1204 1,
1205 )) as usize);
1206 } else if path.len() == 2 {
1207 let i0 = path[0];
1208 let i1 = path[1];
1209 assert(rec_vaddr(path, 2) == 0);
1210 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + rec_vaddr(
1211 path,
1212 2,
1213 )) as usize);
1214 let s = 0x80_0000_0000usize * i0 + 0x4000_0000usize * i1;
1215 } else if path.len() == 3 {
1216 let i0 = path[0];
1217 let i1 = path[1];
1218 let i2 = path[2];
1219 assert(rec_vaddr(path, 3) == 0);
1220 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + rec_vaddr(
1221 path,
1222 3,
1223 )) as usize);
1224 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + rec_vaddr(
1225 path,
1226 1,
1227 )) as usize);
1228 let s = 0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2;
1229 assert(rec_vaddr(path, 0) == s);
1230 assert(s % 0x20_0000 == 0) by (nonlinear_arith)
1231 requires
1232 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2,
1233 ;
1234 } else {
1235 assert(path.len() == 4);
1236 let i0 = path[0];
1237 let i1 = path[1];
1238 let i2 = path[2];
1239 let i3 = path[3];
1240 assert(rec_vaddr(path, 4) == 0);
1241 assert(rec_vaddr(path, 3) == (vaddr_make::<NR_LEVELS>(3, i3 as usize) + rec_vaddr(
1242 path,
1243 4,
1244 )) as usize);
1245 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + rec_vaddr(
1246 path,
1247 2,
1248 )) as usize);
1249 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + rec_vaddr(
1250 path,
1251 1,
1252 )) as usize);
1253 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
1254 + 0x1000usize * i3) as int;
1255 assert(s + 0x1000 <= usize::MAX) by (nonlinear_arith)
1256 requires
1257 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3,
1258 i0 < 512,
1259 i1 < 512,
1260 i2 < 512,
1261 i3 < 512,
1262 ;
1263 }
1264 }
1265
1266 pub proof fn view_rec_mapping_inv(self, path: TreePath<NR_ENTRIES>)
1275 requires
1276 self.pt_inv(),
1277 path.inv(),
1278 path.len() <= INC_LEVELS - 1,
1279 path.len() == self.0.level(),
1280 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1281 ensures
1282 forall|m: Mapping| #[trigger] self.view_rec(path).contains(m) ==> m.inv(),
1283 decreases INC_LEVELS - path.len(),
1284 {
1285 broadcast use PageTableOwner::group_lemmas;
1286
1287 if self.0.value().is_frame() {
1288 lemma_page_size_spec_values();
1289 let frame = self.0.value().frame();
1290 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1291 Self::lemma_vaddr_path_alignment_and_bound(path);
1292 let m = Mapping {
1293 va_range: Range {
1294 start: vaddr_of::<C>(path) as int,
1295 end: vaddr_of::<C>(path) + page_size(pt_level),
1296 },
1297 pa_range: Range {
1298 start: frame.mapped_pa,
1299 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1300 },
1301 page_size: page_size(pt_level),
1302 property: frame.prop,
1303 };
1304
1305 let ps = page_size(pt_level) as int;
1306 vstd_extra::arithmetic::lemma_mod_0_add(frame.mapped_pa as int, ps, ps);
1307 lemma_vaddr_of_eq_int::<C>(path);
1308 C::lemma_page_table_config_constant_properties();
1309 lemma_vaddr_strict_bound(path);
1310 let lb = C::LEADING_BITS_spec() as int;
1311 vstd::arithmetic::power2::lemma2_to64_rest();
1312 assert(lb * 0x1_0000_0000_0000int % ps == 0) by (nonlinear_arith)
1316 requires
1317 lb >= 0,
1318 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int),
1319 ;
1320 vstd::arithmetic::div_mod::lemma_mod_adds(
1321 vaddr(path) as int,
1322 lb * 0x1_0000_0000_0000int,
1323 ps,
1324 );
1325 let v = vaddr(path) as int;
1328 let limit = 0x1_0000_0000_0000int;
1329 assert(limit % ps == 0) by {
1330 if ps == 0x1000int {
1331 assert(0x1_0000_0000_0000int % 0x1000int == 0) by (compute_only);
1332 } else if ps == 0x20_0000int {
1333 assert(0x1_0000_0000_0000int % 0x20_0000int == 0) by (compute_only);
1334 } else {
1335 assert(0x1_0000_0000_0000int % 0x4000_0000int == 0) by (compute_only);
1336 }
1337 };
1338 vstd::arithmetic::div_mod::lemma_mod_equivalence(limit, v, ps);
1339 let diff = limit - v;
1340 let q = diff / ps;
1341 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(diff, ps);
1342 assert(q >= 1) by (nonlinear_arith)
1343 requires
1344 diff > 0,
1345 ps > 0,
1346 diff == ps * q,
1347 ;
1348 vstd::arithmetic::mul::lemma_mul_inequality(1, q, ps);
1349 vstd::arithmetic::mul::lemma_mul_inequality(lb, 0xffffint, 0x1_0000_0000_0000int);
1350 assert(v + ps <= limit) by (nonlinear_arith)
1351 requires
1352 q >= 1,
1353 ps > 0,
1354 diff == ps * q,
1355 diff == limit - v,
1356 ;
1357 assert(0xffffint * 0x1_0000_0000_0000int + 0x1_0000_0000_0000int
1358 == 0x1_0000_0000_0000_0000int) by (compute_only);
1359 assert(lb * limit + v + ps <= 0x1_0000_0000_0000_0000int);
1360 vstd_extra::arithmetic::lemma_mod_0_add(m.va_range.start, ps, ps);
1361 assert(set![4096, 2097152, 1073741824].contains(m.page_size));
1362 assert(m.pa_range.start <= m.pa_range.end <= MAX_PADDR);
1363 assert forall|m2: Mapping| #[trigger]
1364 self.view_rec(path).contains(m2) implies m2.inv() by {};
1365 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
1366 assert forall|m: Mapping| #[trigger]
1367 self.view_rec(path).contains(m) implies m.inv() by {
1368 let i = choose|i: int|
1369 #![trigger self.0.children()[i]]
1370 0 <= i < self.0.children().len() && self.0.children()[i] is Some
1371 && PageTableOwner(self.0.children()[i].unwrap()).view_rec(
1372 path.push_tail(i),
1373 ).contains(m);
1374 self.pt_inv_unroll(i);
1375 let child = self.0.children()[i].unwrap();
1376 PageTableOwner(child).view_rec_mapping_inv(path.push_tail(i));
1377 };
1378 }
1379 }
1380
1381 pub proof fn view_rec_absent_empty(self, path: TreePath<NR_ENTRIES>)
1383 requires
1384 self.0.inv(),
1385 self.0.value().is_absent(),
1386 path.len() <= INC_LEVELS - 1,
1387 ensures
1388 self.view_rec(path) == set![],
1389 {
1390 }
1391
1392 pub proof fn view_rec_nr_children_zero_empty(self, path: TreePath<NR_ENTRIES>)
1403 requires
1404 self.pt_inv(),
1405 self.0.value().is_node(),
1406 self.0.value().node().meta_own.nr_children.value() == 0,
1407 self.0.value().node().count_consistent(),
1408 path.len() <= INC_LEVELS - 1,
1409 path.len() == self.0.level(),
1410 ensures
1411 self.view_rec(path) == set![],
1412 {
1413 if path.len() < INC_LEVELS - 1 {
1414 let cp = self.0.value().node().children_perm.value();
1415 self.lemma_view_rec_contains(path);
1417 assert forall|m: Mapping| self.view_rec(path).contains(m) implies false by {
1418 let i = choose|i: int|
1419 #![trigger self.0.children()[i]]
1420 0 <= i < self.0.children().len() && self.0.children()[i] is Some
1421 && PageTableOwner(self.0.children()[i]->0).view_rec(
1422 path.push_tail(i),
1423 ).contains(m);
1424 self.pt_inv_unroll(i);
1425 if cp[i].is_present() {
1427 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_present(
1428 cp,
1429 cp.len() as int,
1430 i,
1431 );
1432 }
1433 };
1439 }
1440 }
1441
1442 pub open spec fn metaregion_sound_pred(regions: MetaRegionOwners) -> (spec_fn(
1443 EntryOwner<C>,
1444 TreePath<NR_ENTRIES>,
1445 ) -> bool) {
1446 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions)
1447 }
1448
1449 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool
1450 decreases INC_LEVELS - self.0.level(),
1451 when self.0.inv()
1452 {
1453 self.0.subtree_satisfies(self.0.value().path, Self::metaregion_sound_pred(regions))
1454 }
1455
1456 pub proof fn metaregion_sound_preserved_slot_owners_eq(
1461 self,
1462 r0: MetaRegionOwners,
1463 r1: MetaRegionOwners,
1464 )
1465 requires
1466 self.inv(),
1467 self.metaregion_sound(r0),
1468 r0.slot_owners == r1.slot_owners,
1469 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1470 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1471 ensures
1472 self.metaregion_sound(r1),
1473 {
1474 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1475 self.0,
1476 self.0.value().path,
1477 r0,
1478 r1,
1479 );
1480 }
1481
1482 pub proof fn metaregion_sound_preserved_slot_owners_eq_subtree(
1484 subtree: OwnerSubtree<C>,
1485 path: TreePath<NR_ENTRIES>,
1486 r0: MetaRegionOwners,
1487 r1: MetaRegionOwners,
1488 )
1489 requires
1490 subtree.inv(),
1491 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r0)),
1492 r0.slot_owners == r1.slot_owners,
1493 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1494 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1495 ensures
1496 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r1)),
1497 decreases INC_LEVELS - subtree.level(),
1498 {
1499 if subtree.level() < INC_LEVELS - 1 {
1501 assert forall|i: int|
1502 #![trigger subtree.has_child(i)]
1503 0 <= i < NR_ENTRIES && subtree.has_child(i) implies subtree.child(
1504 i,
1505 ).subtree_satisfies(path.push_tail(i), Self::metaregion_sound_pred(r1)) by {
1506 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1507 subtree.child(i),
1508 path.push_tail(i),
1509 r0,
1510 r1,
1511 );
1512 }
1513 }
1514 }
1515
1516 pub proof fn metaregion_sound_preserved_one_slot_changed(
1522 self,
1523 r0: MetaRegionOwners,
1524 r1: MetaRegionOwners,
1525 changed_idx: int,
1526 )
1527 requires
1528 self.inv(),
1529 self.metaregion_sound(r0),
1530 forall|i: int|
1531 #![trigger r1.slot_owners[i]]
1532 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1533 r0.slot_owners.dom() == r1.slot_owners.dom(),
1534 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1535 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1536 self.0.subtree_satisfies(
1538 self.0.value().path,
1539 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1540 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr()->0)
1541 != changed_idx,
1542 ),
1543 self.0.subtree_satisfies(
1547 self.0.value().path,
1548 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1549 e.is_frame() && e.parent_level > 1 ==> {
1550 let pa = e.frame().mapped_pa;
1551 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1552 forall|j: usize|
1553 0 < j < nr_pages ==> {
1554 let sub_idx = #[trigger] frame_to_index(
1555 (pa + j * PAGE_SIZE) as usize,
1556 );
1557 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1558 && r1.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1559 && r1.slot_owners[sub_idx].ref_count() > 0
1560 && r1.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX)
1561 }
1562 },
1563 ),
1564 ensures
1565 self.metaregion_sound(r1),
1566 {
1567 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1568 self.0,
1569 self.0.value().path,
1570 r0,
1571 r1,
1572 changed_idx,
1573 );
1574 }
1575
1576 pub proof fn metaregion_sound_preserved_one_slot_changed_subtree(
1577 subtree: OwnerSubtree<C>,
1578 path: TreePath<NR_ENTRIES>,
1579 r0: MetaRegionOwners,
1580 r1: MetaRegionOwners,
1581 changed_idx: int,
1582 )
1583 requires
1584 subtree.inv(),
1585 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r0)),
1586 forall|i: int|
1587 #![trigger r1.slot_owners[i]]
1588 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1589 r0.slot_owners.dom() == r1.slot_owners.dom(),
1590 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1591 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1592 subtree.subtree_satisfies(
1593 path,
1594 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1595 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr()->0)
1596 != changed_idx,
1597 ),
1598 subtree.subtree_satisfies(
1599 path,
1600 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1601 e.is_frame() && e.parent_level > 1 ==> {
1602 let pa = e.frame().mapped_pa;
1603 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1604 forall|j: usize|
1605 0 < j < nr_pages ==> {
1606 let sub_idx = #[trigger] frame_to_index(
1607 (pa + j * PAGE_SIZE) as usize,
1608 );
1609 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1610 && r1.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1611 && r1.slot_owners[sub_idx].ref_count() > 0
1612 && r1.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX)
1613 }
1614 },
1615 ),
1616 ensures
1617 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r1)),
1618 decreases INC_LEVELS - subtree.level(),
1619 {
1620 if subtree.level() < INC_LEVELS - 1 {
1621 assert forall|i: int|
1622 #![trigger subtree.has_child(i)]
1623 0 <= i < NR_ENTRIES && subtree.has_child(i) implies subtree.child(
1624 i,
1625 ).subtree_satisfies(path.push_tail(i), Self::metaregion_sound_pred(r1)) by {
1626 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1627 subtree.child(i),
1628 path.push_tail(i),
1629 r0,
1630 r1,
1631 changed_idx,
1632 );
1633 }
1634 }
1635 }
1636
1637 pub open spec fn path_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
1640 EntryOwner<C>,
1641 TreePath<NR_ENTRIES>,
1642 ) -> bool {
1643 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1644 {
1645 entry.is_node() && entry.meta_slot_paddr() is Some ==> {
1647 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr()->0))
1648 &&& regions.slot_owner(entry.meta_slot_paddr()->0).paths_in_pt
1649 == set![entry.path]
1650 }
1651 }
1652 }
1653
1654 pub open spec fn relate_region_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
1655 EntryOwner<C>,
1656 TreePath<NR_ENTRIES>,
1657 ) -> bool {
1658 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1659 {
1660 &&& entry.meta_slot_paddr() is Some
1661 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr()->0))
1662 &&& regions.slot_owner(entry.meta_slot_paddr()->0).paths_in_pt == set![path]
1663 }
1664 }
1665
1666 pub open spec fn path_correct_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
1667 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| { entry.path == path }
1668 }
1669
1670 pub open spec fn not_in_scope_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
1671 |entry: EntryOwner<C>, _path: TreePath<NR_ENTRIES>| true
1672 }
1673
1674 pub proof fn tree_not_in_scope(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
1676 requires
1677 subtree.inv(),
1678 ensures
1679 subtree.subtree_satisfies(path, Self::not_in_scope_pred()),
1680 decreases INC_LEVELS - subtree.level(),
1681 {
1682 if subtree.level() < INC_LEVELS - 1 {
1684 assert forall|i: int|
1685 0 <= i < subtree.children().len() && (
1686 #[trigger] subtree.children()[i]) is Some implies subtree.children()[i].unwrap().subtree_satisfies(
1687 path.push_tail(i), Self::not_in_scope_pred()) by {
1688 Self::tree_not_in_scope(subtree.children()[i].unwrap(), path.push_tail(i));
1689 };
1690 }
1691 }
1692
1693 pub proof fn view_rec_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1696 requires
1697 self.0.inv(),
1698 path.len() <= INC_LEVELS - 1,
1699 self.view_rec(path).contains(m),
1700 ensures
1701 m.page_size <= page_size((INC_LEVELS - path.len()) as PagingLevel),
1702 decreases INC_LEVELS - path.len(),
1703 {
1704 broadcast use PageTableOwner::group_lemmas;
1705
1706 if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
1707 let i = choose|i: int|
1708 #![trigger self.0.children()[i]]
1709 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
1710 self.0.children()[i].unwrap(),
1711 ).view_rec(path.push_tail(i)).contains(m);
1712 PageTableOwner(self.0.children()[i].unwrap()).view_rec_page_size_bound(
1713 path.push_tail(i),
1714 m,
1715 );
1716 page_size_monotonic(
1717 (INC_LEVELS - path.len() - 1) as PagingLevel,
1718 (INC_LEVELS - path.len()) as PagingLevel,
1719 );
1720 }
1721 }
1722
1723 pub proof fn view_rec_node_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1726 requires
1727 self.0.inv(),
1728 self.0.value().is_node(),
1729 path.len() < INC_LEVELS - 1,
1730 self.view_rec(path).contains(m),
1731 ensures
1732 m.page_size <= page_size(((INC_LEVELS - path.len()) - 1) as PagingLevel),
1733 decreases INC_LEVELS - path.len(),
1734 {
1735 broadcast use PageTableOwner::group_lemmas;
1736
1737 let i = choose|i: int|
1738 #![trigger self.0.children()[i]]
1739 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
1740 self.0.children()[i].unwrap(),
1741 ).view_rec(path.push_tail(i)).contains(m);
1742 PageTableOwner(self.0.children()[i].unwrap()).view_rec_page_size_bound(
1743 path.push_tail(i),
1744 m,
1745 );
1746 }
1747
1748 pub open spec fn is_prefix_of<const N: usize>(prefix: TreePath<N>, path: TreePath<N>) -> bool {
1750 &&& prefix.len() <= path.len()
1751 &&& forall|i: int| 0 <= i < prefix.len() ==> prefix[i] == path[i]
1752 }
1753
1754 pub proof fn prefix_transitive<const N: usize>(
1756 p1: TreePath<N>,
1757 p2: TreePath<N>,
1758 p3: TreePath<N>,
1759 )
1760 requires
1761 Self::is_prefix_of(p1, p2),
1762 Self::is_prefix_of(p2, p3),
1763 ensures
1764 Self::is_prefix_of(p1, p3),
1765 {
1766 }
1767
1768 pub proof fn prefix_push_different_indices(
1769 prefix: TreePath<NR_ENTRIES>,
1770 path: TreePath<NR_ENTRIES>,
1771 i: int,
1772 j: int,
1773 )
1774 requires
1775 prefix.inv(),
1776 path.inv(),
1777 i != j,
1778 Self::is_prefix_of(prefix.push_tail(i), path),
1779 ensures
1780 !Self::is_prefix_of(prefix.push_tail(j), path),
1781 {
1782 assert(path[prefix.len() as int] == i);
1783 }
1784
1785 pub proof fn prefix_push_tail_implies_prefix<const N: usize>(
1786 prefix: TreePath<N>,
1787 path: TreePath<N>,
1788 i: int,
1789 )
1790 requires
1791 prefix.inv(),
1792 path.inv(),
1793 0 <= i < N,
1794 Self::is_prefix_of(prefix.push_tail(i), path),
1795 ensures
1796 Self::is_prefix_of(prefix, path),
1797 {
1798 }
1799
1800 pub open spec fn is_at_pred(entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>) -> spec_fn(
1801 EntryOwner<C>,
1802 TreePath<NR_ENTRIES>,
1803 ) -> bool {
1804 |entry0: EntryOwner<C>, path0: TreePath<NR_ENTRIES>| { path0 == path ==> entry0 == entry }
1805 }
1806
1807 pub open spec fn path_in_tree_pred(path: TreePath<NR_ENTRIES>) -> spec_fn(
1808 EntryOwner<C>,
1809 TreePath<NR_ENTRIES>,
1810 ) -> bool {
1811 |entry: EntryOwner<C>, path0: TreePath<NR_ENTRIES>|
1812 Self::is_prefix_of(path0, path) ==> !entry.is_node() ==> path == path0
1813 }
1814
1815 pub proof fn is_at_pred_eq(
1816 path: TreePath<NR_ENTRIES>,
1817 entry1: EntryOwner<C>,
1818 entry2: EntryOwner<C>,
1819 )
1820 requires
1821 entry1.inv(),
1822 OwnerSubtree::implies(Self::is_at_pred(entry1, path), Self::is_at_pred(entry2, path)),
1823 ensures
1824 entry1 == entry2,
1825 {
1826 assert(Self::is_at_pred(entry1, path)(entry1, path) ==> Self::is_at_pred(entry2, path)(
1827 entry1,
1828 path,
1829 ));
1830 }
1831
1832 pub proof fn is_at_holds_when_on_wrong_path(
1833 subtree: OwnerSubtree<C>,
1834 root_path: TreePath<NR_ENTRIES>,
1835 dest_path: TreePath<NR_ENTRIES>,
1836 entry: EntryOwner<C>,
1837 )
1838 requires
1839 subtree.inv(),
1840 PageTableOwner(subtree).pt_inv(),
1841 dest_path.inv(),
1842 !Self::is_prefix_of(root_path, dest_path),
1843 root_path.len() <= INC_LEVELS - 1,
1844 root_path.len() == subtree.level(),
1845 ensures
1846 subtree.subtree_satisfies(root_path, Self::is_at_pred(entry, dest_path)),
1847 decreases INC_LEVELS - root_path.len(),
1848 {
1849 if subtree.level() < INC_LEVELS - 1 {
1850 if subtree.value().is_node() {
1851 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1852 #[trigger] subtree.children()[i as int]).unwrap().subtree_satisfies(
1853 root_path.push_tail(i),
1854 Self::is_at_pred(entry, dest_path),
1855 ) by {
1856 PageTableOwner(subtree).pt_inv_unroll(i);
1857 Self::is_at_holds_when_on_wrong_path(
1858 subtree.children()[i as int].unwrap(),
1859 root_path.push_tail(i),
1860 dest_path,
1861 entry,
1862 );
1863 };
1864 } else {
1865 }
1866 }
1867 }
1868
1869 pub proof fn path_in_tree_holds_when_on_wrong_path(
1873 subtree: OwnerSubtree<C>,
1874 root_path: TreePath<NR_ENTRIES>,
1875 dest_path: TreePath<NR_ENTRIES>,
1876 )
1877 requires
1878 subtree.inv(),
1879 PageTableOwner(subtree).pt_inv(),
1880 dest_path.inv(),
1881 !Self::is_prefix_of(root_path, dest_path),
1882 root_path.len() <= INC_LEVELS - 1,
1883 root_path.len() == subtree.level(),
1884 ensures
1885 subtree.subtree_satisfies(root_path, Self::path_in_tree_pred(dest_path)),
1886 decreases INC_LEVELS - root_path.len(),
1887 {
1888 if subtree.level() < INC_LEVELS - 1 {
1889 if subtree.value().is_node() {
1890 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1891 #[trigger] subtree.children()[i as int]).unwrap().subtree_satisfies(
1892 root_path.push_tail(i),
1893 Self::path_in_tree_pred(dest_path),
1894 ) by {
1895 PageTableOwner(subtree).pt_inv_unroll(i);
1896 Self::path_in_tree_holds_when_on_wrong_path(
1897 subtree.children()[i as int].unwrap(),
1898 root_path.push_tail(i),
1899 dest_path,
1900 );
1901 };
1902 } else {
1903 }
1904 }
1905 }
1906
1907 pub proof fn neq_old_from_path_disjoint(
1910 subtree: OwnerSubtree<C>,
1911 path_j: TreePath<NR_ENTRIES>,
1912 old_entry: EntryOwner<C>,
1913 regions: MetaRegionOwners,
1914 )
1915 requires
1916 subtree.inv(),
1917 subtree.value().path == path_j,
1918 path_j.len() == subtree.level(),
1919 path_j.inv(),
1920 path_j.len() <= INC_LEVELS - 1,
1921 subtree.subtree_satisfies(path_j, Self::metaregion_sound_pred(regions)),
1922 subtree.subtree_satisfies(path_j, Self::path_correct_pred()),
1923 old_entry.is_node(),
1924 old_entry.meta_slot_paddr() is Some,
1925 regions.slot_owner(old_entry.meta_slot_paddr()->0).paths_in_pt == set![old_entry.path],
1926 !Self::is_prefix_of(path_j, old_entry.path),
1927 ensures
1928 subtree.subtree_satisfies(
1929 path_j,
1930 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry),
1931 ),
1932 decreases INC_LEVELS - subtree.level(),
1933 {
1934 let f_sound = Self::metaregion_sound_pred(regions);
1935 let f_path = Self::path_correct_pred();
1936 let g = |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry);
1937
1938 assert(g(subtree.value(), path_j)) by {
1939 assert(f_sound(subtree.value(), path_j));
1940 assert(f_path(subtree.value(), path_j));
1941 let entry = subtree.value();
1942 if entry.meta_slot_paddr() is Some && entry.meta_slot_paddr()->0
1943 == old_entry.meta_slot_paddr()->0 {
1944 let idx = frame_to_index(entry.meta_slot_paddr()->0);
1945 let old_idx = frame_to_index(old_entry.meta_slot_paddr()->0);
1946 assert(idx == old_idx);
1947 if entry.is_node() {
1948 assert(regions.slot_owners[idx].paths_in_pt == set![entry.path]);
1949 assert(regions.slot_owners[idx].paths_in_pt.contains(entry.path));
1950 } else {
1951 assert(entry.is_frame());
1952 assert(regions.slot_owners[idx].paths_in_pt.contains(entry.path));
1953 }
1954 assert(set![old_entry.path].contains(entry.path));
1955 assert(entry.path == old_entry.path);
1956 assert(Self::is_prefix_of(path_j, old_entry.path));
1957 }
1958 };
1959
1960 if subtree.level() < INC_LEVELS - 1 {
1961 assert forall|i: int|
1962 0 <= i < subtree.children().len() && (
1963 #[trigger] subtree.children()[i]) is Some implies subtree.children()[i].unwrap().subtree_satisfies(
1964 path_j.push_tail(i), g) by {
1965 let child = subtree.child(i);
1966 let child_path = path_j.push_tail(i);
1967 subtree.lemma_subtree_satisfies_unroll_once(path_j, f_sound, i);
1968 subtree.lemma_subtree_satisfies_unroll_once(path_j, f_path, i);
1969 Self::neq_old_from_path_disjoint(child, child_path, old_entry, regions);
1970 };
1971 }
1972 }
1973
1974 pub proof fn is_at_eq_rec(
1975 subtree: OwnerSubtree<C>,
1976 root_path: TreePath<NR_ENTRIES>,
1977 dest_path: TreePath<NR_ENTRIES>,
1978 entry1: EntryOwner<C>,
1979 entry2: EntryOwner<C>,
1980 )
1981 requires
1982 subtree.inv(),
1983 PageTableOwner(subtree).pt_inv(),
1984 dest_path.inv(),
1985 root_path.inv(),
1986 Self::is_prefix_of(root_path, dest_path),
1987 root_path.len() <= INC_LEVELS - 1,
1988 root_path.len() == subtree.level(),
1989 subtree.subtree_satisfies(root_path, Self::path_in_tree_pred(dest_path)),
1990 subtree.subtree_satisfies(root_path, Self::is_at_pred(entry1, dest_path)),
1991 subtree.subtree_satisfies(root_path, Self::is_at_pred(entry2, dest_path)),
1992 ensures
1993 entry1 == entry2,
1994 decreases INC_LEVELS - root_path.len(),
1995 {
1996 if root_path == dest_path {
1997 } else if subtree.level() == INC_LEVELS - 1 || !subtree.value().is_node() {
1998 proof_from_false()
1999 } else {
2000 if root_path.len() == dest_path.len() {
2001 assert forall|i: int| 0 <= i < root_path.0.len() implies #[trigger] root_path.0[i]
2002 == dest_path.0[i] by {
2003 assert(root_path[i] == dest_path[i]);
2004 };
2005 assert(root_path == dest_path);
2006 assert(false);
2007 }
2008 let i = dest_path[root_path.len() as int];
2009 PageTableOwner(subtree).pt_inv_unroll(i as int);
2010 Self::is_at_eq_rec(
2011 subtree.children()[i as int].unwrap(),
2012 root_path.push_tail(i),
2013 dest_path,
2014 entry1,
2015 entry2,
2016 );
2017 }
2018 }
2019
2020 pub proof fn view_rec_inversion(
2021 self,
2022 path: TreePath<NR_ENTRIES>,
2023 regions: MetaRegionOwners,
2024 m: Mapping,
2025 ) -> (entry: EntryOwner<C>)
2026 requires
2027 self.pt_inv(),
2028 path.len() == self.0.level(),
2029 self.view_rec(path).contains(m),
2030 self.0.subtree_satisfies(path, Self::path_correct_pred()),
2031 self.0.subtree_satisfies(path, Self::relate_region_tracked_pred(regions)),
2032 ensures
2033 Self::is_prefix_of(path, entry.path),
2034 regions.slot_owner(m.pa_range.start).paths_in_pt == set![entry.path],
2035 m.va_range.start == vaddr_of::<C>(entry.path),
2036 m.page_size == page_size((INC_LEVELS - entry.path.len()) as PagingLevel),
2037 entry.is_frame(),
2038 m.property == entry.frame().prop,
2039 self.0.subtree_satisfies(path, Self::is_at_pred(entry, entry.path)),
2040 self.0.subtree_satisfies(path, Self::path_in_tree_pred(entry.path)),
2041 entry.inv(),
2042 decreases INC_LEVELS - path.len(),
2043 {
2044 broadcast use PageTableOwner::group_lemmas;
2045
2046 if self.0.value().is_frame() {
2047 self.0.value()
2048 } else if self.0.value().is_node() {
2049 let i = self.view_rec_contains_choose(path, m);
2050 self.pt_inv_unroll(i);
2051 let entry = PageTableOwner(self.0.children()[i].unwrap()).view_rec_inversion(
2052 path.push_tail(i),
2053 regions,
2054 m,
2055 );
2056 assert forall|j: int|
2057 0 <= j < NR_ENTRIES
2058 && #[trigger] self.0.children()[j] is Some implies self.0.children()[j].unwrap().subtree_satisfies(
2059 path.push_tail(j), Self::is_at_pred(entry, entry.path)) by {
2060 if j != i {
2061 self.pt_inv_unroll(j);
2062 Self::is_at_holds_when_on_wrong_path(
2063 self.0.children()[j].unwrap(),
2064 path.push_tail(j),
2065 entry.path,
2066 entry,
2067 );
2068 }
2069 };
2070
2071 assert forall|j: int|
2072 0 <= j < NR_ENTRIES && #[trigger] self.0.has_child(j) implies self.0.child(
2073 j,
2074 ).subtree_satisfies(path.push_tail(j), Self::path_in_tree_pred(entry.path)) by {
2075 if j != i {
2076 Self::path_in_tree_holds_when_on_wrong_path(
2077 self.0.child(j),
2078 path.push_tail(j),
2079 entry.path,
2080 );
2081 }
2082 };
2083 entry
2084 } else {
2085 proof_from_false()
2086 }
2087 }
2088
2089 pub proof fn view_rec_inversion_unique(
2090 self,
2091 path: TreePath<NR_ENTRIES>,
2092 regions: MetaRegionOwners,
2093 m1: Mapping,
2094 m2: Mapping,
2095 )
2096 requires
2097 self.pt_inv(),
2098 path.len() <= INC_LEVELS - 1,
2099 path.len() == self.0.level(),
2100 self.view_rec(path).contains(m1),
2101 self.view_rec(path).contains(m2),
2102 m1.pa_range.start == m2.pa_range.start,
2103 m1.inv(),
2104 m2.inv(),
2105 self.0.subtree_satisfies(path, Self::path_tracked_pred(regions)),
2106 self.0.subtree_satisfies(path, Self::path_correct_pred()),
2107 self.0.subtree_satisfies(path, Self::relate_region_tracked_pred(regions)),
2108 ensures
2109 m1 == m2,
2110 {
2111 let entry1 = self.view_rec_inversion(path, regions, m1);
2112 let entry2 = self.view_rec_inversion(path, regions, m2);
2113
2114 let idx = frame_to_index(m1.pa_range.start);
2116 assert(set![entry1.path].contains(entry2.path));
2117
2118 Self::is_at_eq_rec(self.0, path, entry1.path, entry1, entry2);
2119 }
2120
2121 pub broadcast group group_lemmas {
2122 PageTableOwner::lemma_view_rec_contains,
2123 PageTableOwner::lemma_view_rec_contains_intro,
2124 }
2125}
2126
2127impl<C: PageTableConfig> Inv for PageTableOwner<C> {
2128 open spec fn inv(self) -> bool {
2129 &&& self.0.inv()
2130 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level()) as nat)
2131 &&& self.0.value().is_node()
2132 &&& self.0.value().path.len() <= INC_LEVELS - 1
2133 &&& self.0.value().path.inv()
2134 &&& self.0.value().path.len() == self.0.level()
2135 &&& self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel
2136 &&& self.0.value().node().tree_level == self.0.value().path.len()
2137 &&& self.0.subtree_satisfies(self.0.value().path, Self::path_correct_pred())
2138 }
2139}
2140
2141impl<C: PageTableConfig> View for PageTableOwner<C> {
2142 type V = PageTableView;
2143
2144 open spec fn view(&self) -> <Self as View>::V {
2145 let mappings = self.view_rec(self.0.value().path);
2146 PageTableView { mappings }
2147 }
2148}
2149
2150}