1use vstd::prelude::*;
2use vstd_extra::{
3 arithmetic::{
4 lemma_nat_align_down_monotone, lemma_nat_align_down_sound,
5 lemma_nat_align_down_within_block, nat_align_down,
6 },
7 ghost_tree::*,
8 ownership::*,
9};
10
11use crate::specs::{
12 arch::{NR_ENTRIES, NR_LEVELS},
13 mm::page_table::{
14 cursor::{
15 owners::*,
16 page_size_lemmas::{lemma_page_size_divides, lemma_page_size_ge_base},
17 },
18 owners::*,
19 *,
20 },
21};
22
23use crate::arch::mm::PagingConsts;
24use crate::mm::{PagingConstsTrait, PagingLevel, Vaddr, page_size, page_table::*};
25
26verus! {
27
28broadcast use group_ghost_tree_lemmas;
29impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
32 pub proof fn as_page_table_owner_preserves_view_mappings(self)
33 requires
34 self.inv(),
35 self.all_some(),
36 ensures
37 self.as_page_table_owner().view_rec(self.path()) == self.view_mappings(),
38 self.as_subtree().inv(),
39 PageTableOwner(self.as_subtree()).pt_inv(),
40 {
41 broadcast use {CursorContinuation::group_lemmas, PageTableOwner::group_lemmas};
42
43 self.as_page_table_owner_pt_inv();
44 }
45
46 pub proof fn view_mappings_take_child(self)
47 requires
48 self.inv(),
49 self.all_some(),
50 ensures
51 self.take_child().1.view_mappings() == self.view_mappings()
52 - self.view_mappings_take_child_spec(),
53 {
54 broadcast use CursorContinuation::group_lemmas;
55
56 let def = self.take_child().1.view_mappings();
57 let diff = self.view_mappings() - self.view_mappings_take_child_spec();
58 assert forall|m: Mapping| diff.contains(m) implies def.contains(m) by {
59 let i = choose|i: int|
60 0 <= i < self.children.len() && #[trigger] self.children[i] is Some
61 && PageTableOwner(self.children[i].unwrap()).view_rec(
62 self.path().push_tail(i),
63 ).contains(m);
64 assert(self.take_child().1.children[i] is Some);
65 };
66 assert forall|m: Mapping| #![trigger def.contains(m)] def.contains(m) implies diff.contains(
67 m,
68 ) by {
69 let left = self.take_child().1;
70 if self.view_mappings_take_child_spec().contains(m) {
71 let i = choose|i: int|
72 0 <= i < left.children.len() && #[trigger] left.children[i] is Some
73 && PageTableOwner(left.children[i].unwrap()).view_rec(
74 left.path().push_tail(i),
75 ).contains(m);
76
77 PageTableOwner(self.children[self.idx as int].unwrap()).lemma_view_rec_vaddr_range(
78 self.path().push_tail(self.idx as int),
79 m,
80 );
81 PageTableOwner(left.children[i as int].unwrap()).lemma_view_rec_vaddr_range(
82 left.path().push_tail(i),
83 m,
84 );
85
86 let size = page_size::<PagingConsts>(
87 (INC_LEVELS - self.path().len() - 1) as PagingLevel,
88 );
89 sibling_paths_disjoint::<C>(self.path(), self.idx as int, i, size);
91 lemma_vaddr_of_eq_int::<C>(self.path().push_tail(self.idx as int));
92 lemma_vaddr_of_eq_int::<C>(self.path().push_tail(i));
93 }
94 };
95 }
96
97 pub proof fn view_mappings_put_child(self, child: OwnerSubtree<C>)
98 requires
99 self.inv(),
100 child.inv(),
101 self.all_but_index_some(),
102 ensures
103 self.put_child(child).view_mappings() == self.view_mappings() + PageTableOwner(
104 child,
105 ).view_rec(self.path().push_tail(self.idx as int)),
106 {
107 broadcast use CursorContinuation::group_lemmas;
108
109 let def = self.put_child(child).view_mappings();
110 let sum = self.view_mappings() + PageTableOwner(child).view_rec(
111 self.path().push_tail(self.idx as int),
112 );
113 assert forall|m: Mapping| sum.contains(m) implies def.contains(m) by {
114 if self.view_mappings().contains(m) {
115 let i = choose|i: int|
116 0 <= i < self.children.len() && #[trigger] self.children[i] is Some
117 && PageTableOwner(self.children[i].unwrap()).view_rec(
118 self.path().push_tail(i),
119 ).contains(m);
120 assert(self.put_child(child).children[i] == self.children[i]);
121 } else {
122 self.put_child(child).lemma_view_mappings_intro(m, self.idx as int);
123 }
124 };
125 }
126}
127
128impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
129 proof fn as_subtree_inv(self)
131 requires
132 self.inv(),
133 self.all_some(),
134 ensures
135 self.as_subtree().inv(),
136 {
137 }
138
139 proof fn as_page_table_owner_pt_inv(self)
140 requires
141 self.inv(),
142 self.all_some(),
143 ensures
144 PageTableOwner(self.as_subtree()).pt_inv(),
145 {
146 reveal(PageTableOwner::pt_inv_at_depth);
147 }
148}
149
150impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
152 pub proof fn lemma_cur_subtree_eq_filtered_mappings_path(self)
155 requires
156 self.inv(),
157 self.in_barrier_va(),
158 ensures
159 ({
160 let subtree_va = vaddr_of::<C>(self.cur_subtree().value().path) as int;
161 let size = page_size::<PagingConsts>(self.level) as int;
162 PageTableOwner(self.cur_subtree())@.mappings == self@.mappings.filter(
163 |m: Mapping| subtree_va <= m.va_range.start < subtree_va + size,
164 )
165 }),
166 {
167 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
168
169 let cur_subtree = self.cur_subtree();
170 let cur_path = cur_subtree.value().path;
171 let subtree_va = vaddr_of::<C>(cur_path) as int;
172 let size = page_size::<PagingConsts>(self.level) as int;
173
174 let subtree_mappings = PageTableOwner(cur_subtree)@.mappings;
175 let filtered = self@.mappings.filter(
176 |m: Mapping| subtree_va <= m.va_range.start < subtree_va + size,
177 );
178
179 let cont = self.continuations[self.level - 1];
180 assert forall|m: Mapping| subtree_mappings.contains(m) implies filtered.contains(m) by {
184 PageTableOwner(cur_subtree).lemma_view_rec_vaddr_range(cur_path, m);
189 };
190
191 assert forall|m: Mapping| filtered.contains(m) implies subtree_mappings.contains(m) by {
193 let i = choose|i: int|
195 self.level - 1 <= i < NR_LEVELS
196 && #[trigger] self.continuations[i].view_mappings().contains(m);
197
198 let cont_i = self.continuations[i];
199 let j = choose|j: int|
200 #![auto]
201 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
202 cont_i.children[j].unwrap(),
203 ).view_rec(cont_i.path().push_tail(j)).contains(m);
204
205 PageTableOwner(cont_i.children[j].unwrap()).lemma_view_rec_vaddr_range(
206 cont_i.path().push_tail(j),
207 m,
208 );
209
210 if i == self.level - 1 {
211 if j as usize != self.index() {
214 let sib_size = page_size::<PagingConsts>(
216 (INC_LEVELS - cont.path().len() - 1) as PagingLevel,
217 );
218 sibling_paths_disjoint::<C>(cont.path(), self.index() as int, j, sib_size);
219 lemma_vaddr_of_eq_int::<C>(cont.path().push_tail(self.index() as int));
222 lemma_vaddr_of_eq_int::<C>(cont.path().push_tail(j));
223 assert(false); }
225 } else {
226 if j as usize != cont_i.idx as int {
227 self.subtree_va_in_ancestor_range(i);
229
230 let sib_size = page_size::<PagingConsts>(
232 (INC_LEVELS - cont_i.path().len() - 1) as PagingLevel,
233 );
234 sibling_paths_disjoint::<C>(cont_i.path(), cont_i.idx as int, j, sib_size);
235 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(j));
236 lemma_vaddr_of_eq_int::<C>(cur_path);
237 assert(false); } else {
239 assert(false); }
241 }
242 };
243
244 }
245
246 pub proof fn lemma_cur_subtree_eq_filtered_mappings(self)
249 requires
250 self.inv(),
251 self.in_barrier_va(),
252 ensures
253 ({
254 let start = nat_align_down(
255 self@.cur_va as nat,
256 page_size::<PagingConsts>(self.level) as nat,
257 ) as Vaddr;
258 let size = page_size::<PagingConsts>(self.level);
259 PageTableOwner(self.cur_subtree())@.mappings == self@.mappings.filter(
260 |m: Mapping| start <= m.va_range.start < start + size,
261 )
262 }),
263 {
264 self.lemma_cur_subtree_eq_filtered_mappings_path();
265 self.cur_va_in_subtree_range();
266 }
267
268 pub(super) proof fn cur_va_in_cont_child_range(self, lvl: int)
272 requires
273 self.inv(),
274 self.in_barrier_va(),
275 self.level - 1 <= lvl < NR_LEVELS,
276 ensures
277 vaddr(self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int))
278 + vaddr_leading_part_spec::<C>(self.cur_va()) <= self.cur_va(),
279 self.cur_va() < vaddr(
280 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int),
281 ) + vaddr_leading_part_spec::<C>(self.cur_va()) + page_size::<PagingConsts>(
282 (lvl + 1) as PagingLevel,
283 ),
284 vaddr(self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int))
285 + vaddr_leading_part_spec::<C>(self.cur_va()) == nat_align_down(
286 self.cur_va() as nat,
287 page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat,
288 ),
289 vaddr_of::<C>(
290 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int),
291 ) == nat_align_down(
292 self.cur_va() as nat,
293 page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat,
294 ),
295 {
296 C::lemma_paging_consts_properties();
297 C::axiom_current_paging_consts_hardcoded();
298 lemma_vaddr_leading_part_is_align_down::<C>(self.cur_va());
299 let cont = self.continuations[lvl];
300 let child_path = cont.path().push_tail(cont.idx as int);
301 assert(child_path.len() == C::NR_LEVELS() - lvl);
302 assert forall|k: int| 0 <= k < child_path.len() implies #[trigger] child_path[k]
303 == pte_index_spec::<C>(self.cur_va(), (C::NR_LEVELS() - k) as PagingLevel) by {
304 lemma_pte_index_bound::<C>(self.cur_va(), (C::NR_LEVELS() - k) as PagingLevel);
305 };
306 lemma_vaddr_path_aligned::<C>(child_path, self.cur_va());
307 lemma_vaddr_of_eq_int::<C>(child_path);
308 lemma_page_size_ge_base::<PagingConsts>((lvl + 1) as PagingLevel);
309 lemma_nat_align_down_sound(
310 self.cur_va() as nat,
311 page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat,
312 );
313 }
314
315 proof fn subtree_va_in_ancestor_range(self, lvl: int)
318 requires
319 self.inv(),
320 self.in_barrier_va(),
321 self.level - 1 < lvl < NR_LEVELS,
322 ensures
323 ({
324 let subtree_va = vaddr(self.cur_subtree().value().path);
325 let idx_path_va = vaddr(
326 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int),
327 );
328 &&& idx_path_va <= subtree_va
329 &&& subtree_va + page_size::<PagingConsts>(self.level) <= idx_path_va + page_size::<
330 PagingConsts,
331 >((lvl + 1) as PagingLevel)
332 }),
333 {
334 self.cur_va_in_cont_child_range(self.level - 1);
335 self.cur_va_in_cont_child_range(lvl);
336
337 let x = self.cur_va() as nat;
338 let fine = page_size::<PagingConsts>(self.level as PagingLevel) as nat;
339 let coarse = page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat;
340
341 lemma_page_size_divides::<PagingConsts>(
342 self.level as PagingLevel,
343 (lvl + 1) as PagingLevel,
344 );
345 lemma_nat_align_down_monotone(x, fine, coarse);
346 lemma_nat_align_down_within_block(x, fine, coarse);
347 }
348
349 pub proof fn subtree_va_ranges_disjoint(self, j: int)
351 requires
352 self.inv(),
353 self.in_barrier_va(),
354 0 <= j < NR_ENTRIES,
355 j != self.index(),
356 self.continuations[self.level - 1].children[j] is Some,
357 ensures
358 vaddr(self.continuations[self.level - 1].path().push_tail(j))
359 + vaddr_leading_part_spec::<C>(self.cur_va()) + page_size::<PagingConsts>(
360 self.level as PagingLevel,
361 ) <= self.cur_va() || self.cur_va() < vaddr(
362 self.continuations[self.level - 1].path().push_tail(j),
363 ) + vaddr_leading_part_spec::<C>(self.cur_va()),
364 {
365 let cont = self.continuations[self.level - 1];
366 let idx = self.index();
367
368 self.cur_va_in_cont_child_range(self.level - 1);
371
372 let size = page_size::<PagingConsts>((INC_LEVELS - cont.path().len() - 1) as PagingLevel);
374 sibling_paths_disjoint::<C>(cont.path(), idx as int, j, size);
375 }
376
377 pub proof fn higher_level_children_disjoint(self, i: int, j: int)
380 requires
381 self.inv(),
382 self.in_barrier_va(),
383 self.level - 1 < i < NR_LEVELS,
384 0 <= j < NR_ENTRIES,
385 j != self.continuations[i].idx,
386 self.continuations[i].children[j] is Some,
387 ensures
388 vaddr(self.continuations[i].path().push_tail(j)) + vaddr_leading_part_spec::<C>(
389 self.cur_va(),
390 ) + page_size::<PagingConsts>((i + 1) as PagingLevel) <= self.cur_va() || self.cur_va()
391 < vaddr(self.continuations[i].path().push_tail(j)) + vaddr_leading_part_spec::<C>(
392 self.cur_va(),
393 ),
394 {
395 let cont = self.continuations[i];
396
397 self.cur_va_in_cont_child_range(i);
400
401 let size = page_size::<PagingConsts>((INC_LEVELS - cont.path().len() - 1) as PagingLevel);
403 sibling_paths_disjoint::<C>(cont.path(), cont.idx as int, j, size);
404 }
405
406 pub proof fn mapping_covering_cur_va_from_cur_subtree(self, m: Mapping)
410 requires
411 self.inv(),
412 self.in_barrier_va(),
413 self.view_mappings().contains(m),
414 m.va_range.start <= self.cur_va() < m.va_range.end,
415 ensures
416 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value().path).contains(
417 m,
418 ),
419 {
420 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
421
422 lemma_vaddr_leading_part_is_align_down::<C>(self.cur_va());
423 let i = choose|i: int|
426 self.level - 1 <= i < NR_LEVELS
427 && #[trigger] self.continuations[i].view_mappings().contains(m);
428
429 let cont_i = self.continuations[i];
430 let j = choose|j: int|
431 #![auto]
432 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
433 cont_i.children[j].unwrap(),
434 ).view_rec(cont_i.path().push_tail(j)).contains(m);
435
436 let child_j = cont_i.children[j].unwrap();
437 let path_j = cont_i.path().push_tail(j);
438 PageTableOwner(child_j).lemma_view_rec_vaddr_range(path_j, m);
439 lemma_vaddr_of_eq_int::<C>(path_j);
442
443 if i == self.level - 1 {
444 if j as usize != self.index() {
445 self.subtree_va_ranges_disjoint(j);
446 }
447 } else {
448 if j as usize != cont_i.idx as int {
449 self.higher_level_children_disjoint(i, j);
450 } else {
451 assert(false);
452 }
453 }
454 }
455
456 #[verifier::rlimit(60)]
459 pub proof fn view_mappings_replace_lowest(
460 old_self: Self,
461 new_self: Self,
462 old_cont: CursorContinuation<'rcu, C>,
463 new_cont: CursorContinuation<'rcu, C>,
464 )
465 requires
466 old_self.inv(),
467 old_self.in_barrier_va(),
468 new_self.inv(),
469 old_self.level == new_self.level,
470 old_self.continuations[old_self.level - 1] == old_cont,
471 new_self.continuations[new_self.level - 1] == new_cont,
472 forall|i: int|
473 old_self.level <= i < NR_LEVELS ==> old_self.continuations[i]
474 == new_self.continuations[i],
475 ensures
476 new_self.view_mappings() == (old_self.view_mappings() - old_cont.view_mappings()).union(
477 new_cont.view_mappings(),
478 ),
479 {
480 hide(CursorContinuation::inv_children_rel);
481 hide(CursorContinuation::inv_children);
482 hide(CursorContinuation::pt_inv_children);
483 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
484
485 let level = old_self.level;
486
487 assert forall|m: Mapping| new_self.view_mappings().contains(m) implies ((
488 old_self.view_mappings().contains(m) && !old_cont.view_mappings().contains(m))
489 || new_cont.view_mappings().contains(m)) by {
490 let i = choose|i: int|
491 level - 1 <= i < NR_LEVELS
492 && #[trigger] new_self.continuations[i].view_mappings().contains(m);
493 if i != level - 1 {
496 assert(old_self.continuations[i] == new_self.continuations[i]);
497
498 if old_cont.view_mappings().contains(m) {
499 old_self.lemma_inv_continuation(i);
500 old_self.lemma_inv_continuation(level - 1);
501 let cont_i = old_self.continuations[i];
502 let j = choose|j: int|
503 #![auto]
504 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
505 cont_i.children[j].unwrap(),
506 ).view_rec(cont_i.path().push_tail(j)).contains(m);
507 cont_i.lemma_inv_children_unroll(j);
508 cont_i.lemma_pt_inv_children_unroll(j);
509 cont_i.lemma_inv_children_rel_unroll(j);
510 PageTableOwner(cont_i.children[j].unwrap()).lemma_view_rec_vaddr_range(
511 cont_i.path().push_tail(j),
512 m,
513 );
514
515 let k = choose|k: int|
516 #![auto]
517 0 <= k < NR_ENTRIES && old_cont.children[k] is Some && PageTableOwner(
518 old_cont.children[k].unwrap(),
519 ).view_rec(old_cont.path().push_tail(k)).contains(m);
520 old_cont.lemma_inv_children_unroll(k);
521 old_cont.lemma_pt_inv_children_unroll(k);
522 old_cont.lemma_inv_children_rel_unroll(k);
523 PageTableOwner(old_cont.children[k].unwrap()).lemma_view_rec_vaddr_range(
524 old_cont.path().push_tail(k),
525 m,
526 );
527
528 if j as usize != cont_i.idx as int {
529 old_self.cur_va_in_cont_child_range(level as int);
530 old_self.cur_va_in_cont_child_range(i);
531
532 let x = old_self.cur_va() as nat;
533 let ps_node = page_size::<PagingConsts>((level + 1) as PagingLevel) as nat;
534 let ps_anc = page_size::<PagingConsts>((i + 1) as PagingLevel) as nat;
535
536 lemma_page_size_ge_base::<PagingConsts>((i + 1) as PagingLevel);
537 lemma_page_size_divides::<PagingConsts>(
538 (level + 1) as PagingLevel,
539 (i + 1) as PagingLevel,
540 );
541
542 lemma_nat_align_down_monotone(x, ps_node, ps_anc);
543 lemma_nat_align_down_within_block(x, ps_node, ps_anc);
544
545 let sib_size = page_size::<PagingConsts>(
546 (INC_LEVELS - cont_i.path().len() - 1) as PagingLevel,
547 );
548 sibling_paths_disjoint::<C>(cont_i.path(), cont_i.idx as int, j, sib_size);
549 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(cont_i.idx as int));
551 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(j));
552
553 old_cont.as_subtree_inv();
554 old_cont.as_page_table_owner_preserves_view_mappings();
555 PageTableOwner(old_cont.as_subtree()).lemma_view_rec_vaddr_range(
556 old_cont.path(),
557 m,
558 );
559 } else {
560 assert(cont_i.children[cont_i.idx as int] is None);
561 }
562 }
563 }
564 };
565
566 }
567
568 #[verifier::rlimit(120)]
569 pub proof fn as_page_table_owner_preserves_view_mappings(self)
570 requires
571 self.inv(),
572 ensures
573 self.as_page_table_owner().view_rec(self.continuations[3].path())
574 == self.view_mappings(),
575 self.as_page_table_owner().0.inv(),
576 self.as_page_table_owner().0.level() == self.continuations[3].tree_level,
577 self.as_page_table_owner().pt_inv(),
578 {
579 broadcast use CursorOwner::group_lemmas;
580
581 if self.level == 4 {
582 self.continuations[3].as_page_table_owner_preserves_view_mappings();
583 self.lemma_inv_continuation(3);
584 assert(self.view_mappings() == self.continuations[3].view_mappings());
585 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
586 == self.view_mappings());
587 } else if self.level == 3 {
588 let c2 = self.continuations[2];
589 let c3 = self.continuations[3];
590
591 c2.as_page_table_owner_preserves_view_mappings();
592 c2.as_subtree_inv();
593 c3.view_mappings_put_child(c2.as_subtree());
594 c3.as_subtree_restore(c2);
595
596 let l4 = c3.restore(c2).0;
597 c2.as_page_table_owner_pt_inv();
598
599 c2.lemma_inv_children_unroll_all();
600 c3.lemma_inv_children_unroll_all();
601 l4.as_page_table_owner_preserves_view_mappings();
602
603 assert(self.view_mappings() == self.continuations[2].view_mappings().union(
604 self.continuations[3].view_mappings(),
605 )) by {
606 assert forall|m: Mapping| #[trigger]
607 self.view_mappings().contains(
608 m,
609 ) implies self.continuations[2].view_mappings().contains(m)
610 || self.continuations[3].view_mappings().contains(m) by {
611 let i = choose|i: int|
612 2 <= i < NR_LEVELS
613 && #[trigger] self.continuations[i].view_mappings().contains(m);
614 };
615 };
616 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
617 == self.view_mappings());
618 } else if self.level == 2 {
619 let c1 = self.continuations[1];
620 let c2 = self.continuations[2];
621 let c3 = self.continuations[3];
622
623 c1.as_page_table_owner_preserves_view_mappings();
624 c1.as_subtree_inv();
625 c2.view_mappings_put_child(c1.as_subtree());
626 c2.as_subtree_restore(c1);
627
628 let l3 = c2.restore(c1).0;
629 c1.as_page_table_owner_pt_inv();
630
631 c1.lemma_inv_children_unroll_all();
632 c2.lemma_inv_children_unroll_all();
633 l3.as_page_table_owner_preserves_view_mappings();
634 l3.as_subtree_inv();
635 c3.as_subtree_restore(l3);
636 c3.view_mappings_put_child(l3.as_subtree());
637
638 let l4 = c3.restore(l3).0;
639 l3.as_page_table_owner_pt_inv();
640
641 c3.lemma_inv_children_unroll_all();
642 l4.as_page_table_owner_preserves_view_mappings();
643
644 assert(self.view_mappings() == c1.view_mappings().union(c2.view_mappings()).union(
645 c3.view_mappings(),
646 )) by {
647 assert forall|m: Mapping| self.view_mappings().contains(m) implies (
648 c1.view_mappings().contains(m) || c2.view_mappings().contains(m)
649 || c3.view_mappings().contains(m)) by {
650 let i = choose|i: int|
651 1 <= i < NR_LEVELS
652 && #[trigger] self.continuations[i].view_mappings().contains(m);
653 };
654 };
655 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
656 == self.view_mappings());
657 } else {
658 let c0 = self.continuations[0];
660 let c1 = self.continuations[1];
661 let c2 = self.continuations[2];
662 let c3 = self.continuations[3];
663
664 c0.as_page_table_owner_preserves_view_mappings();
665 c0.as_subtree_inv();
666 c1.view_mappings_put_child(c0.as_subtree());
667 c1.as_subtree_restore(c0);
668 let l2 = c1.restore(c0).0;
669 c0.as_page_table_owner_pt_inv();
670
671 c0.lemma_inv_children_unroll_all();
672 c1.lemma_inv_children_unroll_all();
673 l2.as_page_table_owner_preserves_view_mappings();
674 l2.as_subtree_inv();
675 c2.view_mappings_put_child(l2.as_subtree());
676 c2.as_subtree_restore(l2);
677 let l3 = c2.restore(l2).0;
678 l2.as_page_table_owner_pt_inv();
679
680 c2.lemma_inv_children_unroll_all();
681 l3.as_page_table_owner_preserves_view_mappings();
682 l3.as_subtree_inv();
683 c3.view_mappings_put_child(l3.as_subtree());
684 c3.as_subtree_restore(l3);
685 let l4 = c3.restore(l3).0;
686 l3.as_page_table_owner_pt_inv();
687
688 c3.lemma_inv_children_unroll_all();
689 l4.as_page_table_owner_preserves_view_mappings();
690
691 assert(self.view_mappings() == c0.view_mappings().union(c1.view_mappings()).union(
692 c2.view_mappings(),
693 ).union(c3.view_mappings())) by {
694 assert forall|m: Mapping| self.view_mappings().contains(m) implies (
695 c0.view_mappings().contains(m) || c1.view_mappings().contains(m)
696 || c2.view_mappings().contains(m) || c3.view_mappings().contains(m)) by {
697 let i = choose|i: int|
698 0 <= i < NR_LEVELS
699 && #[trigger] self.continuations[i].view_mappings().contains(m);
700 };
701 };
702 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
703 == self.view_mappings());
704 }
705 }
706
707 pub proof fn lemma_view_mapping_inv(self)
709 requires
710 self.inv(),
711 ensures
712 forall|m: Mapping| self.view_mappings().contains(m) ==> #[trigger] m.inv(),
713 {
714 self.as_page_table_owner_preserves_view_mappings();
715 let pto = self.as_page_table_owner();
716 let root_path = self.continuations[3].path();
717 pto.lemma_view_rec_mapping_inv(root_path);
718 }
719
720 pub proof fn as_page_table_owner_view_non_overlapping(self)
727 requires
728 self.inv(),
729 ensures
730 self@.non_overlapping(),
731 {
732 self.as_page_table_owner_preserves_view_mappings();
733 let pto = self.as_page_table_owner();
734 let root_path = self.continuations[3].path();
735
736 assert forall|m: Mapping, n: Mapping| #[trigger]
737 self@.mappings.contains(m) && #[trigger] self@.mappings.contains(n) && m
738 != n implies m.va_range.end <= n.va_range.start || n.va_range.end
739 <= m.va_range.start by {
740 pto.lemma_view_rec_disjoint_vaddrs(root_path, m, n);
741 };
742 }
743}
744
745}