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(
61 path: TreePath<NR_ENTRIES>,
62 idx: int,
63) -> usizedecreases path.len() - idx,
69 when 0 <= idx <= path.len()
70{
71 if idx == path.len() {
72 0
73 } else {
74 let offset = path[idx] as usize;
75 (vaddr_make::<NR_LEVELS>(idx, offset) + rec_vaddr(path, idx + 1)) as usize
76 }
77}
78
79pub open spec fn vaddr(path: TreePath<NR_ENTRIES>) -> usize {
80 rec_vaddr(path, 0)
81}
82
83pub open spec fn vaddr_at(path: TreePath<NR_ENTRIES>, leading_bits: int) -> usize {
90 (vaddr(path) + leading_bits * 0x1_0000_0000_0000int) as usize
91}
92
93pub open spec fn vaddr_of<C: PageTableConfig>(path: TreePath<NR_ENTRIES>) -> usize {
99 vaddr_at(path, C::LEADING_BITS_spec() as int)
100}
101
102#[verifier::spinoff_prover]
106pub proof fn lemma_vaddr_strict_bound(path: TreePath<NR_ENTRIES>)
107 requires
108 path.inv(),
109 path.len() <= INC_LEVELS - 1,
110 ensures
111 vaddr(path) < 0x1_0000_0000_0000int,
112{
113 vstd::arithmetic::power2::lemma2_to64();
114 vstd::arithmetic::power2::lemma2_to64_rest();
115 if path.len() == 0 {
116 } else if path.len() == 1 {
117 let i0 = path[0];
118 assert(rec_vaddr(path, 1) == 0);
119 } else if path.len() == 2 {
120 let i0 = path[0];
121 let i1 = path[1];
122 assert(rec_vaddr(path, 2) == 0);
123 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1 as usize) as usize);
124 } else if path.len() == 3 {
125 let i0 = path[0];
126 let i1 = path[1];
127 let i2 = path[2];
128 assert(rec_vaddr(path, 3) == 0);
129 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2 as usize) as usize);
130 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
131 NR_LEVELS,
132 >(2, i2 as usize)) as usize);
133 } else {
134 let i0 = path[0];
135 let i1 = path[1];
136 let i2 = path[2];
137 let i3 = path[3];
138 assert(rec_vaddr(path, 4) == 0);
139 assert(rec_vaddr(path, 3) == vaddr_make::<NR_LEVELS>(3, i3 as usize) as usize);
140 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<
141 NR_LEVELS,
142 >(3, i3 as usize)) as usize);
143 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
144 NR_LEVELS,
145 >(2, i2 as usize) + vaddr_make::<NR_LEVELS>(3, i3 as usize)) as usize);
146 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + vaddr_make::<
147 NR_LEVELS,
148 >(1, i1 as usize) + vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<NR_LEVELS>(
149 3,
150 i3 as usize,
151 )) as usize);
152 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2 + 0x1000usize
153 * i3 < 0x1_0000_0000_0000int) by (nonlinear_arith)
154 requires
155 i0 < 512,
156 i1 < 512,
157 i2 < 512,
158 i3 < 512,
159 ;
160 }
161}
162
163pub proof fn lemma_vaddr_top_index_cell(path: TreePath<NR_ENTRIES>)
167 requires
168 path.inv(),
169 1 <= path.len() <= INC_LEVELS - 1,
170 ensures
171 (path[0]) * 0x80_0000_0000int <= vaddr(path),
172 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= (path[0] + 1)
173 * 0x80_0000_0000int,
174{
175 broadcast use TreePath::lemma_index_satisfies_elem_inv;
176
177 lemma_page_size_spec_values();
178 vstd::arithmetic::power2::lemma2_to64();
179 vstd::arithmetic::power2::lemma2_to64_rest();
180 let i0 = path[0];
181 if path.len() == 1 {
182 assert(rec_vaddr(path, 1) == 0);
183 } else if path.len() == 2 {
184 let i1 = path[1];
185 assert(rec_vaddr(path, 2) == 0);
186 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1 as usize) as usize);
187 } else if path.len() == 3 {
188 let i1 = path[1];
189 let i2 = path[2];
190 assert(rec_vaddr(path, 3) == 0);
191 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2 as usize) as usize);
192 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
193 NR_LEVELS,
194 >(2, i2 as usize)) as usize);
195 } else {
196 let i1 = path[1];
197 let i2 = path[2];
198 let i3 = path[3];
199 assert(rec_vaddr(path, 4) == 0);
200 assert(rec_vaddr(path, 3) == vaddr_make::<NR_LEVELS>(3, i3 as usize) as usize);
201 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<
202 NR_LEVELS,
203 >(3, i3 as usize)) as usize);
204 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
205 NR_LEVELS,
206 >(2, i2 as usize) + vaddr_make::<NR_LEVELS>(3, i3 as usize)) as usize);
207 assert(0x80_0000_0000int * i0 + 0x4000_0000int * i1 + 0x20_0000int * i2 + 0x1000int * i3
208 + 0x1000int <= (i0 + 1) * 0x80_0000_0000int) by (nonlinear_arith)
209 requires
210 i1 < 512,
211 i2 < 512,
212 i3 < 512,
213 ;
214 }
215}
216
217pub proof fn lemma_vaddr_of_eq_int<C: PageTableConfig>(path: TreePath<NR_ENTRIES>)
221 requires
222 path.inv(),
223 path.len() <= INC_LEVELS - 1,
224 ensures
225 vaddr_of::<C>(path) == vaddr(path) + C::LEADING_BITS_spec() as int * 0x1_0000_0000_0000int,
226{
227 C::lemma_page_table_config_constant_properties();
228 lemma_vaddr_strict_bound(path);
229}
230
231pub proof fn page_size_monotonic(a: PagingLevel, b: PagingLevel)
233 requires
234 1 <= a <= b <= NR_LEVELS + 1,
235 ensures
236 page_size(a) <= page_size(b),
237{
238 if a == b {
239 } else {
240 let ps_a = page_size(a);
241 let ps_b = page_size(b);
242
243 lemma_page_size_ge_page_size(b);
244
245 lemma_page_size_divides(a, b);
246
247 assert(ps_a <= ps_b) by {
248 if ps_b < ps_a {
249 vstd::arithmetic::div_mod::lemma_small_mod(ps_b as nat, ps_a as nat);
250 assert(false);
251 }
252 }
253 }
254}
255
256pub proof fn sibling_paths_disjoint<C: PageTableConfig>(
263 prefix: TreePath<NR_ENTRIES>,
264 j: int,
265 k: int,
266 size: usize,
267)
268 requires
269 prefix.inv(),
270 prefix.len() < INC_LEVELS - 1,
271 0 <= j,
272 0 <= k,
273 j < NR_ENTRIES,
274 k < NR_ENTRIES,
275 j != k,
276 size == page_size((INC_LEVELS - prefix.len() - 1) as PagingLevel),
277 ensures
278 vaddr(prefix.push_tail(j)) + size <= vaddr(prefix.push_tail(k)) || vaddr(
279 prefix.push_tail(k),
280 ) + size <= vaddr(prefix.push_tail(j)),
281{
282 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, j);
283 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, k);
284 let s = size as int;
285 let vp = vaddr(prefix) as int;
286 let vj = vaddr(prefix.push_tail(j)) as int;
287 let vk = vaddr(prefix.push_tail(k)) as int;
288 if j < k {
289 assert(vj + s <= vk) by (nonlinear_arith)
290 requires
291 vj == vp + j * s,
292 vk == vp + k * s,
293 j < k,
294 s >= 0,
295 ;
296 } else {
297 assert(vk + s <= vj) by (nonlinear_arith)
298 requires
299 vj == vp + j * s,
300 vk == vp + k * s,
301 k < j,
302 s >= 0,
303 ;
304 }
305}
306
307impl<C: PageTableConfig, const L: usize> TreeNodeValue<L> for EntryOwner<C> {
308 open spec fn default(lv: nat) -> Self {
309 Self {
310 kind: EntryOwnerKind::Absent,
311 path: TreePath::new(Seq::empty()),
312 parent_level: (INC_LEVELS - lv) as PagingLevel,
313 }
314 }
315
316 proof fn lemma_default_preserves_inv() {
317 }
318
319 open spec fn la_inv(self, lv: nat) -> bool {
320 self.is_node() ==> lv < L - 1
321 }
322
323 proof fn lemma_default_preserves_la_inv() {
324 }
325
326 open spec fn rel_children(self, i: int, child: Option<Self>) -> bool {
329 true
330 }
331
332 proof fn lemma_default_preserves_rel_children(self, lv: nat) {
333 }
334}
335
336pub const INC_LEVELS: usize = NR_LEVELS + 1;
337
338pub type OwnerSubtree<C> = TreeNode<EntryOwner<C>, NR_ENTRIES, INC_LEVELS>;
348
349pub open spec fn allocated_empty_node_owner<C: PageTableConfig>(
358 owner: OwnerSubtree<C>,
359 level: PagingLevel,
360) -> bool {
361 &&& owner.inv()
362 &&& owner.value().is_node()
363 &&& owner.value().path == TreePath::<NR_ENTRIES>::new(Seq::empty())
364 &&& owner.value().parent_level == (level + 1) as PagingLevel
365 &&& owner.value().node().level
366 == level
367 &&& owner.level() == (INC_LEVELS - level - 1) as nat
372 &&& owner.value().node().inv()
373 &&& !owner.value().node().children_perm.value().all(|child: C::E| child.is_present())
374 &&& forall|i: int|
375 0 <= i < NR_ENTRIES ==> {
376 &&& #[trigger] owner.has_child(i)
377 &&& owner.child(i).value().is_absent()
378 &&& owner.child(i).value().inv()
379 &&& owner.child(i).value().path == owner.value().path.push_tail(i)
380 }
381 &&& forall|i: int|
382 #![auto]
383 0 <= i < NR_ENTRIES ==> owner.child(i).value().match_pte(
384 owner.value().node().children_perm.value()[i],
385 owner.child(i).value().parent_level,
386 )
387 &&& forall|i: int|
388 #![auto]
389 0 <= i < NR_ENTRIES ==> owner.child(i).value().parent_level
390 == owner.value().node().level
391 &&& forall|j: int|
396 0 <= j < NR_ENTRIES ==> #[trigger] owner.value().node().children_perm.value()[j]
397 == C::E::new_absent_spec()
398}
399
400pub open spec fn allocated_empty_node_grandchildren_none<C: PageTableConfig>(
408 owner: OwnerSubtree<C>,
409) -> bool {
410 forall|i: int, j: int|
411 0 <= i < NR_ENTRIES && 0 <= j < NR_ENTRIES ==> !#[trigger] owner.child(i).has_child(j)
412}
413
414pub proof fn rebase_freshly_allocated_children_at<C: PageTableConfig>(
419 tracked owner: &mut OwnerSubtree<C>,
420 new_path: TreePath<NR_ENTRIES>,
421 i: usize,
422)
423 requires
424 i <= NR_ENTRIES,
425 old(owner).children().len() == NR_ENTRIES,
426 new_path.inv(),
427 forall|j: int| i <= j < NR_ENTRIES ==> (#[trigger] old(owner).children()[j]) is Some,
428 ensures
429 final(owner).value() == old(owner).value(),
430 final(owner).level() == old(owner).level(),
431 final(owner).children().len() == NR_ENTRIES,
432 forall|j: int|
433 0 <= j < i ==> (#[trigger] final(owner).children()[j]) == old(owner).children()[j],
434 forall|j: int|
435 i <= j < NR_ENTRIES ==> {
436 let c_old = old(owner).child(j);
437 let c_new = (#[trigger] final(owner).children()[j])->0;
438 &&& final(owner).has_child(j)
439 &&& c_new.value() == EntryOwner { path: new_path.push_tail(j), ..c_old.value() }
440 &&& c_new.level() == c_old.level()
441 &&& c_new.children() == c_old.children()
442 },
443 decreases NR_ENTRIES - i,
444{
445 if i < NR_ENTRIES {
446 let tracked mut child_value = owner.tracked_borrow_mut_child(
447 i as int,
448 ).tracked_borrow_mut_value();
449 child_value.path = new_path.push_tail(i as int);
450 rebase_freshly_allocated_children_at(owner, new_path, (i + 1) as usize);
451 }
452}
453
454pub proof fn rebase_freshly_allocated_children<C: PageTableConfig>(
464 tracked owner: &mut OwnerSubtree<C>,
465 new_path: TreePath<NR_ENTRIES>,
466)
467 requires
468 old(owner).children().len() == NR_ENTRIES,
469 new_path.inv(),
470 forall|i: int| 0 <= i < NR_ENTRIES ==> (#[trigger] old(owner).children()[i]) is Some,
471 ensures
472 final(owner).value() == old(owner).value(),
473 final(owner).level() == old(owner).level(),
474 final(owner).children().len() == NR_ENTRIES,
475 forall|i: int|
476 0 <= i < NR_ENTRIES ==> {
477 let c_old = old(owner).child(i);
478 let c_new = (#[trigger] final(owner).children()[i])->0;
479 &&& final(owner).has_child(i)
480 &&& c_new.value() == EntryOwner { path: new_path.push_tail(i), ..c_old.value() }
481 &&& c_new.level() == c_old.level()
482 &&& c_new.children() == c_old.children()
483 },
484{
485 rebase_freshly_allocated_children_at(owner, new_path, 0);
486}
487
488pub proof fn fresh_node_subtree_satisfies<C: PageTableConfig>(
497 node: OwnerSubtree<C>,
498 path: TreePath<NR_ENTRIES>,
499 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
500)
501 requires
502 node.inv(),
503 node.level() < INC_LEVELS - 1,
504 f(node.value(), path),
505 forall|i: int| 0 <= i < NR_ENTRIES ==> #[trigger] node.has_child(i),
506 forall|i: int, j: int|
507 0 <= i < NR_ENTRIES && 0 <= j < NR_ENTRIES ==> !#[trigger] node.child(i).has_child(j),
508 forall|i: int|
509 0 <= i < NR_ENTRIES ==> #[trigger] f(node.child(i).value(), path.push_tail(i)),
510 ensures
511 node.subtree_satisfies(path, f),
512{
513 assert forall|i: int|
514 0 <= i < node.children().len() && #[trigger] node.has_child(i) implies node.child(
515 i,
516 ).subtree_satisfies(path.push_tail(i), f) by {
517 assert(node.child(i).inv());
520 };
521}
522
523pub tracked struct PageTableOwner<C: PageTableConfig>(pub OwnerSubtree<C>);
530
531impl<C: PageTableConfig> PageTableOwner<C> {
532 pub open spec fn pt_edge_at(parent: OwnerSubtree<C>, i: int) -> bool {
534 &&& parent.has_child(i)
535 &&& parent.child(i).value().path.len() == parent.value().node().tree_level
536 + 1
537 &&& (parent.child(i).value().match_pte(
545 parent.value().node().children_perm.value()[i],
546 parent.value().node().level,
547 ) || (parent.value().node().level == NR_LEVELS && C::LEADING_BITS_spec() == 0
548 && parent.child(i).value().borrowed_match_pte(
549 parent.value().node().children_perm.value()[i],
550 parent.value().node().level,
551 )))
552 &&& parent.child(i).value().path == parent.value().path.push_tail(i)
553 &&& parent.child(i).value().parent_level == parent.value().node().level
554 }
555
556 pub open spec fn pt_inv_at_depth(self, depth: nat) -> bool
560 decreases depth,
561 {
562 if depth == 0 {
563 true
564 } else if self.0.value().is_node() {
565 forall|i: int|
566 #![trigger self.0.has_child(i)]
567 0 <= i < NR_ENTRIES ==> Self::pt_edge_at(self.0, i) && PageTableOwner(
568 self.0.child(i),
569 ).pt_inv_at_depth((depth - 1) as nat)
570 } else {
571 forall|i: int|
572 #![trigger self.0.has_child(i)]
573 0 <= i < NR_ENTRIES ==> !self.0.has_child(i)
574 }
575 }
576
577 pub open spec fn pt_inv(self) -> bool {
582 &&& self.0.inv()
583 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level()) as nat)
584 }
585
586 pub proof fn pt_inv_unroll(self, i: int)
587 requires
588 self.pt_inv(),
589 self.0.value().is_node(),
590 0 <= i < NR_ENTRIES,
591 ensures
592 Self::pt_edge_at(self.0, i),
593 PageTableOwner(self.0.child(i)).pt_inv(),
594 {
595 let depth = (INC_LEVELS - self.0.level()) as nat;
598 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::la_inv(
599 self.0.value(),
600 self.0.level(),
601 ));
602 }
603
604 pub proof fn pt_inv_non_node(self, i: int)
605 requires
606 self.pt_inv(),
607 !self.0.value().is_node(),
608 0 <= i < NR_ENTRIES,
609 ensures
610 !self.0.has_child(i),
611 {
612 }
613
614 pub proof fn non_node_pt_inv_at_depth(self, depth: nat)
618 requires
619 !self.0.value().is_node(),
620 forall|j: int| 0 <= j < NR_ENTRIES ==> !#[trigger] self.0.has_child(j),
621 ensures
622 self.pt_inv_at_depth(depth),
623 decreases depth,
624 {
625 }
626
627 #[verifier::spinoff_prover]
636 pub proof fn allocated_empty_node_pt_inv(owner: OwnerSubtree<C>)
637 requires
638 owner.inv(),
639 owner.value().is_node(),
640 owner.children().len() == NR_ENTRIES,
641 forall|i: int|
642 0 <= i < NR_ENTRIES ==> {
643 &&& #[trigger] owner.has_child(i)
644 &&& owner.child(i).value().is_absent()
645 &&& owner.child(i).value().path.len() == owner.value().node().tree_level + 1
646 &&& owner.child(i).value().match_pte(
647 owner.value().node().children_perm.value()[i],
648 owner.value().node().level,
649 )
650 &&& owner.child(i).value().path == owner.value().path.push_tail(i)
651 &&& owner.child(i).value().parent_level == owner.value().node().level
652 },
653 allocated_empty_node_grandchildren_none(owner),
654 ensures
655 PageTableOwner(owner).pt_inv(),
656 {
657 let depth = (INC_LEVELS - owner.level()) as nat;
658 assert forall|i: int| 0 <= i < NR_ENTRIES implies #[trigger] owner.has_child(i)
662 && Self::pt_edge_at(owner, i) && PageTableOwner(owner.child(i)).pt_inv_at_depth(
663 (depth - 1) as nat,
664 ) by {
665 let child = owner.child(i);
666 assert(owner.has_child(i));
671 PageTableOwner(child).non_node_pt_inv_at_depth((depth - 1) as nat);
674 };
675 }
676
677 pub open spec fn top_level_indices_absent(self) -> bool {
682 let range = C::TOP_LEVEL_INDEX_RANGE();
683 self.0.value().is_node() ==> forall|i: int|
684 #![trigger self.0.has_child(i)]
685 0 <= i < NR_ENTRIES && !(range.start <= i < range.end) ==> self.0.has_child(i)
686 && self.0.child(i).value().is_absent()
687 }
688
689 pub open spec fn view_rec_node_children(self, path: TreePath<NR_ENTRIES>) -> Seq<Set<Mapping>>
690 decreases INC_LEVELS - path.len(), 0nat,
691 when self.0.inv() && path.len() < INC_LEVELS - 1
692 {
693 self.0.children().map(
694 |i, child: Option<OwnerSubtree<C>>|
695 if child is Some {
696 PageTableOwner(child->0).view_rec(path.push_tail(i))
697 } else {
698 Set::empty()
699 },
700 )
701 }
702
703 pub open spec fn view_rec(self, path: TreePath<NR_ENTRIES>) -> Set<Mapping>
704 decreases INC_LEVELS - path.len(), 1nat,
705 when self.0.inv() && path.len() <= INC_LEVELS - 1
706 {
707 if self.0.value().is_frame() {
708 let va = vaddr_of::<C>(path);
709 let pt_level = INC_LEVELS - path.len();
710 let page_size = page_size(pt_level as PagingLevel);
711
712 set![Mapping {
713 va_range: Range { start: va as int, end: va + page_size },
714 pa_range: Range {
715 start: self.0.value().frame().mapped_pa,
716 end: (self.0.value().frame().mapped_pa + page_size) as Paddr,
717 },
718 page_size: page_size,
719 property: self.0.value().frame().prop,
720 }]
721 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
722 self.view_rec_node_children(path).to_set().flatten()
723 } else {
724 set![]
725 }
726 }
727
728 pub broadcast proof fn lemma_view_rec_contains_intro(
729 self,
730 path: TreePath<NR_ENTRIES>,
731 m: Mapping,
732 i: int,
733 )
734 requires
735 self.0.inv(),
736 path.len() < INC_LEVELS - 1,
737 self.0.value().is_node(),
738 0 <= i < self.0.children().len(),
739 self.0.has_child(i),
740 #[trigger] PageTableOwner(self.0.children()[i]->0).view_rec(path.push_tail(i)).contains(
741 m,
742 ),
743 ensures
744 self.view_rec(path).contains(m),
745 {
746 broadcast use vstd::seq_lib::group_seq_properties;
747
748 let mapped = self.view_rec_node_children(path);
749 assert(mapped.to_set().contains(mapped[i]));
750 }
751
752 pub broadcast proof fn lemma_view_rec_contains(self, path: TreePath<NR_ENTRIES>)
753 requires
754 self.0.inv(),
755 path.len() < INC_LEVELS - 1,
756 self.0.value().is_node(),
757 ensures
758 #![trigger self.view_rec(path)]
759 forall|m: Mapping|
760 #![trigger self.view_rec(path).contains(m)]
761 self.view_rec(path).contains(m) ==> exists|i: int|
762 #![trigger self.0.children()[i]]
763 0 <= i < self.0.children().len() && self.0.children()[i] is Some
764 && PageTableOwner(self.0.children()[i]->0).view_rec(
765 path.push_tail(i),
766 ).contains(m),
767 {
768 broadcast use vstd::seq_lib::group_seq_properties;
769
770 }
771
772 pub proof fn view_rec_contains_choose(self, path: TreePath<NR_ENTRIES>, m: Mapping) -> (i: int)
773 requires
774 self.0.inv(),
775 path.len() < INC_LEVELS - 1,
776 self.view_rec(path).contains(m),
777 self.0.value().is_node(),
778 ensures
779 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
780 self.0.children()[i]->0,
781 ).view_rec(path.push_tail(i)).contains(m),
782 {
783 broadcast use PageTableOwner::group_lemmas;
784
785 choose|i: int|
786 #![auto]
787 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
788 self.0.children()[i].unwrap(),
789 ).view_rec(path.push_tail(i)).contains(m)
790 }
791
792 #[verifier::rlimit(400)]
794 pub proof fn lemma_vaddr_push_tail_eq(path: TreePath<NR_ENTRIES>, i: int)
795 requires
796 path.inv(),
797 path.len() < INC_LEVELS - 1,
798 0 <= i < NR_ENTRIES,
799 ensures
800 vaddr(path.push_tail(i)) == vaddr(path) + i * page_size(
801 (INC_LEVELS - path.len() - 1) as PagingLevel,
802 ),
803 vaddr(path) + (i + 1) * page_size((INC_LEVELS - path.len() - 1) as PagingLevel)
804 <= usize::MAX,
805 {
806 broadcast use {
807 TreePath::lemma_push_tail_len,
808 TreePath::lemma_push_tail_preserves_inv,
809 TreePath::lemma_index_satisfies_elem_inv,
810 };
811
812 lemma_page_size_spec_values();
813 lemma_vaddr_strict_bound(path);
814 vstd::arithmetic::power2::lemma2_to64();
815 vstd::arithmetic::power2::lemma2_to64_rest();
816 let pt = path.push_tail(i);
817 if path.len() >= 1 {
818 }
819 if path.len() == 0 {
820 assert(rec_vaddr(pt, 1) == 0);
821 assert(vaddr_make::<NR_LEVELS>(0, i as usize) == 0x80_0000_0000usize * i) by (compute);
822 assert(0x80_0000_0000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
823 requires
824 i < 512,
825 ;
826 } else if path.len() == 1 {
827 let i0 = path[0];
828 assert(vaddr_make::<NR_LEVELS>(0, i0 as usize) == 0x80_0000_0000usize * i0);
829 assert(rec_vaddr(pt, 2) == 0);
830 } else if path.len() == 2 {
831 let i0 = path[0];
832 let i1 = path[1];
833 assert(rec_vaddr(path, 2) == 0);
834 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1 as usize) as usize);
835 assert(rec_vaddr(pt, 3) == 0);
836 assert(rec_vaddr(pt, 2) == vaddr_make::<NR_LEVELS>(2, i as usize) as usize);
837 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
838 NR_LEVELS,
839 >(2, i as usize)) as usize);
840 } else {
841 let i0 = path[0];
842 let i1 = path[1];
843 let i2 = path[2];
844 assert(rec_vaddr(path, 3) == 0);
845 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2 as usize) as usize);
846 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
847 NR_LEVELS,
848 >(2, i2 as usize)) as usize);
849 assert(vaddr_make::<NR_LEVELS>(1, i1 as usize) == 0x4000_0000usize * i1) by (compute);
850 assert(rec_vaddr(pt, 4) == 0);
851 assert(rec_vaddr(pt, 3) == vaddr_make::<NR_LEVELS>(3, i as usize) as usize);
852 assert(rec_vaddr(pt, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + vaddr_make::<
853 NR_LEVELS,
854 >(3, i as usize)) as usize);
855 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + vaddr_make::<
856 NR_LEVELS,
857 >(2, i2 as usize) + vaddr_make::<NR_LEVELS>(3, i as usize)) as usize);
858 assert(vaddr_make::<NR_LEVELS>(3, i as usize) == 0x1000usize * i) by (compute);
859 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
860 + 0x1000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
861 requires
862 i0 < 512,
863 i1 < 512,
864 i2 < 512,
865 i < 512,
866 ;
867 }
868 }
869
870 pub proof fn view_rec_vaddr_range(self, path: TreePath<NR_ENTRIES>, m: Mapping)
871 requires
872 self.pt_inv(),
873 path.inv(),
874 path.len() <= INC_LEVELS - 1,
875 path.len() == self.0.level(),
876 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
877 self.view_rec(path).contains(m),
878 ensures
879 vaddr_of::<C>(path) <= m.va_range.start,
880 m.va_range.start < m.va_range.end,
881 m.va_range.end <= vaddr_of::<C>(path) + page_size(
882 (INC_LEVELS - path.len()) as PagingLevel,
883 ),
884 decreases INC_LEVELS - path.len(),
885 {
886 broadcast use PageTableOwner::group_lemmas;
887
888 lemma_page_size_spec_values();
889 if self.0.value().is_frame() {
890 let frame = self.0.value().frame();
891 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
892 let expected = Mapping {
893 va_range: Range {
894 start: vaddr_of::<C>(path) as int,
895 end: vaddr_of::<C>(path) + page_size(pt_level),
896 },
897 pa_range: Range {
898 start: frame.mapped_pa,
899 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
900 },
901 page_size: page_size(pt_level),
902 property: frame.prop,
903 };
904 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
905 let i = choose|i: int|
906 #![trigger self.0.children()[i]]
907 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
908 self.0.children()[i].unwrap(),
909 ).view_rec(path.push_tail(i)).contains(m);
910 self.pt_inv_unroll(i);
911 let child = PageTableOwner(self.0.children()[i].unwrap());
912 child.view_rec_vaddr_range(path.push_tail(i), m);
913 Self::lemma_vaddr_push_tail_eq(path, i);
914
915 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel) as int;
916 assert((i + 1) * child_ps <= 512 * child_ps) by (nonlinear_arith)
917 requires
918 0 <= i < 512,
919 child_ps >= 0,
920 ;
921 lemma_vaddr_of_eq_int::<C>(path.push_tail(i));
922 assert(i * child_ps + child_ps == (i + 1) * child_ps) by (nonlinear_arith);
923 }
924 }
925
926 pub proof fn view_rec_top_index_va_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping, t: int)
932 requires
933 self.pt_inv(),
934 path.inv(),
935 1 <= path.len() <= INC_LEVELS - 1,
936 path.len() == self.0.level(),
937 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
938 path[0] < t,
939 self.view_rec(path).contains(m),
940 ensures
941 (path[0]) * 0x80_0000_0000int + C::LEADING_BITS_spec() * 0x1_0000_0000_0000int
942 <= m.va_range.start,
943 m.va_range.start < m.va_range.end,
944 m.va_range.end <= t * 0x80_0000_0000int + C::LEADING_BITS_spec()
945 * 0x1_0000_0000_0000int,
946 {
947 self.view_rec_vaddr_range(path, m);
948 lemma_vaddr_of_eq_int::<C>(path);
949 lemma_vaddr_top_index_cell(path);
950 }
957
958 pub proof fn pt_inv_implies_path_correct(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
966 requires
967 PageTableOwner(subtree).pt_inv(),
968 subtree.value().path == path,
969 ensures
970 subtree.subtree_satisfies(path, Self::path_correct_pred()),
971 decreases INC_LEVELS - subtree.level(),
972 {
973 if subtree.level() < INC_LEVELS - 1 {
975 assert forall|i: int|
976 0 <= i < subtree.children().len() && (
977 #[trigger] subtree.children()[i]) is Some implies subtree.children()[i].unwrap().subtree_satisfies(
978 path.push_tail(i), Self::path_correct_pred()) by {
979 if subtree.value().is_node() {
980 PageTableOwner(subtree).pt_inv_unroll(i);
981 Self::pt_inv_implies_path_correct(
983 subtree.children()[i].unwrap(),
984 path.push_tail(i),
985 );
986 } else {
987 PageTableOwner(subtree).pt_inv_non_node(i);
989 }
990 };
991 }
992 }
993
994 pub proof fn no_frame_with_path_rec(
1004 self,
1005 path: TreePath<NR_ENTRIES>,
1006 removed_path: TreePath<NR_ENTRIES>,
1007 ambient: Set<Mapping>,
1008 )
1009 requires
1010 self.pt_inv(),
1011 path.inv(),
1012 path.len() <= INC_LEVELS - 1,
1013 path.len() == self.0.level(),
1014 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1015 self.0.value().path == path,
1016 self.0.subtree_satisfies(path, Self::path_correct_pred()),
1017 forall|mm: Mapping|
1018 #![trigger self.view_rec(path).contains(mm)]
1019 self.view_rec(path).contains(mm) ==> ambient.contains(mm),
1020 forall|mm: Mapping|
1021 #![trigger ambient.contains(mm)]
1022 ambient.contains(mm) ==> mm.va_range.start != vaddr_of::<C>(removed_path),
1023 ensures
1024 self.0.subtree_satisfies(
1025 path,
1026 |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1027 e.is_frame() ==> e.path != removed_path,
1028 ),
1029 decreases INC_LEVELS - path.len(),
1030 {
1031 broadcast use PageTableOwner::group_lemmas;
1032
1033 let g = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1034 e.is_frame() ==> e.path != removed_path;
1035
1036 if self.0.value().is_frame() {
1038 let frame = self.0.value().frame();
1039 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1040 let expected = Mapping {
1041 va_range: Range {
1042 start: vaddr_of::<C>(path) as int,
1043 end: vaddr_of::<C>(path) + page_size(pt_level),
1044 },
1045 pa_range: Range {
1046 start: frame.mapped_pa,
1047 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1048 },
1049 page_size: page_size(pt_level),
1050 property: frame.prop,
1051 };
1052 assert(self.view_rec(path).contains(expected));
1053
1054 }
1055 if self.0.level() < INC_LEVELS - 1 {
1056 assert forall|i: int|
1057 0 <= i < self.0.children().len() && (
1058 #[trigger] self.0.children()[i]) is Some implies self.0.children()[i].unwrap().subtree_satisfies(
1059 path.push_tail(i), g) by {
1060 if self.0.value().is_node() {
1061 self.pt_inv_unroll(i);
1062 let child = PageTableOwner(self.0.children()[i].unwrap());
1063 child.no_frame_with_path_rec(path.push_tail(i), removed_path, ambient);
1066 } else {
1067 PageTableOwner(self.0).pt_inv_non_node(i);
1068 }
1069 };
1070 }
1071 }
1072
1073 pub proof fn view_rec_disjoint_vaddrs(
1074 self,
1075 path: TreePath<NR_ENTRIES>,
1076 m1: Mapping,
1077 m2: Mapping,
1078 )
1079 requires
1080 self.pt_inv(),
1081 path.inv(),
1082 path.len() <= INC_LEVELS - 1,
1083 path.len() == self.0.level(),
1084 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1085 self.view_rec(path).contains(m1),
1086 self.view_rec(path).contains(m2),
1087 m1 != m2,
1088 ensures
1089 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start,
1090 decreases INC_LEVELS - path.len(),
1091 {
1092 broadcast use PageTableOwner::group_lemmas;
1093 broadcast use group_set_properties;
1094
1095 if self.0.value().is_frame() {
1096 } else if self.0.value().is_node() {
1097 let i1 = self.view_rec_contains_choose(path, m1);
1098 let i2 = self.view_rec_contains_choose(path, m2);
1099
1100 if i1 == i2 {
1101 self.pt_inv_unroll(i1);
1102 PageTableOwner(self.0.children()[i1].unwrap()).view_rec_disjoint_vaddrs(
1103 path.push_tail(i1),
1104 m1,
1105 m2,
1106 );
1107 } else {
1108 self.pt_inv_unroll(i1);
1109 self.pt_inv_unroll(i2);
1110 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel);
1111 PageTableOwner(self.0.children()[i1].unwrap()).view_rec_vaddr_range(
1112 path.push_tail(i1),
1113 m1,
1114 );
1115 PageTableOwner(self.0.children()[i2].unwrap()).view_rec_vaddr_range(
1116 path.push_tail(i2),
1117 m2,
1118 );
1119 if i1 < i2 {
1120 sibling_paths_disjoint::<C>(path, i1, i2, child_ps);
1121 } else {
1122 sibling_paths_disjoint::<C>(path, i2, i1, child_ps);
1123 }
1124 lemma_vaddr_of_eq_int::<C>(path.push_tail(i1));
1128 lemma_vaddr_of_eq_int::<C>(path.push_tail(i2));
1129 }
1130 }
1131 }
1132
1133 pub proof fn view_rec_mapping_page_size(self, path: TreePath<NR_ENTRIES>)
1140 requires
1141 self.pt_inv(),
1142 path.len() <= INC_LEVELS - 1,
1143 path.len() == self.0.level(),
1144 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1145 ensures
1146 forall|m: Mapping| #[trigger]
1147 self.view_rec(path).contains(m)
1148 ==> set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size),
1149 decreases INC_LEVELS - path.len(),
1150 {
1151 broadcast use PageTableOwner::group_lemmas;
1152
1153 if self.0.value().is_frame() {
1154 lemma_page_size_spec_values();
1155 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
1156 assert forall|m: Mapping| #[trigger]
1157 self.view_rec(path).contains(
1158 m,
1159 ) implies set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size) by {
1160 let i = choose|i: int|
1161 #![trigger self.0.children()[i]]
1162 0 <= i < self.0.children().len() && self.0.children()[i] is Some
1163 && PageTableOwner(self.0.children()[i].unwrap()).view_rec(
1164 path.push_tail(i),
1165 ).contains(m);
1166 self.pt_inv_unroll(i);
1167 let child = self.0.children()[i].unwrap();
1168 PageTableOwner(child).view_rec_mapping_page_size(path.push_tail(i));
1169 };
1170 }
1171 }
1172
1173 #[verifier::rlimit(400)]
1180 proof fn lemma_vaddr_path_alignment_and_bound(path: TreePath<NR_ENTRIES>)
1181 requires
1182 path.inv(),
1183 path.len() <= INC_LEVELS - 1,
1184 1 <= INC_LEVELS - path.len() <= NR_LEVELS,
1185 ensures
1186 vaddr(path) % page_size((INC_LEVELS - path.len()) as PagingLevel) == 0,
1187 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= usize::MAX,
1188 {
1189 lemma_page_size_spec_values();
1190 vstd::arithmetic::power2::lemma2_to64();
1191 vstd::arithmetic::power2::lemma2_to64_rest();
1192 broadcast use TreePath::lemma_index_satisfies_elem_inv;
1193 if path.len() == 0 {
1205 assert(rec_vaddr(path, 0) == 0);
1206 } else if path.len() == 1 {
1207 let i0 = path[0];
1208 assert(rec_vaddr(path, 1) == 0);
1209 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + rec_vaddr(
1210 path,
1211 1,
1212 )) as usize);
1213 } else if path.len() == 2 {
1214 let i0 = path[0];
1215 let i1 = path[1];
1216 assert(rec_vaddr(path, 2) == 0);
1217 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + rec_vaddr(
1218 path,
1219 2,
1220 )) as usize);
1221 let s = 0x80_0000_0000usize * i0 + 0x4000_0000usize * i1;
1222 } else if path.len() == 3 {
1223 let i0 = path[0];
1224 let i1 = path[1];
1225 let i2 = path[2];
1226 assert(rec_vaddr(path, 3) == 0);
1227 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2 as usize) + rec_vaddr(
1228 path,
1229 3,
1230 )) as usize);
1231 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + rec_vaddr(
1232 path,
1233 1,
1234 )) as usize);
1235 let s = 0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2;
1236 assert(rec_vaddr(path, 0) == s);
1237 assert(s % 0x20_0000 == 0) by (nonlinear_arith)
1238 requires
1239 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2,
1240 ;
1241 } else {
1242 assert(path.len() == 4);
1243 let i0 = path[0];
1244 let i1 = path[1];
1245 let i2 = path[2];
1246 let i3 = path[3];
1247 assert(rec_vaddr(path, 4) == 0);
1248 assert(rec_vaddr(path, 3) == (vaddr_make::<NR_LEVELS>(3, i3 as usize) + rec_vaddr(
1249 path,
1250 4,
1251 )) as usize);
1252 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1 as usize) + rec_vaddr(
1253 path,
1254 2,
1255 )) as usize);
1256 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0 as usize) + rec_vaddr(
1257 path,
1258 1,
1259 )) as usize);
1260 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
1261 + 0x1000usize * i3) as int;
1262 assert(s + 0x1000 <= usize::MAX) by (nonlinear_arith)
1263 requires
1264 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3,
1265 i0 < 512,
1266 i1 < 512,
1267 i2 < 512,
1268 i3 < 512,
1269 ;
1270 }
1271 }
1272
1273 pub proof fn view_rec_mapping_inv(self, path: TreePath<NR_ENTRIES>)
1282 requires
1283 self.pt_inv(),
1284 path.inv(),
1285 path.len() <= INC_LEVELS - 1,
1286 path.len() == self.0.level(),
1287 self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel,
1288 ensures
1289 forall|m: Mapping| #[trigger] self.view_rec(path).contains(m) ==> m.inv(),
1290 decreases INC_LEVELS - path.len(),
1291 {
1292 broadcast use PageTableOwner::group_lemmas;
1293
1294 if self.0.value().is_frame() {
1295 lemma_page_size_spec_values();
1296 let frame = self.0.value().frame();
1297 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1298 Self::lemma_vaddr_path_alignment_and_bound(path);
1299 let m = Mapping {
1300 va_range: Range {
1301 start: vaddr_of::<C>(path) as int,
1302 end: vaddr_of::<C>(path) + page_size(pt_level),
1303 },
1304 pa_range: Range {
1305 start: frame.mapped_pa,
1306 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1307 },
1308 page_size: page_size(pt_level),
1309 property: frame.prop,
1310 };
1311 assert(self.view_rec(path) == set![m]);
1312 let ps = page_size(pt_level) as int;
1313 assert((frame.mapped_pa + ps) % ps == 0) by (nonlinear_arith)
1314 requires
1315 (frame.mapped_pa as int) % ps == 0,
1316 ps > 0,
1317 ;
1318 lemma_vaddr_of_eq_int::<C>(path);
1320 C::lemma_page_table_config_constant_properties();
1321 lemma_vaddr_strict_bound(path);
1322 let lb = C::LEADING_BITS_spec() as int;
1323 vstd::arithmetic::power2::lemma2_to64_rest();
1324 assert(lb * 0x1_0000_0000_0000int % ps == 0) by (nonlinear_arith)
1328 requires
1329 lb >= 0,
1330 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int),
1331 ;
1332 vstd::arithmetic::div_mod::lemma_mod_adds(
1333 vaddr(path) as int,
1334 lb * 0x1_0000_0000_0000int,
1335 ps,
1336 );
1337 let v = vaddr(path) as int;
1340 assert(vaddr_of::<C>(path) + ps <= pow2(64)) by (nonlinear_arith)
1341 requires
1342 vaddr_of::<C>(path) == v + lb * 0x1_0000_0000_0000int,
1343 v + ps <= 0x1_0000_0000_0000int,
1344 lb < 0x1_0000int,
1345 lb >= 0,
1346 pow2(64) == 0x1_0000_0000_0000_0000int,
1347 ;
1348 assert(m.inv());
1349 } else if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
1350 assert forall|m: Mapping| #[trigger]
1351 self.view_rec(path).contains(m) implies m.inv() by {
1352 let i = choose|i: int|
1353 #![trigger self.0.children()[i]]
1354 0 <= i < self.0.children().len() && self.0.children()[i] is Some
1355 && PageTableOwner(self.0.children()[i].unwrap()).view_rec(
1356 path.push_tail(i),
1357 ).contains(m);
1358 self.pt_inv_unroll(i);
1359 let child = self.0.children()[i].unwrap();
1360 PageTableOwner(child).view_rec_mapping_inv(path.push_tail(i));
1361 };
1362 }
1363 }
1364
1365 pub proof fn view_rec_absent_empty(self, path: TreePath<NR_ENTRIES>)
1367 requires
1368 self.0.inv(),
1369 self.0.value().is_absent(),
1370 path.len() <= INC_LEVELS - 1,
1371 ensures
1372 self.view_rec(path) == set![],
1373 {
1374 }
1375
1376 pub proof fn view_rec_nr_children_zero_empty(self, path: TreePath<NR_ENTRIES>)
1387 requires
1388 self.pt_inv(),
1389 self.0.value().is_node(),
1390 self.0.value().node().meta_own.nr_children.value() == 0,
1391 self.0.value().node().count_consistent(),
1392 path.len() <= INC_LEVELS - 1,
1393 path.len() == self.0.level(),
1394 ensures
1395 self.view_rec(path) == set![],
1396 {
1397 if path.len() < INC_LEVELS - 1 {
1398 let cp = self.0.value().node().children_perm.value();
1399 self.lemma_view_rec_contains(path);
1401 assert forall|m: Mapping| self.view_rec(path).contains(m) implies false by {
1402 let i = choose|i: int|
1403 #![trigger self.0.children()[i]]
1404 0 <= i < self.0.children().len() && self.0.children()[i] is Some
1405 && PageTableOwner(self.0.children()[i]->0).view_rec(
1406 path.push_tail(i),
1407 ).contains(m);
1408 self.pt_inv_unroll(i);
1409 if cp[i].is_present() {
1411 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_present(
1412 cp,
1413 cp.len() as int,
1414 i,
1415 );
1416 }
1417 };
1423 }
1424 }
1425
1426 pub open spec fn metaregion_sound_pred(regions: MetaRegionOwners) -> (spec_fn(
1427 EntryOwner<C>,
1428 TreePath<NR_ENTRIES>,
1429 ) -> bool) {
1430 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions)
1431 }
1432
1433 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool
1434 decreases INC_LEVELS - self.0.level(),
1435 when self.0.inv()
1436 {
1437 self.0.subtree_satisfies(self.0.value().path, Self::metaregion_sound_pred(regions))
1438 }
1439
1440 pub proof fn metaregion_sound_preserved_slot_owners_eq(
1445 self,
1446 r0: MetaRegionOwners,
1447 r1: MetaRegionOwners,
1448 )
1449 requires
1450 self.inv(),
1451 self.metaregion_sound(r0),
1452 r0.slot_owners == r1.slot_owners,
1453 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1454 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1455 ensures
1456 self.metaregion_sound(r1),
1457 {
1458 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1459 self.0,
1460 self.0.value().path,
1461 r0,
1462 r1,
1463 );
1464 }
1465
1466 pub proof fn metaregion_sound_preserved_slot_owners_eq_subtree(
1468 subtree: OwnerSubtree<C>,
1469 path: TreePath<NR_ENTRIES>,
1470 r0: MetaRegionOwners,
1471 r1: MetaRegionOwners,
1472 )
1473 requires
1474 subtree.inv(),
1475 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r0)),
1476 r0.slot_owners == r1.slot_owners,
1477 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1478 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1479 ensures
1480 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r1)),
1481 decreases INC_LEVELS - subtree.level(),
1482 {
1483 if subtree.level() < INC_LEVELS - 1 {
1485 assert forall|i: int|
1486 #![trigger subtree.has_child(i)]
1487 0 <= i < NR_ENTRIES && subtree.has_child(i) implies subtree.child(
1488 i,
1489 ).subtree_satisfies(path.push_tail(i), Self::metaregion_sound_pred(r1)) by {
1490 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1491 subtree.child(i),
1492 path.push_tail(i),
1493 r0,
1494 r1,
1495 );
1496 }
1497 }
1498 }
1499
1500 pub proof fn metaregion_sound_preserved_one_slot_changed(
1506 self,
1507 r0: MetaRegionOwners,
1508 r1: MetaRegionOwners,
1509 changed_idx: int,
1510 )
1511 requires
1512 self.inv(),
1513 self.metaregion_sound(r0),
1514 forall|i: int|
1515 #![trigger r1.slot_owners[i]]
1516 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1517 r0.slot_owners.dom() == r1.slot_owners.dom(),
1518 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1519 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1520 self.0.subtree_satisfies(
1522 self.0.value().path,
1523 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1524 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr()->0)
1525 != changed_idx,
1526 ),
1527 self.0.subtree_satisfies(
1531 self.0.value().path,
1532 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1533 e.is_frame() && e.parent_level > 1 ==> {
1534 let pa = e.frame().mapped_pa;
1535 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1536 forall|j: usize|
1537 0 < j < nr_pages ==> {
1538 let sub_idx = #[trigger] frame_to_index(
1539 (pa + j * PAGE_SIZE) as usize,
1540 );
1541 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1542 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1543 != REF_COUNT_UNUSED
1544 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1545 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1546 <= REF_COUNT_MAX)
1547 }
1548 },
1549 ),
1550 ensures
1551 self.metaregion_sound(r1),
1552 {
1553 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1554 self.0,
1555 self.0.value().path,
1556 r0,
1557 r1,
1558 changed_idx,
1559 );
1560 }
1561
1562 pub proof fn metaregion_sound_preserved_one_slot_changed_subtree(
1563 subtree: OwnerSubtree<C>,
1564 path: TreePath<NR_ENTRIES>,
1565 r0: MetaRegionOwners,
1566 r1: MetaRegionOwners,
1567 changed_idx: int,
1568 )
1569 requires
1570 subtree.inv(),
1571 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r0)),
1572 forall|i: int|
1573 #![trigger r1.slot_owners[i]]
1574 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1575 r0.slot_owners.dom() == r1.slot_owners.dom(),
1576 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1577 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1578 subtree.subtree_satisfies(
1579 path,
1580 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1581 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr()->0)
1582 != changed_idx,
1583 ),
1584 subtree.subtree_satisfies(
1585 path,
1586 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1587 e.is_frame() && e.parent_level > 1 ==> {
1588 let pa = e.frame().mapped_pa;
1589 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1590 forall|j: usize|
1591 0 < j < nr_pages ==> {
1592 let sub_idx = #[trigger] frame_to_index(
1593 (pa + j * PAGE_SIZE) as usize,
1594 );
1595 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1596 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1597 != REF_COUNT_UNUSED
1598 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1599 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1600 <= REF_COUNT_MAX)
1601 }
1602 },
1603 ),
1604 ensures
1605 subtree.subtree_satisfies(path, Self::metaregion_sound_pred(r1)),
1606 decreases INC_LEVELS - subtree.level(),
1607 {
1608 if subtree.level() < INC_LEVELS - 1 {
1609 assert forall|i: int|
1610 #![trigger subtree.has_child(i)]
1611 0 <= i < NR_ENTRIES && subtree.has_child(i) implies subtree.child(
1612 i,
1613 ).subtree_satisfies(path.push_tail(i), Self::metaregion_sound_pred(r1)) by {
1614 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1615 subtree.child(i),
1616 path.push_tail(i),
1617 r0,
1618 r1,
1619 changed_idx,
1620 );
1621 }
1622 }
1623 }
1624
1625 pub open spec fn path_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
1628 EntryOwner<C>,
1629 TreePath<NR_ENTRIES>,
1630 ) -> bool {
1631 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1632 {
1633 entry.is_node() && entry.meta_slot_paddr() is Some ==> {
1635 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr()->0))
1636 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr()->0)].paths_in_pt
1637 == set![entry.path]
1638 }
1639 }
1640 }
1641
1642 pub open spec fn relate_region_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
1643 EntryOwner<C>,
1644 TreePath<NR_ENTRIES>,
1645 ) -> bool {
1646 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1647 {
1648 &&& entry.meta_slot_paddr() is Some
1649 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr()->0))
1650 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr()->0)].paths_in_pt
1651 == set![path]
1652 }
1653 }
1654
1655 pub open spec fn path_correct_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
1656 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| { entry.path == path }
1657 }
1658
1659 pub open spec fn not_in_scope_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
1660 |entry: EntryOwner<C>, _path: TreePath<NR_ENTRIES>| true
1661 }
1662
1663 pub proof fn tree_not_in_scope(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
1665 requires
1666 subtree.inv(),
1667 ensures
1668 subtree.subtree_satisfies(path, Self::not_in_scope_pred()),
1669 decreases INC_LEVELS - subtree.level(),
1670 {
1671 if subtree.level() < INC_LEVELS - 1 {
1673 assert forall|i: int|
1674 0 <= i < subtree.children().len() && (
1675 #[trigger] subtree.children()[i]) is Some implies subtree.children()[i].unwrap().subtree_satisfies(
1676 path.push_tail(i), Self::not_in_scope_pred()) by {
1677 Self::tree_not_in_scope(subtree.children()[i].unwrap(), path.push_tail(i));
1678 };
1679 }
1680 }
1681
1682 pub proof fn view_rec_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1685 requires
1686 self.0.inv(),
1687 path.len() <= INC_LEVELS - 1,
1688 self.view_rec(path).contains(m),
1689 ensures
1690 m.page_size <= page_size((INC_LEVELS - path.len()) as PagingLevel),
1691 decreases INC_LEVELS - path.len(),
1692 {
1693 broadcast use PageTableOwner::group_lemmas;
1694
1695 if self.0.value().is_node() && path.len() < INC_LEVELS - 1 {
1696 let i = choose|i: int|
1697 #![trigger self.0.children()[i]]
1698 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
1699 self.0.children()[i].unwrap(),
1700 ).view_rec(path.push_tail(i)).contains(m);
1701 PageTableOwner(self.0.children()[i].unwrap()).view_rec_page_size_bound(
1702 path.push_tail(i),
1703 m,
1704 );
1705 page_size_monotonic(
1706 (INC_LEVELS - path.len() - 1) as PagingLevel,
1707 (INC_LEVELS - path.len()) as PagingLevel,
1708 );
1709 }
1710 }
1711
1712 pub proof fn view_rec_node_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1715 requires
1716 self.0.inv(),
1717 self.0.value().is_node(),
1718 path.len() < INC_LEVELS - 1,
1719 self.view_rec(path).contains(m),
1720 ensures
1721 m.page_size <= page_size(((INC_LEVELS - path.len()) - 1) as PagingLevel),
1722 decreases INC_LEVELS - path.len(),
1723 {
1724 broadcast use PageTableOwner::group_lemmas;
1725
1726 let i = choose|i: int|
1727 #![trigger self.0.children()[i]]
1728 0 <= i < self.0.children().len() && self.0.children()[i] is Some && PageTableOwner(
1729 self.0.children()[i].unwrap(),
1730 ).view_rec(path.push_tail(i)).contains(m);
1731 PageTableOwner(self.0.children()[i].unwrap()).view_rec_page_size_bound(
1732 path.push_tail(i),
1733 m,
1734 );
1735 }
1736
1737 pub open spec fn is_prefix_of<const N: usize>(prefix: TreePath<N>, path: TreePath<N>) -> bool {
1739 &&& prefix.len() <= path.len()
1740 &&& forall|i: int| 0 <= i < prefix.len() ==> prefix[i] == path[i]
1741 }
1742
1743 pub proof fn prefix_transitive<const N: usize>(
1745 p1: TreePath<N>,
1746 p2: TreePath<N>,
1747 p3: TreePath<N>,
1748 )
1749 requires
1750 Self::is_prefix_of(p1, p2),
1751 Self::is_prefix_of(p2, p3),
1752 ensures
1753 Self::is_prefix_of(p1, p3),
1754 {
1755 }
1756
1757 pub proof fn prefix_push_different_indices(
1758 prefix: TreePath<NR_ENTRIES>,
1759 path: TreePath<NR_ENTRIES>,
1760 i: int,
1761 j: int,
1762 )
1763 requires
1764 prefix.inv(),
1765 path.inv(),
1766 i != j,
1767 Self::is_prefix_of(prefix.push_tail(i), path),
1768 ensures
1769 !Self::is_prefix_of(prefix.push_tail(j), path),
1770 {
1771 assert(path[prefix.len() as int] == i);
1772 }
1773
1774 pub proof fn prefix_push_tail_implies_prefix<const N: usize>(
1775 prefix: TreePath<N>,
1776 path: TreePath<N>,
1777 i: int,
1778 )
1779 requires
1780 prefix.inv(),
1781 path.inv(),
1782 0 <= i < N,
1783 Self::is_prefix_of(prefix.push_tail(i), path),
1784 ensures
1785 Self::is_prefix_of(prefix, path),
1786 {
1787 }
1788
1789 pub open spec fn is_at_pred(entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>) -> spec_fn(
1790 EntryOwner<C>,
1791 TreePath<NR_ENTRIES>,
1792 ) -> bool {
1793 |entry0: EntryOwner<C>, path0: TreePath<NR_ENTRIES>| { path0 == path ==> entry0 == entry }
1794 }
1795
1796 pub open spec fn path_in_tree_pred(path: TreePath<NR_ENTRIES>) -> spec_fn(
1797 EntryOwner<C>,
1798 TreePath<NR_ENTRIES>,
1799 ) -> bool {
1800 |entry: EntryOwner<C>, path0: TreePath<NR_ENTRIES>|
1801 Self::is_prefix_of(path0, path) ==> !entry.is_node() ==> path == path0
1802 }
1803
1804 pub proof fn is_at_pred_eq(
1805 path: TreePath<NR_ENTRIES>,
1806 entry1: EntryOwner<C>,
1807 entry2: EntryOwner<C>,
1808 )
1809 requires
1810 entry1.inv(),
1811 OwnerSubtree::implies(Self::is_at_pred(entry1, path), Self::is_at_pred(entry2, path)),
1812 ensures
1813 entry1 == entry2,
1814 {
1815 assert(Self::is_at_pred(entry1, path)(entry1, path) ==> Self::is_at_pred(entry2, path)(
1816 entry1,
1817 path,
1818 ));
1819 }
1820
1821 pub proof fn is_at_holds_when_on_wrong_path(
1822 subtree: OwnerSubtree<C>,
1823 root_path: TreePath<NR_ENTRIES>,
1824 dest_path: TreePath<NR_ENTRIES>,
1825 entry: EntryOwner<C>,
1826 )
1827 requires
1828 subtree.inv(),
1829 PageTableOwner(subtree).pt_inv(),
1830 dest_path.inv(),
1831 !Self::is_prefix_of(root_path, dest_path),
1832 root_path.len() <= INC_LEVELS - 1,
1833 root_path.len() == subtree.level(),
1834 ensures
1835 subtree.subtree_satisfies(root_path, Self::is_at_pred(entry, dest_path)),
1836 decreases INC_LEVELS - root_path.len(),
1837 {
1838 if subtree.level() < INC_LEVELS - 1 {
1839 if subtree.value().is_node() {
1840 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1841 #[trigger] subtree.children()[i as int]).unwrap().subtree_satisfies(
1842 root_path.push_tail(i),
1843 Self::is_at_pred(entry, dest_path),
1844 ) by {
1845 PageTableOwner(subtree).pt_inv_unroll(i);
1846 Self::is_at_holds_when_on_wrong_path(
1847 subtree.children()[i as int].unwrap(),
1848 root_path.push_tail(i),
1849 dest_path,
1850 entry,
1851 );
1852 };
1853 } else {
1854 }
1855 }
1856 }
1857
1858 pub proof fn path_in_tree_holds_when_on_wrong_path(
1862 subtree: OwnerSubtree<C>,
1863 root_path: TreePath<NR_ENTRIES>,
1864 dest_path: TreePath<NR_ENTRIES>,
1865 )
1866 requires
1867 subtree.inv(),
1868 PageTableOwner(subtree).pt_inv(),
1869 dest_path.inv(),
1870 !Self::is_prefix_of(root_path, dest_path),
1871 root_path.len() <= INC_LEVELS - 1,
1872 root_path.len() == subtree.level(),
1873 ensures
1874 subtree.subtree_satisfies(root_path, Self::path_in_tree_pred(dest_path)),
1875 decreases INC_LEVELS - root_path.len(),
1876 {
1877 if subtree.level() < INC_LEVELS - 1 {
1878 if subtree.value().is_node() {
1879 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1880 #[trigger] subtree.children()[i as int]).unwrap().subtree_satisfies(
1881 root_path.push_tail(i),
1882 Self::path_in_tree_pred(dest_path),
1883 ) by {
1884 PageTableOwner(subtree).pt_inv_unroll(i);
1885 Self::path_in_tree_holds_when_on_wrong_path(
1886 subtree.children()[i as int].unwrap(),
1887 root_path.push_tail(i),
1888 dest_path,
1889 );
1890 };
1891 } else {
1892 }
1893 }
1894 }
1895
1896 pub proof fn neq_old_from_path_disjoint(
1899 subtree: OwnerSubtree<C>,
1900 path_j: TreePath<NR_ENTRIES>,
1901 old_entry: EntryOwner<C>,
1902 regions: MetaRegionOwners,
1903 )
1904 requires
1905 subtree.inv(),
1906 subtree.value().path == path_j,
1907 path_j.len() == subtree.level(),
1908 path_j.inv(),
1909 path_j.len() <= INC_LEVELS - 1,
1910 subtree.subtree_satisfies(path_j, Self::metaregion_sound_pred(regions)),
1911 subtree.subtree_satisfies(path_j, Self::path_correct_pred()),
1912 old_entry.is_node(),
1913 old_entry.meta_slot_paddr() is Some,
1914 regions.slot_owners[frame_to_index(old_entry.meta_slot_paddr()->0)].paths_in_pt
1915 == set![old_entry.path],
1916 !Self::is_prefix_of(path_j, old_entry.path),
1917 ensures
1918 subtree.subtree_satisfies(
1919 path_j,
1920 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry),
1921 ),
1922 decreases INC_LEVELS - subtree.level(),
1923 {
1924 let f_sound = Self::metaregion_sound_pred(regions);
1925 let f_path = Self::path_correct_pred();
1926 let g = |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry);
1927
1928 if subtree.level() < INC_LEVELS - 1 {
1929 assert forall|i: int|
1930 0 <= i < subtree.children().len() && (
1931 #[trigger] subtree.children()[i]) is Some implies subtree.children()[i].unwrap().subtree_satisfies(
1932 path_j.push_tail(i), g) by {
1933 let child = subtree.child(i);
1934 let child_path = path_j.push_tail(i);
1935 subtree.lemma_subtree_satisfies_unroll_once(path_j, f_sound, i);
1936 subtree.lemma_subtree_satisfies_unroll_once(path_j, f_path, i);
1937 Self::neq_old_from_path_disjoint(child, child_path, old_entry, regions);
1938 };
1939 }
1940 }
1941
1942 pub proof fn is_at_eq_rec(
1943 subtree: OwnerSubtree<C>,
1944 root_path: TreePath<NR_ENTRIES>,
1945 dest_path: TreePath<NR_ENTRIES>,
1946 entry1: EntryOwner<C>,
1947 entry2: EntryOwner<C>,
1948 )
1949 requires
1950 subtree.inv(),
1951 PageTableOwner(subtree).pt_inv(),
1952 dest_path.inv(),
1953 root_path.inv(),
1954 Self::is_prefix_of(root_path, dest_path),
1955 root_path.len() <= INC_LEVELS - 1,
1956 root_path.len() == subtree.level(),
1957 subtree.subtree_satisfies(root_path, Self::path_in_tree_pred(dest_path)),
1958 subtree.subtree_satisfies(root_path, Self::is_at_pred(entry1, dest_path)),
1959 subtree.subtree_satisfies(root_path, Self::is_at_pred(entry2, dest_path)),
1960 ensures
1961 entry1 == entry2,
1962 decreases INC_LEVELS - root_path.len(),
1963 {
1964 if root_path == dest_path {
1965 } else if subtree.level() == INC_LEVELS - 1 || !subtree.value().is_node() {
1966 proof_from_false()
1967 } else {
1968 if root_path.len() == dest_path.len() {
1969 assert forall|i: int| 0 <= i < root_path.0.len() implies #[trigger] root_path.0[i]
1970 == dest_path.0[i] by {
1971 assert(root_path[i] == dest_path[i]);
1972 };
1973 assert(root_path == dest_path);
1974 assert(false);
1975 }
1976 let i = dest_path[root_path.len() as int];
1977 PageTableOwner(subtree).pt_inv_unroll(i as int);
1978 Self::is_at_eq_rec(
1979 subtree.children()[i as int].unwrap(),
1980 root_path.push_tail(i),
1981 dest_path,
1982 entry1,
1983 entry2,
1984 );
1985 }
1986 }
1987
1988 pub proof fn view_rec_inversion(
1989 self,
1990 path: TreePath<NR_ENTRIES>,
1991 regions: MetaRegionOwners,
1992 m: Mapping,
1993 ) -> (entry: EntryOwner<C>)
1994 requires
1995 self.pt_inv(),
1996 path.len() == self.0.level(),
1997 self.view_rec(path).contains(m),
1998 self.0.subtree_satisfies(path, Self::path_correct_pred()),
1999 self.0.subtree_satisfies(path, Self::relate_region_tracked_pred(regions)),
2000 ensures
2001 Self::is_prefix_of(path, entry.path),
2002 regions.slot_owners[frame_to_index(m.pa_range.start)].paths_in_pt == set![entry.path],
2003 m.va_range.start == vaddr_of::<C>(entry.path),
2004 m.page_size == page_size((INC_LEVELS - entry.path.len()) as PagingLevel),
2005 entry.is_frame(),
2006 m.property == entry.frame().prop,
2007 self.0.subtree_satisfies(path, Self::is_at_pred(entry, entry.path)),
2008 self.0.subtree_satisfies(path, Self::path_in_tree_pred(entry.path)),
2009 entry.inv(),
2010 decreases INC_LEVELS - path.len(),
2011 {
2012 broadcast use PageTableOwner::group_lemmas;
2013
2014 if self.0.value().is_frame() {
2015 self.0.value()
2016 } else if self.0.value().is_node() {
2017 let i = self.view_rec_contains_choose(path, m);
2018 self.pt_inv_unroll(i);
2019 let entry = PageTableOwner(self.0.children()[i].unwrap()).view_rec_inversion(
2020 path.push_tail(i),
2021 regions,
2022 m,
2023 );
2024 assert forall|j: int|
2025 0 <= j < NR_ENTRIES
2026 && #[trigger] self.0.children()[j] is Some implies self.0.children()[j].unwrap().subtree_satisfies(
2027 path.push_tail(j), Self::is_at_pred(entry, entry.path)) by {
2028 if j != i {
2029 self.pt_inv_unroll(j);
2030 Self::is_at_holds_when_on_wrong_path(
2031 self.0.children()[j].unwrap(),
2032 path.push_tail(j),
2033 entry.path,
2034 entry,
2035 );
2036 }
2037 };
2038
2039 assert forall|j: int|
2040 0 <= j < NR_ENTRIES && #[trigger] self.0.has_child(j) implies self.0.child(
2041 j,
2042 ).subtree_satisfies(path.push_tail(j), Self::path_in_tree_pred(entry.path)) by {
2043 if j != i {
2044 Self::path_in_tree_holds_when_on_wrong_path(
2045 self.0.child(j),
2046 path.push_tail(j),
2047 entry.path,
2048 );
2049 }
2050 };
2051 entry
2052 } else {
2053 proof_from_false()
2054 }
2055 }
2056
2057 pub proof fn view_rec_inversion_unique(
2058 self,
2059 path: TreePath<NR_ENTRIES>,
2060 regions: MetaRegionOwners,
2061 m1: Mapping,
2062 m2: Mapping,
2063 )
2064 requires
2065 self.pt_inv(),
2066 path.len() <= INC_LEVELS - 1,
2067 path.len() == self.0.level(),
2068 self.view_rec(path).contains(m1),
2069 self.view_rec(path).contains(m2),
2070 m1.pa_range.start == m2.pa_range.start,
2071 m1.inv(),
2072 m2.inv(),
2073 self.0.subtree_satisfies(path, Self::path_tracked_pred(regions)),
2074 self.0.subtree_satisfies(path, Self::path_correct_pred()),
2075 self.0.subtree_satisfies(path, Self::relate_region_tracked_pred(regions)),
2076 ensures
2077 m1 == m2,
2078 {
2079 let entry1 = self.view_rec_inversion(path, regions, m1);
2080 let entry2 = self.view_rec_inversion(path, regions, m2);
2081
2082 let idx = frame_to_index(m1.pa_range.start);
2084 assert(set![entry1.path].contains(entry2.path));
2085
2086 Self::is_at_eq_rec(self.0, path, entry1.path, entry1, entry2);
2087 }
2088
2089 pub broadcast group group_lemmas {
2090 PageTableOwner::lemma_view_rec_contains,
2091 PageTableOwner::lemma_view_rec_contains_intro,
2092 }
2093}
2094
2095impl<C: PageTableConfig> Inv for PageTableOwner<C> {
2096 open spec fn inv(self) -> bool {
2097 &&& self.0.inv()
2098 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level()) as nat)
2099 &&& self.0.value().is_node()
2100 &&& self.0.value().path.len() <= INC_LEVELS - 1
2101 &&& self.0.value().path.inv()
2102 &&& self.0.value().path.len() == self.0.level()
2103 &&& self.0.value().parent_level == (INC_LEVELS - self.0.level()) as PagingLevel
2104 &&& self.0.value().node().tree_level == self.0.value().path.len()
2105 &&& self.0.subtree_satisfies(self.0.value().path, Self::path_correct_pred())
2106 }
2107}
2108
2109impl<C: PageTableConfig> View for PageTableOwner<C> {
2110 type V = PageTableView;
2111
2112 open spec fn view(&self) -> <Self as View>::V {
2113 let mappings = self.view_rec(self.0.value().path);
2114 PageTableView { mappings }
2115 }
2116}
2117
2118}