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 Mapping,
15 cursor::{
16 owners::*,
17 page_size_lemmas::{lemma_page_size_divides, lemma_page_size_ge_base},
18 },
19 lemma_pte_index_bound, lemma_vaddr_upper_part_is_align_down,
20 owners::{
21 INC_LEVELS, OwnerSubtree, PageTableOwner, lemma_vaddr_of_eq_int,
22 lemma_vaddr_path_aligned, sibling_paths_disjoint, vaddr, vaddr_of,
23 },
24 pte_index_spec, vaddr_upper_part_spec,
25 },
26};
27
28use crate::arch::mm::PagingConsts;
29use crate::mm::{PagingConstsTrait, PagingLevel, Vaddr, page_size, page_table::*};
30
31verus! {
32
33broadcast use group_ghost_tree_lemmas;
34impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
37 pub proof fn as_page_table_owner_preserves_view_mappings(self)
38 requires
39 self.inv(),
40 self.all_some(),
41 ensures
42 self.as_page_table_owner().view_rec(self.path()) == self.view_mappings(),
43 self.as_subtree().inv(),
44 PageTableOwner(self.as_subtree()).pt_inv(),
45 {
46 broadcast use {CursorContinuation::group_lemmas, PageTableOwner::group_lemmas};
47
48 self.as_page_table_owner_pt_inv();
49 }
50
51 pub proof fn view_mappings_take_child(self)
52 requires
53 self.inv(),
54 self.all_some(),
55 ensures
56 self.take_child().1.view_mappings() == self.view_mappings()
57 - self.view_mappings_take_child_spec(),
58 {
59 broadcast use CursorContinuation::group_lemmas;
60
61 let def = self.take_child().1.view_mappings();
62 let diff = self.view_mappings() - self.view_mappings_take_child_spec();
63 assert forall|m: Mapping| diff.contains(m) implies def.contains(m) by {
64 let i = choose|i: int|
65 0 <= i < self.children.len() && #[trigger] self.children[i] is Some
66 && PageTableOwner(self.children[i].unwrap()).view_rec(
67 self.path().push_tail(i),
68 ).contains(m);
69 assert(self.take_child().1.children[i] is Some);
70 };
71 assert forall|m: Mapping| #![trigger def.contains(m)] def.contains(m) implies diff.contains(
72 m,
73 ) by {
74 let left = self.take_child().1;
75 if self.view_mappings_take_child_spec().contains(m) {
76 let i = choose|i: int|
77 0 <= i < left.children.len() && #[trigger] left.children[i] is Some
78 && PageTableOwner(left.children[i].unwrap()).view_rec(
79 left.path().push_tail(i),
80 ).contains(m);
81
82 PageTableOwner(self.children[self.idx as int].unwrap()).view_rec_vaddr_range(
83 self.path().push_tail(self.idx as int),
84 m,
85 );
86 PageTableOwner(left.children[i as int].unwrap()).view_rec_vaddr_range(
87 left.path().push_tail(i),
88 m,
89 );
90
91 let size = page_size::<PagingConsts>(
92 (INC_LEVELS - self.path().len() - 1) as PagingLevel,
93 );
94 sibling_paths_disjoint::<C>(self.path(), self.idx as int, i, size);
96 lemma_vaddr_of_eq_int::<C>(self.path().push_tail(self.idx as int));
97 lemma_vaddr_of_eq_int::<C>(self.path().push_tail(i));
98 }
99 };
100 }
101
102 pub proof fn view_mappings_put_child(self, child: OwnerSubtree<C>)
103 requires
104 self.inv(),
105 child.inv(),
106 self.all_but_index_some(),
107 ensures
108 self.put_child(child).view_mappings() == self.view_mappings() + PageTableOwner(
109 child,
110 ).view_rec(self.path().push_tail(self.idx as int)),
111 {
112 broadcast use CursorContinuation::group_lemmas;
113
114 let def = self.put_child(child).view_mappings();
115 let sum = self.view_mappings() + PageTableOwner(child).view_rec(
116 self.path().push_tail(self.idx as int),
117 );
118 assert forall|m: Mapping| sum.contains(m) implies def.contains(m) by {
119 if self.view_mappings().contains(m) {
120 let i = choose|i: int|
121 0 <= i < self.children.len() && #[trigger] self.children[i] is Some
122 && PageTableOwner(self.children[i].unwrap()).view_rec(
123 self.path().push_tail(i),
124 ).contains(m);
125 assert(self.put_child(child).children[i] == self.children[i]);
126 } else {
127 self.put_child(child).lemma_view_mappings_intro(m, self.idx as int);
128 }
129 };
130 }
131}
132
133impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
134 proof fn as_subtree_inv(self)
136 requires
137 self.inv(),
138 self.all_some(),
139 ensures
140 self.as_subtree().inv(),
141 {
142 }
143
144 proof fn as_page_table_owner_pt_inv(self)
145 requires
146 self.inv(),
147 self.all_some(),
148 ensures
149 PageTableOwner(self.as_subtree()).pt_inv(),
150 {
151 reveal(PageTableOwner::pt_inv_at_depth);
152 }
153}
154
155impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
157 pub proof fn cur_subtree_eq_filtered_mappings_path(self)
160 requires
161 self.inv(),
162 self.in_locked_range(),
163 ensures
164 ({
165 let subtree_va = vaddr_of::<C>(self.cur_subtree().value().path) as int;
166 let size = page_size::<PagingConsts>(self.level) as int;
167 PageTableOwner(self.cur_subtree())@.mappings == self@.mappings.filter(
168 |m: Mapping| subtree_va <= m.va_range.start < subtree_va + size,
169 )
170 }),
171 {
172 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
173
174 let cur_subtree = self.cur_subtree();
175 let cur_path = cur_subtree.value().path;
176 let subtree_va = vaddr_of::<C>(cur_path) as int;
177 let size = page_size::<PagingConsts>(self.level) as int;
178
179 let subtree_mappings = PageTableOwner(cur_subtree)@.mappings;
180 let filtered = self@.mappings.filter(
181 |m: Mapping| subtree_va <= m.va_range.start < subtree_va + size,
182 );
183
184 let cont = self.continuations[self.level - 1];
185 assert forall|m: Mapping| subtree_mappings.contains(m) implies filtered.contains(m) by {
189 PageTableOwner(cur_subtree).view_rec_vaddr_range(cur_path, m);
194 };
195
196 assert forall|m: Mapping| filtered.contains(m) implies subtree_mappings.contains(m) by {
198 let i = choose|i: int|
200 self.level - 1 <= i < NR_LEVELS
201 && #[trigger] self.continuations[i].view_mappings().contains(m);
202
203 let cont_i = self.continuations[i];
204 let j = choose|j: int|
205 #![auto]
206 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
207 cont_i.children[j].unwrap(),
208 ).view_rec(cont_i.path().push_tail(j)).contains(m);
209
210 PageTableOwner(cont_i.children[j].unwrap()).view_rec_vaddr_range(
211 cont_i.path().push_tail(j),
212 m,
213 );
214
215 if i == self.level - 1 {
216 if j as usize != self.index() {
219 let sib_size = page_size::<PagingConsts>(
221 (INC_LEVELS - cont.path().len() - 1) as PagingLevel,
222 );
223 sibling_paths_disjoint::<C>(cont.path(), self.index() as int, j, sib_size);
224 lemma_vaddr_of_eq_int::<C>(cont.path().push_tail(self.index() as int));
227 lemma_vaddr_of_eq_int::<C>(cont.path().push_tail(j));
228 assert(false); }
230 } else {
231 if j as usize != cont_i.idx as int {
232 self.subtree_va_in_ancestor_range(i);
234
235 let sib_size = page_size::<PagingConsts>(
237 (INC_LEVELS - cont_i.path().len() - 1) as PagingLevel,
238 );
239 sibling_paths_disjoint::<C>(cont_i.path(), cont_i.idx as int, j, sib_size);
240 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(j));
241 lemma_vaddr_of_eq_int::<C>(cur_path);
242 assert(false); } else {
244 assert(false); }
246 }
247 };
248
249 }
250
251 pub proof fn cur_subtree_eq_filtered_mappings(self)
254 requires
255 self.inv(),
256 self.in_locked_range(),
257 ensures
258 ({
259 let start = nat_align_down(
260 self@.cur_va as nat,
261 page_size::<PagingConsts>(self.level) as nat,
262 ) as Vaddr;
263 let size = page_size::<PagingConsts>(self.level);
264 PageTableOwner(self.cur_subtree())@.mappings == self@.mappings.filter(
265 |m: Mapping| start <= m.va_range.start < start + size,
266 )
267 }),
268 {
269 self.cur_subtree_eq_filtered_mappings_path();
270 self.cur_va_in_subtree_range();
271 }
272
273 pub(super) proof fn cur_va_in_cont_child_range(self, lvl: int)
277 requires
278 self.inv(),
279 self.in_locked_range(),
280 self.level - 1 <= lvl < NR_LEVELS,
281 ensures
282 vaddr(self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int))
283 + vaddr_upper_part_spec::<C>(self.cur_va()) <= self.cur_va(),
284 self.cur_va() < vaddr(
285 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int),
286 ) + vaddr_upper_part_spec::<C>(self.cur_va()) + page_size::<PagingConsts>(
287 (lvl + 1) as PagingLevel,
288 ),
289 vaddr(self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int))
290 + vaddr_upper_part_spec::<C>(self.cur_va()) == nat_align_down(
291 self.cur_va() as nat,
292 page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat,
293 ),
294 vaddr_of::<C>(
295 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int),
296 ) == nat_align_down(
297 self.cur_va() as nat,
298 page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat,
299 ),
300 {
301 C::lemma_paging_consts_properties();
302 lemma_vaddr_upper_part_is_align_down::<C>(self.cur_va());
303 let cont = self.continuations[lvl];
304 let child_path = cont.path().push_tail(cont.idx as int);
305 assert(child_path.len() == C::NR_LEVELS() - lvl);
306 assert forall|k: int| 0 <= k < child_path.len() implies #[trigger] child_path[k]
307 == pte_index_spec::<C>(self.cur_va(), (C::NR_LEVELS() - k) as PagingLevel) by {
308 lemma_pte_index_bound::<C>(self.cur_va(), (C::NR_LEVELS() - k) as PagingLevel);
309 };
310 lemma_vaddr_path_aligned::<C>(child_path, self.cur_va());
311 lemma_vaddr_of_eq_int::<C>(child_path);
312 lemma_page_size_ge_base::<PagingConsts>((lvl + 1) as PagingLevel);
313 lemma_nat_align_down_sound(
314 self.cur_va() as nat,
315 page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat,
316 );
317 }
318
319 proof fn subtree_va_in_ancestor_range(self, lvl: int)
322 requires
323 self.inv(),
324 self.in_locked_range(),
325 self.level - 1 < lvl < NR_LEVELS,
326 ensures
327 ({
328 let subtree_va = vaddr(self.cur_subtree().value().path);
329 let idx_path_va = vaddr(
330 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as int),
331 );
332 &&& idx_path_va <= subtree_va
333 &&& subtree_va + page_size::<PagingConsts>(self.level) <= idx_path_va + page_size::<
334 PagingConsts,
335 >((lvl + 1) as PagingLevel)
336 }),
337 {
338 self.cur_va_in_cont_child_range(self.level - 1);
339 self.cur_va_in_cont_child_range(lvl);
340
341 let x = self.cur_va() as nat;
342 let fine = page_size::<PagingConsts>(self.level as PagingLevel) as nat;
343 let coarse = page_size::<PagingConsts>((lvl + 1) as PagingLevel) as nat;
344
345 lemma_page_size_divides::<PagingConsts>(
346 self.level as PagingLevel,
347 (lvl + 1) as PagingLevel,
348 );
349 lemma_nat_align_down_monotone(x, fine, coarse);
350 lemma_nat_align_down_within_block(x, fine, coarse);
351 }
352
353 pub proof fn subtree_va_ranges_disjoint(self, j: int)
355 requires
356 self.inv(),
357 self.in_locked_range(),
358 0 <= j < NR_ENTRIES,
359 j != self.index(),
360 self.continuations[self.level - 1].children[j] is Some,
361 ensures
362 vaddr(self.continuations[self.level - 1].path().push_tail(j)) + vaddr_upper_part_spec::<
363 C,
364 >(self.cur_va()) + page_size::<PagingConsts>(self.level as PagingLevel) <= self.cur_va()
365 || self.cur_va() < vaddr(self.continuations[self.level - 1].path().push_tail(j))
366 + vaddr_upper_part_spec::<C>(self.cur_va()),
367 {
368 let cont = self.continuations[self.level - 1];
369 let idx = self.index();
370
371 self.cur_va_in_cont_child_range(self.level - 1);
374
375 let size = page_size::<PagingConsts>((INC_LEVELS - cont.path().len() - 1) as PagingLevel);
377 sibling_paths_disjoint::<C>(cont.path(), idx as int, j, size);
378 }
379
380 pub proof fn higher_level_children_disjoint(self, i: int, j: int)
383 requires
384 self.inv(),
385 self.in_locked_range(),
386 self.level - 1 < i < NR_LEVELS,
387 0 <= j < NR_ENTRIES,
388 j != self.continuations[i].idx,
389 self.continuations[i].children[j] is Some,
390 ensures
391 vaddr(self.continuations[i].path().push_tail(j)) + vaddr_upper_part_spec::<C>(
392 self.cur_va(),
393 ) + page_size::<PagingConsts>((i + 1) as PagingLevel) <= self.cur_va() || self.cur_va()
394 < vaddr(self.continuations[i].path().push_tail(j)) + vaddr_upper_part_spec::<C>(
395 self.cur_va(),
396 ),
397 {
398 let cont = self.continuations[i];
399
400 self.cur_va_in_cont_child_range(i);
403
404 let size = page_size::<PagingConsts>((INC_LEVELS - cont.path().len() - 1) as PagingLevel);
406 sibling_paths_disjoint::<C>(cont.path(), cont.idx as int, j, size);
407 }
408
409 pub proof fn mapping_covering_cur_va_from_cur_subtree(self, m: Mapping)
413 requires
414 self.inv(),
415 self.in_locked_range(),
416 self.view_mappings().contains(m),
417 m.va_range.start <= self.cur_va() < m.va_range.end,
418 ensures
419 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value().path).contains(
420 m,
421 ),
422 {
423 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
424
425 lemma_vaddr_upper_part_is_align_down::<C>(self.cur_va());
426 let i = choose|i: int|
429 self.level - 1 <= i < NR_LEVELS
430 && #[trigger] self.continuations[i].view_mappings().contains(m);
431
432 let cont_i = self.continuations[i];
433 let j = choose|j: int|
434 #![auto]
435 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
436 cont_i.children[j].unwrap(),
437 ).view_rec(cont_i.path().push_tail(j)).contains(m);
438
439 let child_j = cont_i.children[j].unwrap();
440 let path_j = cont_i.path().push_tail(j);
441 PageTableOwner(child_j).view_rec_vaddr_range(path_j, m);
442 lemma_vaddr_of_eq_int::<C>(path_j);
445
446 if i == self.level - 1 {
447 if j as usize != self.index() {
448 self.subtree_va_ranges_disjoint(j);
449 }
450 } else {
451 if j as usize != cont_i.idx as int {
452 self.higher_level_children_disjoint(i, j);
453 } else {
454 assert(false);
455 }
456 }
457 }
458
459 #[verifier::rlimit(60)]
462 pub proof fn view_mappings_replace_lowest(
463 old_self: Self,
464 new_self: Self,
465 old_cont: CursorContinuation<'rcu, C>,
466 new_cont: CursorContinuation<'rcu, C>,
467 )
468 requires
469 old_self.inv(),
470 old_self.in_locked_range(),
471 new_self.inv(),
472 old_self.level == new_self.level,
473 old_self.continuations[old_self.level - 1] == old_cont,
474 new_self.continuations[new_self.level - 1] == new_cont,
475 forall|i: int|
476 old_self.level <= i < NR_LEVELS ==> old_self.continuations[i]
477 == new_self.continuations[i],
478 ensures
479 new_self.view_mappings() == (old_self.view_mappings() - old_cont.view_mappings()).union(
480 new_cont.view_mappings(),
481 ),
482 {
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 PageTableOwner(cont_i.children[j].unwrap()).view_rec_vaddr_range(
509 cont_i.path().push_tail(j),
510 m,
511 );
512
513 let k = choose|k: int|
514 #![auto]
515 0 <= k < NR_ENTRIES && old_cont.children[k] is Some && PageTableOwner(
516 old_cont.children[k].unwrap(),
517 ).view_rec(old_cont.path().push_tail(k)).contains(m);
518 old_cont.lemma_inv_children_unroll(k);
519 PageTableOwner(old_cont.children[k].unwrap()).view_rec_vaddr_range(
520 old_cont.path().push_tail(k),
521 m,
522 );
523
524 if j as usize != cont_i.idx as int {
525 old_self.cur_va_in_cont_child_range(level as int);
526 old_self.cur_va_in_cont_child_range(i);
527
528 let x = old_self.cur_va() as nat;
529 let ps_node = page_size::<PagingConsts>((level + 1) as PagingLevel) as nat;
530 let ps_anc = page_size::<PagingConsts>((i + 1) as PagingLevel) as nat;
531
532 lemma_page_size_ge_base::<PagingConsts>((i + 1) as PagingLevel);
533 lemma_page_size_divides::<PagingConsts>(
534 (level + 1) as PagingLevel,
535 (i + 1) as PagingLevel,
536 );
537
538 lemma_nat_align_down_monotone(x, ps_node, ps_anc);
539 lemma_nat_align_down_within_block(x, ps_node, ps_anc);
540
541 let sib_size = page_size::<PagingConsts>(
542 (INC_LEVELS - cont_i.path().len() - 1) as PagingLevel,
543 );
544 sibling_paths_disjoint::<C>(cont_i.path(), cont_i.idx as int, j, sib_size);
545 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(cont_i.idx as int));
547 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(j));
548
549 old_cont.as_subtree_inv();
550 old_cont.as_page_table_owner_preserves_view_mappings();
551 PageTableOwner(old_cont.as_subtree()).view_rec_vaddr_range(
552 old_cont.path(),
553 m,
554 );
555 } else {
556 assert(cont_i.children[cont_i.idx as int] is None);
557 }
558 }
559 }
560 };
561
562 }
563
564 #[verifier::rlimit(120)]
565 pub proof fn as_page_table_owner_preserves_view_mappings(self)
566 requires
567 self.inv(),
568 ensures
569 self.as_page_table_owner().view_rec(self.continuations[3].path())
570 == self.view_mappings(),
571 self.as_page_table_owner().0.inv(),
572 self.as_page_table_owner().0.level() == self.continuations[3].tree_level,
573 self.as_page_table_owner().pt_inv(),
574 {
575 broadcast use CursorOwner::group_lemmas;
576
577 if self.level == 4 {
578 self.continuations[3].as_page_table_owner_preserves_view_mappings();
579 self.lemma_inv_continuation(3);
580 assert(self.view_mappings() == self.continuations[3].view_mappings());
581 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
582 == self.view_mappings());
583 } else if self.level == 3 {
584 let c2 = self.continuations[2];
585 let c3 = self.continuations[3];
586
587 c2.as_page_table_owner_preserves_view_mappings();
588 c2.as_subtree_inv();
589 c3.view_mappings_put_child(c2.as_subtree());
590 c3.as_subtree_restore(c2);
591
592 let l4 = c3.restore(c2).0;
593 c2.as_page_table_owner_pt_inv();
594
595 c2.lemma_inv_children_unroll_all();
596 c3.lemma_inv_children_unroll_all();
597 l4.as_page_table_owner_preserves_view_mappings();
598
599 assert(self.view_mappings() == self.continuations[2].view_mappings().union(
600 self.continuations[3].view_mappings(),
601 )) by {
602 assert forall|m: Mapping| #[trigger]
603 self.view_mappings().contains(
604 m,
605 ) implies self.continuations[2].view_mappings().contains(m)
606 || self.continuations[3].view_mappings().contains(m) by {
607 let i = choose|i: int|
608 2 <= i < NR_LEVELS
609 && #[trigger] self.continuations[i].view_mappings().contains(m);
610 };
611 };
612 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
613 == self.view_mappings());
614 } else if self.level == 2 {
615 let c1 = self.continuations[1];
616 let c2 = self.continuations[2];
617 let c3 = self.continuations[3];
618
619 c1.as_page_table_owner_preserves_view_mappings();
620 c1.as_subtree_inv();
621 c2.view_mappings_put_child(c1.as_subtree());
622 c2.as_subtree_restore(c1);
623
624 let l3 = c2.restore(c1).0;
625 c1.as_page_table_owner_pt_inv();
626
627 c1.lemma_inv_children_unroll_all();
628 c2.lemma_inv_children_unroll_all();
629 l3.as_page_table_owner_preserves_view_mappings();
630 l3.as_subtree_inv();
631 c3.as_subtree_restore(l3);
632 c3.view_mappings_put_child(l3.as_subtree());
633
634 let l4 = c3.restore(l3).0;
635 l3.as_page_table_owner_pt_inv();
636
637 c3.lemma_inv_children_unroll_all();
638 l4.as_page_table_owner_preserves_view_mappings();
639
640 assert(self.view_mappings() == c1.view_mappings().union(c2.view_mappings()).union(
641 c3.view_mappings(),
642 )) by {
643 assert forall|m: Mapping| self.view_mappings().contains(m) implies (
644 c1.view_mappings().contains(m) || c2.view_mappings().contains(m)
645 || c3.view_mappings().contains(m)) by {
646 let i = choose|i: int|
647 1 <= i < NR_LEVELS
648 && #[trigger] self.continuations[i].view_mappings().contains(m);
649 };
650 };
651 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
652 == self.view_mappings());
653 } else {
654 let c0 = self.continuations[0];
656 let c1 = self.continuations[1];
657 let c2 = self.continuations[2];
658 let c3 = self.continuations[3];
659
660 c0.as_page_table_owner_preserves_view_mappings();
661 c0.as_subtree_inv();
662 c1.view_mappings_put_child(c0.as_subtree());
663 c1.as_subtree_restore(c0);
664 let l2 = c1.restore(c0).0;
665 c0.as_page_table_owner_pt_inv();
666
667 c0.lemma_inv_children_unroll_all();
668 c1.lemma_inv_children_unroll_all();
669 l2.as_page_table_owner_preserves_view_mappings();
670 l2.as_subtree_inv();
671 c2.view_mappings_put_child(l2.as_subtree());
672 c2.as_subtree_restore(l2);
673 let l3 = c2.restore(l2).0;
674 l2.as_page_table_owner_pt_inv();
675
676 c2.lemma_inv_children_unroll_all();
677 l3.as_page_table_owner_preserves_view_mappings();
678 l3.as_subtree_inv();
679 c3.view_mappings_put_child(l3.as_subtree());
680 c3.as_subtree_restore(l3);
681 let l4 = c3.restore(l3).0;
682 l3.as_page_table_owner_pt_inv();
683
684 c3.lemma_inv_children_unroll_all();
685 l4.as_page_table_owner_preserves_view_mappings();
686
687 assert(self.view_mappings() == c0.view_mappings().union(c1.view_mappings()).union(
688 c2.view_mappings(),
689 ).union(c3.view_mappings())) by {
690 assert forall|m: Mapping| self.view_mappings().contains(m) implies (
691 c0.view_mappings().contains(m) || c1.view_mappings().contains(m)
692 || c2.view_mappings().contains(m) || c3.view_mappings().contains(m)) by {
693 let i = choose|i: int|
694 0 <= i < NR_LEVELS
695 && #[trigger] self.continuations[i].view_mappings().contains(m);
696 };
697 };
698 assert(self.as_page_table_owner().view_rec(self.continuations[3].path())
699 == self.view_mappings());
700 }
701 }
702
703 pub proof fn 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.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.view_rec_disjoint_vaddrs(root_path, m, n);
741 };
742 }
743}
744
745}