1use vstd::prelude::*;
2
3use vstd_extra::arithmetic::{
4 lemma_nat_align_down_monotone, lemma_nat_align_down_within_block, nat_align_down,
5};
6use vstd_extra::ghost_tree::*;
7use vstd_extra::ownership::*;
8
9use crate::mm::page_table::*;
10use crate::mm::{PagingLevel, Vaddr, page_size};
11use crate::specs::arch::{NR_ENTRIES, NR_LEVELS};
12use crate::specs::mm::page_table::cursor::owners::*;
13use crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides;
14use crate::specs::mm::page_table::owners::{
15 INC_LEVELS, OwnerSubtree, PageTableOwner, lemma_vaddr_of_eq_int, sibling_paths_disjoint, vaddr,
16 vaddr_of,
17};
18use crate::specs::mm::page_table::{AbstractVaddr, Mapping};
19
20verus! {
21
22impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
24 pub proof fn as_page_table_owner_preserves_view_mappings(self)
25 requires
26 self.inv(),
27 self.all_some(),
28 ensures
29 self.as_page_table_owner().view_rec(self.path()) == self.view_mappings(),
30 self.as_subtree().inv(),
31 PageTableOwner(self.as_subtree()).pt_inv(),
32 {
33 broadcast use {CursorContinuation::group_lemmas, PageTableOwner::group_lemmas};
34
35 self.inv_children_unroll_all();
36 self.as_subtree_inv();
37 self.as_page_table_owner_pt_inv();
38 let pto = self.as_page_table_owner();
39 assert(self.as_page_table_owner().view_rec(self.path()) == self.view_mappings()) by {
40 assert forall|m: Mapping|
41 #![auto]
42 self.view_mappings().contains(m) implies pto.view_rec(self.path()).contains(m) by {
43 let i = choose|i: int|
44 #![auto]
45 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
46 self.children[i].unwrap(),
47 ).view_rec(self.path().push_tail(i as usize)).contains(m);
48 assert(pto.view_rec(self.path()).contains(m));
49 };
50 assert forall|m: Mapping|
51 pto.view_rec(self.path()).contains(
52 m,
53 ) implies #[trigger] self.view_mappings().contains(m) by {
54 let i = choose|i: int|
55 #![auto]
56 0 <= i < pto.0.children.len() && pto.0.children[i] is Some && PageTableOwner(
57 pto.0.children[i].unwrap(),
58 ).view_rec(self.path().push_tail(i as usize)).contains(m);
59 };
60 };
61 }
62
63 pub proof fn view_mappings_take_child(self)
64 requires
65 self.inv(),
66 self.all_some(),
67 ensures
68 self.take_child().1.view_mappings() == self.view_mappings()
69 - self.view_mappings_take_child_spec(),
70 {
71 broadcast use CursorContinuation::group_lemmas;
72
73 self.inv_children_unroll_all();
74 let def = self.take_child().1.view_mappings();
75 let diff = self.view_mappings() - self.view_mappings_take_child_spec();
76 assert forall|m: Mapping| diff.contains(m) implies def.contains(m) by {
77 let i = choose|i: int|
78 0 <= i < self.children.len() && #[trigger] self.children[i] is Some
79 && PageTableOwner(self.children[i].unwrap()).view_rec(
80 self.path().push_tail(i as usize),
81 ).contains(m);
82 assert(i != self.idx);
83 assert(self.take_child().1.children[i] is Some);
84 };
85 assert forall|m: Mapping| #![trigger def.contains(m)] def.contains(m) implies diff.contains(
86 m,
87 ) by {
88 let left = self.take_child().1;
89 assert(left.view_mappings().contains(m));
90 let wi = choose|i: int|
92 #![auto]
93 0 <= i < left.children.len() && left.children[i] is Some && PageTableOwner(
94 left.children[i].unwrap(),
95 ).view_rec(left.path().push_tail(i as usize)).contains(m);
96 if self.view_mappings_take_child_spec().contains(m) {
97 assert(PageTableOwner(self.children[self.idx as int].unwrap()).view_rec(
98 self.path().push_tail(self.idx as usize),
99 ).contains(m));
100 let i = choose|i: int|
101 0 <= i < left.children.len() && #[trigger] left.children[i] is Some
102 && PageTableOwner(left.children[i].unwrap()).view_rec(
103 left.path().push_tail(i as usize),
104 ).contains(m);
105 assert(PageTableOwner(left.children[i as int].unwrap()).view_rec(
106 left.path().push_tail(i as usize),
107 ).contains(m));
108
109 PageTableOwner(self.children[self.idx as int].unwrap()).view_rec_vaddr_range(
110 self.path().push_tail(self.idx as usize),
111 m,
112 );
113 PageTableOwner(left.children[i as int].unwrap()).view_rec_vaddr_range(
114 left.path().push_tail(i as usize),
115 m,
116 );
117
118 let size = page_size((INC_LEVELS - self.path().len() - 1) as PagingLevel);
119 sibling_paths_disjoint::<C>(self.path(), self.idx, i as usize, size);
121 lemma_vaddr_of_eq_int::<C>(self.path().push_tail(self.idx as usize));
122 lemma_vaddr_of_eq_int::<C>(self.path().push_tail(i as usize));
123 }
124 };
125 }
126
127 pub proof fn view_mappings_put_child(self, child: OwnerSubtree<C>)
128 requires
129 self.inv(),
130 child.inv(),
131 self.all_but_index_some(),
132 ensures
133 self.put_child(child).view_mappings() == self.view_mappings() + PageTableOwner(
134 child,
135 ).view_rec(self.path().push_tail(self.idx as usize)),
136 {
137 broadcast use CursorContinuation::group_lemmas;
138
139 let def = self.put_child(child).view_mappings();
140 let sum = self.view_mappings() + PageTableOwner(child).view_rec(
141 self.path().push_tail(self.idx as usize),
142 );
143 assert forall|m: Mapping| sum.contains(m) implies def.contains(m) by {
144 if self.view_mappings().contains(m) {
145 let i = choose|i: int|
146 0 <= i < self.children.len() && #[trigger] self.children[i] is Some
147 && PageTableOwner(self.children[i].unwrap()).view_rec(
148 self.path().push_tail(i as usize),
149 ).contains(m);
150 assert(self.put_child(child).children[i] == self.children[i]);
151 self.put_child(child).lemma_view_mappings_intro(m, i);
152 } else {
153 assert(PageTableOwner(child).view_rec(
154 self.path().push_tail(self.idx as usize),
155 ).contains(m));
156 assert(self.put_child(child).children[self.idx as int] == Some(child));
157 self.put_child(child).lemma_view_mappings_intro(m, self.idx as int);
158 }
159 };
160 assert forall|m: Mapping| def.contains(m) implies sum.contains(m) by {
161 let i = choose|i: int|
162 0 <= i < self.put_child(child).children.len() && #[trigger] self.put_child(
163 child,
164 ).children[i] is Some && PageTableOwner(
165 self.put_child(child).children[i].unwrap(),
166 ).view_rec(self.put_child(child).path().push_tail(i as usize)).contains(m);
167 if i == self.idx {
168 } else {
169 assert(self.children[i] == self.put_child(child).children[i]);
170 }
171 };
172 }
173}
174
175impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
176 proof fn as_subtree_inv(self)
178 requires
179 self.inv(),
180 self.all_some(),
181 ensures
182 self.as_subtree().inv(),
183 {
184 self.inv_children_unroll_all();
185 }
186
187 proof fn as_page_table_owner_pt_inv(self)
188 requires
189 self.inv(),
190 self.all_some(),
191 ensures
192 PageTableOwner(self.as_subtree()).pt_inv(),
193 {
194 self.as_subtree_inv();
195 let st = self.as_subtree();
196 let depth = (INC_LEVELS - st.level) as nat;
197 assert forall|i: int|
198 #![trigger st.children[i]]
199 0 <= i < NR_ENTRIES implies PageTableOwner::<C>::pt_edge_at(st, i) && PageTableOwner(
200 st.children[i].unwrap(),
201 ).pt_inv_at_depth((depth - 1) as nat) by {
202 self.inv_children_rel_unroll(i);
203 self.pt_inv_children_unroll(i);
204 };
205 }
206}
207
208impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
210 pub proof fn cur_subtree_eq_filtered_mappings_path(self)
213 requires
214 self.inv(),
215 self.in_locked_range(),
216 ensures
217 ({
218 let subtree_va = vaddr_of::<C>(self.cur_subtree().value.path) as int;
219 let size = page_size(self.level) as int;
220 PageTableOwner(self.cur_subtree())@.mappings == self@.mappings.filter(
221 |m: Mapping| subtree_va <= m.va_range.start < subtree_va + size,
222 )
223 }),
224 {
225 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
226
227 let cur_subtree = self.cur_subtree();
228 let cur_path = cur_subtree.value.path;
229 let subtree_va = vaddr_of::<C>(cur_path) as int;
230 let size = page_size(self.level) as int;
231
232 let subtree_mappings = PageTableOwner(cur_subtree)@.mappings;
233 let filtered = self@.mappings.filter(
234 |m: Mapping| subtree_va <= m.va_range.start < subtree_va + size,
235 );
236
237 self.cur_subtree_inv();
238
239 let cont = self.continuations[self.level - 1];
240 self.inv_continuation(self.level - 1);
241 cont.inv_children_rel_unroll(self.index() as int);
242 assert forall|m: Mapping| subtree_mappings.contains(m) implies filtered.contains(m) by {
246 assert(cont.children[self.index() as int] is Some);
248 assert(cont.children[self.index() as int].unwrap() == cur_subtree);
249
250 PageTableOwner(cur_subtree).view_rec_vaddr_range(cur_path, m);
254 };
255
256 assert forall|m: Mapping| filtered.contains(m) implies subtree_mappings.contains(m) by {
258 let i = choose|i: int|
260 self.level - 1 <= i < NR_LEVELS
261 && #[trigger] self.continuations[i].view_mappings().contains(m);
262 self.inv_continuation(i);
263
264 let cont_i = self.continuations[i];
265 let j = choose|j: int|
266 #![auto]
267 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
268 cont_i.children[j].unwrap(),
269 ).view_rec(cont_i.path().push_tail(j as usize)).contains(m);
270
271 cont_i.inv_children_unroll(j);
272 PageTableOwner(cont_i.children[j].unwrap()).view_rec_vaddr_range(
273 cont_i.path().push_tail(j as usize),
274 m,
275 );
276
277 if i == self.level - 1 {
278 if j as usize == self.index() {
279 assert(cont_i.children[j] == Some(cur_subtree));
282 assert(cont_i.path().push_tail(j as usize) == cur_path);
283 assert(subtree_mappings == PageTableOwner(cur_subtree).view_rec(cur_path));
284 assert(PageTableOwner(cur_subtree).view_rec(cur_path).contains(m));
285 assert(subtree_mappings.contains(m));
286 } else {
287 let sib_size = page_size((INC_LEVELS - cont.path().len() - 1) as PagingLevel);
289 sibling_paths_disjoint::<C>(cont.path(), self.index(), j as usize, sib_size);
290 lemma_vaddr_of_eq_int::<C>(cont.path().push_tail(self.index() as usize));
293 lemma_vaddr_of_eq_int::<C>(cont.path().push_tail(j as usize));
294 assert(false); }
296 } else {
297 if j as usize != cont_i.idx as usize {
298 self.subtree_va_in_ancestor_range(i);
300
301 let sib_size = page_size((INC_LEVELS - cont_i.path().len() - 1) as PagingLevel);
303 sibling_paths_disjoint::<C>(cont_i.path(), cont_i.idx, j as usize, sib_size);
304 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(cont_i.idx as usize));
305 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(j as usize));
306 lemma_vaddr_of_eq_int::<C>(cur_path);
307 assert(false); } else {
309 assert(cont_i.children[cont_i.idx as int] is None);
310 assert(false); }
312 }
313 };
314
315 assert(subtree_mappings == filtered);
316 }
317
318 pub proof fn cur_subtree_eq_filtered_mappings(self)
321 requires
322 self.inv(),
323 self.in_locked_range(),
324 ensures
325 ({
326 let start = nat_align_down(
327 self@.cur_va as nat,
328 page_size(self.level) as nat,
329 ) as Vaddr;
330 let size = page_size(self.level);
331 PageTableOwner(self.cur_subtree())@.mappings == self@.mappings.filter(
332 |m: Mapping| start <= m.va_range.start < start + size,
333 )
334 }),
335 {
336 self.cur_subtree_eq_filtered_mappings_path();
341 self.cur_va_in_cont_child_range(self.level - 1);
342 self.va.to_path_vaddr_concrete(self.level - 1);
343 let cur_path = self.cur_subtree().value.path;
344 let ps = page_size(self.level);
345 lemma_vaddr_of_eq_int::<C>(cur_path);
346 vstd_extra::arithmetic::lemma_nat_align_down_sound(self@.cur_va as nat, ps as nat);
349 let nad = nat_align_down(self@.cur_va as nat, ps as nat);
350 assert(nad as Vaddr == nad);
351 assert(nad as Vaddr == vaddr_of::<C>(cur_path));
352 }
353
354 proof fn cur_va_in_cont_child_range(self, lvl: int)
358 requires
359 self.inv(),
360 self.in_locked_range(),
361 self.level - 1 <= lvl < NR_LEVELS,
362 ensures
363 vaddr(self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as usize))
364 + self.va.leading_bits * 0x1_0000_0000_0000int <= self.cur_va(),
365 self.cur_va() < vaddr(
366 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as usize),
367 ) + self.va.leading_bits * 0x1_0000_0000_0000int + page_size((lvl + 1) as PagingLevel),
368 vaddr(self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as usize))
369 == vaddr(self.va.to_path(lvl)),
370 {
371 let cont = self.continuations[lvl];
372 let child_path = cont.path().push_tail(cont.idx as usize);
373 let va_path = self.va.to_path(lvl);
374
375 self.va.to_path_len(lvl);
376 cont.path().push_tail_property_len(cont.idx as usize);
377 assert forall|k: int| 0 <= k < child_path.len() implies child_path.index(k)
378 == va_path.index(k) by {
379 self.va.to_path_index(lvl, k);
380 if lvl == 3 {
381 cont.path().push_tail_property_index(cont.idx as usize);
382 } else if lvl == 2 {
383 cont.path().push_tail_property_index(cont.idx as usize);
384 self.continuations[3].path().push_tail_property_index(
385 self.continuations[3].idx as usize,
386 );
387 } else if lvl == 1 {
388 cont.path().push_tail_property_index(cont.idx as usize);
389 self.continuations[2].path().push_tail_property_index(
390 self.continuations[2].idx as usize,
391 );
392 self.continuations[3].path().push_tail_property_index(
393 self.continuations[3].idx as usize,
394 );
395 } else {
396 cont.path().push_tail_property_index(cont.idx as usize);
397 self.continuations[1].path().push_tail_property_index(
398 self.continuations[1].idx as usize,
399 );
400 self.continuations[2].path().push_tail_property_index(
401 self.continuations[2].idx as usize,
402 );
403 self.continuations[3].path().push_tail_property_index(
404 self.continuations[3].idx as usize,
405 );
406 }
407 };
408
409 self.va.to_path_inv(lvl);
410 cont.path().push_tail_preserves_inv(cont.idx as usize);
411 AbstractVaddr::rec_vaddr_eq_if_indices_eq(child_path, va_path, 0);
412 self.va.vaddr_range_from_path(lvl);
413 }
414
415 proof fn subtree_va_in_ancestor_range(self, lvl: int)
418 requires
419 self.inv(),
420 self.in_locked_range(),
421 self.level - 1 < lvl < NR_LEVELS,
422 ensures
423 ({
424 let subtree_va = vaddr(self.cur_subtree().value.path);
425 let idx_path_va = vaddr(
426 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as usize),
427 );
428 &&& idx_path_va <= subtree_va
429 &&& subtree_va + page_size(self.level) <= idx_path_va + page_size(
430 (lvl + 1) as PagingLevel,
431 )
432 }),
433 {
434 let cont = self.continuations[self.level - 1];
435 self.inv_continuation(self.level - 1);
436 cont.inv_children_rel_unroll(self.index() as int);
437 self.cur_va_in_cont_child_range(self.level - 1);
440 self.cur_va_in_cont_child_range(lvl);
441 self.va.to_path_vaddr_concrete(self.level - 1);
442 self.va.to_path_vaddr_concrete(lvl);
443
444 let x = self.cur_va() as nat;
445 let fine = page_size(self.level as PagingLevel) as nat;
446 let coarse = page_size((lvl + 1) as PagingLevel) as nat;
447 let shift = self.va.leading_bits * 0x1_0000_0000_0000int;
448
449 let subtree_va = vaddr(self.cur_subtree().value.path);
451 assert(subtree_va == vaddr(self.va.to_path(self.level - 1)));
452 assert(subtree_va + shift == nat_align_down(x, fine));
453
454 let idx_path_va = vaddr(
456 self.continuations[lvl].path().push_tail(self.continuations[lvl].idx as usize),
457 );
458 assert(idx_path_va == vaddr(self.va.to_path(lvl)));
459 assert(idx_path_va + shift == nat_align_down(x, coarse));
460
461 lemma_page_size_divides(self.level as PagingLevel, (lvl + 1) as PagingLevel);
462 lemma_nat_align_down_monotone(x, fine, coarse);
463 lemma_nat_align_down_within_block(x, fine, coarse);
464
465 vstd_extra::arithmetic::lemma_nat_align_down_sound(x, fine);
467 vstd_extra::arithmetic::lemma_nat_align_down_sound(x, coarse);
468 }
469
470 pub proof fn subtree_va_ranges_disjoint(self, j: int)
472 requires
473 self.inv(),
474 self.in_locked_range(),
475 0 <= j < NR_ENTRIES,
476 j != self.index(),
477 self.continuations[self.level - 1].children[j] is Some,
478 ensures
479 vaddr(self.continuations[self.level - 1].path().push_tail(j as usize))
480 + self.va.leading_bits * 0x1_0000_0000_0000int + page_size(
481 self.level as PagingLevel,
482 ) <= self.cur_va() || self.cur_va() < vaddr(
483 self.continuations[self.level - 1].path().push_tail(j as usize),
484 ) + self.va.leading_bits * 0x1_0000_0000_0000int,
485 {
486 let cont = self.continuations[self.level - 1];
487 let idx = self.index();
488
489 self.cur_va_in_cont_child_range(self.level - 1);
492
493 let size = page_size((INC_LEVELS - cont.path().len() - 1) as PagingLevel);
495 sibling_paths_disjoint::<C>(cont.path(), idx, j as usize, size);
496 }
497
498 pub proof fn higher_level_children_disjoint(self, i: int, j: int)
501 requires
502 self.inv(),
503 self.in_locked_range(),
504 self.level - 1 < i < NR_LEVELS,
505 0 <= j < NR_ENTRIES,
506 j != self.continuations[i].idx,
507 self.continuations[i].children[j] is Some,
508 ensures
509 vaddr(self.continuations[i].path().push_tail(j as usize)) + self.va.leading_bits
510 * 0x1_0000_0000_0000int + page_size((i + 1) as PagingLevel) <= self.cur_va()
511 || self.cur_va() < vaddr(self.continuations[i].path().push_tail(j as usize))
512 + self.va.leading_bits * 0x1_0000_0000_0000int,
513 {
514 let cont = self.continuations[i];
515
516 self.cur_va_in_cont_child_range(i);
519
520 let size = page_size((INC_LEVELS - cont.path().len() - 1) as PagingLevel);
522 sibling_paths_disjoint::<C>(cont.path(), cont.idx, j as usize, size);
523 }
524
525 pub proof fn mapping_covering_cur_va_from_cur_subtree(self, m: Mapping)
529 requires
530 self.inv(),
531 self.in_locked_range(),
532 self.view_mappings().contains(m),
533 m.va_range.start <= self.cur_va() < m.va_range.end,
534 ensures
535 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value.path).contains(m),
536 {
537 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
538
539 let cur_va = self.cur_va();
540
541 let i = choose|i: int|
543 self.level - 1 <= i < NR_LEVELS
544 && #[trigger] self.continuations[i].view_mappings().contains(m);
545 self.inv_continuation(i);
546
547 let cont_i = self.continuations[i];
548 let j = choose|j: int|
549 #![auto]
550 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
551 cont_i.children[j].unwrap(),
552 ).view_rec(cont_i.path().push_tail(j as usize)).contains(m);
553
554 cont_i.inv_children_unroll(j);
555 let child_j = cont_i.children[j].unwrap();
556 let path_j = cont_i.path().push_tail(j as usize);
557 PageTableOwner(child_j).view_rec_vaddr_range(path_j, m);
558 lemma_vaddr_of_eq_int::<C>(path_j);
561
562 if i == self.level - 1 {
563 if j as usize != self.index() {
564 self.subtree_va_ranges_disjoint(j);
565 }
566 } else {
567 if j as usize != cont_i.idx as usize {
568 self.higher_level_children_disjoint(i, j);
569 } else {
570 assert(cont_i.children[cont_i.idx as int] is None);
571 assert(false);
572 }
573 }
574 }
575
576 #[verifier::rlimit(60)]
579 pub proof fn view_mappings_replace_lowest(
580 old_self: Self,
581 new_self: Self,
582 old_cont: CursorContinuation<'rcu, C>,
583 new_cont: CursorContinuation<'rcu, C>,
584 )
585 requires
586 old_self.inv(),
587 old_self.in_locked_range(),
588 new_self.inv(),
589 old_self.level == new_self.level,
590 old_self.continuations[old_self.level - 1] == old_cont,
591 new_self.continuations[new_self.level - 1] == new_cont,
592 forall|i: int|
593 old_self.level <= i < NR_LEVELS ==> old_self.continuations[i]
594 == new_self.continuations[i],
595 ensures
596 new_self.view_mappings() == (old_self.view_mappings() - old_cont.view_mappings()).union(
597 new_cont.view_mappings(),
598 ),
599 {
600 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
601
602 let level = old_self.level;
603
604 assert forall|m: Mapping| new_self.view_mappings().contains(m) implies ((
605 old_self.view_mappings().contains(m) && !old_cont.view_mappings().contains(m))
606 || new_cont.view_mappings().contains(m)) by {
607 let i = choose|i: int|
608 level - 1 <= i < NR_LEVELS
609 && #[trigger] new_self.continuations[i].view_mappings().contains(m);
610 if i == level - 1 {
611 assert(new_cont.view_mappings().contains(m));
612 } else {
613 assert(old_self.continuations[i] == new_self.continuations[i]);
614 assert(old_self.continuations[i].view_mappings().contains(m));
615
616 if old_cont.view_mappings().contains(m) {
617 old_self.inv_continuation(i);
618 old_self.inv_continuation(level - 1);
619 let cont_i = old_self.continuations[i];
620 let j = choose|j: int|
621 #![auto]
622 0 <= j < NR_ENTRIES && cont_i.children[j] is Some && PageTableOwner(
623 cont_i.children[j].unwrap(),
624 ).view_rec(cont_i.path().push_tail(j as usize)).contains(m);
625 cont_i.inv_children_unroll(j);
626 PageTableOwner(cont_i.children[j].unwrap()).view_rec_vaddr_range(
627 cont_i.path().push_tail(j as usize),
628 m,
629 );
630
631 let k = choose|k: int|
632 #![auto]
633 0 <= k < NR_ENTRIES && old_cont.children[k] is Some && PageTableOwner(
634 old_cont.children[k].unwrap(),
635 ).view_rec(old_cont.path().push_tail(k as usize)).contains(m);
636 old_cont.inv_children_unroll(k);
637 PageTableOwner(old_cont.children[k].unwrap()).view_rec_vaddr_range(
638 old_cont.path().push_tail(k as usize),
639 m,
640 );
641
642 if j as usize != cont_i.idx as usize {
643 old_self.cur_va_in_cont_child_range(level as int);
644 old_self.va.to_path_vaddr_concrete(level as int);
645 old_self.cur_va_in_cont_child_range(i);
646 old_self.va.to_path_vaddr_concrete(i);
647
648 let x = old_self.cur_va() as nat;
649 let ps_node = page_size((level + 1) as PagingLevel) as nat;
650 let ps_anc = page_size((i + 1) as PagingLevel) as nat;
651
652 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
653 (level + 1) as PagingLevel);
654 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
655 (i + 1) as PagingLevel);
656 lemma_page_size_divides((level + 1) as PagingLevel, (i + 1) as PagingLevel);
657
658 lemma_nat_align_down_monotone(x, ps_node, ps_anc);
659 lemma_nat_align_down_within_block(x, ps_node, ps_anc);
660 vstd_extra::arithmetic::lemma_nat_align_down_sound(x, ps_node);
661 vstd_extra::arithmetic::lemma_nat_align_down_sound(x, ps_anc);
662
663 let sib_size = page_size(
664 (INC_LEVELS - cont_i.path().len() - 1) as PagingLevel,
665 );
666 sibling_paths_disjoint::<C>(
667 cont_i.path(),
668 cont_i.idx,
669 j as usize,
670 sib_size,
671 );
672 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(cont_i.idx as usize));
674 lemma_vaddr_of_eq_int::<C>(cont_i.path().push_tail(j as usize));
675
676 old_cont.as_subtree_inv();
677 old_cont.as_page_table_owner_preserves_view_mappings();
678 PageTableOwner(old_cont.as_subtree()).view_rec_vaddr_range(
679 old_cont.path(),
680 m,
681 );
682 } else {
683 assert(cont_i.children[cont_i.idx as int] is None);
684 }
685 }
686 }
687 };
688
689 assert forall|m: Mapping|
690 ((old_self.view_mappings().contains(m) && !old_cont.view_mappings().contains(m))
691 || new_cont.view_mappings().contains(m)) implies new_self.view_mappings().contains(
692 m,
693 ) by {
694 if new_cont.view_mappings().contains(m) {
695 assert(new_self.continuations[level - 1].view_mappings().contains(m));
696 } else {
697 let i = choose|i: int|
698 level - 1 <= i < NR_LEVELS
699 && #[trigger] old_self.continuations[i].view_mappings().contains(m);
700 if i == level - 1 {
701 assert(false);
703 } else {
704 assert(new_self.continuations[i] == old_self.continuations[i]);
705 assert(new_self.continuations[i].view_mappings().contains(m));
706 }
707 }
708 };
709
710 assert(new_self.view_mappings() == (old_self.view_mappings()
711 - old_cont.view_mappings()).union(new_cont.view_mappings()));
712 }
713
714 #[verifier::rlimit(120)]
715 pub proof fn as_page_table_owner_preserves_view_mappings(self)
716 requires
717 self.inv(),
718 ensures
719 self.as_page_table_owner().view_rec(self.continuations[3].path())
720 == self.view_mappings(),
721 self.as_page_table_owner().0.inv(),
722 self.as_page_table_owner().0.level == self.continuations[3].tree_level,
723 self.as_page_table_owner().pt_inv(),
724 {
725 broadcast use CursorOwner::group_lemmas;
726
727 if self.level == 4 {
728 self.continuations[3].as_page_table_owner_preserves_view_mappings();
729 self.inv_continuation(3);
730 assert(self.view_mappings() == self.continuations[3].view_mappings());
731 } else if self.level == 3 {
732 let c2 = self.continuations[2];
733 let c3 = self.continuations[3];
734
735 c2.as_page_table_owner_preserves_view_mappings();
736 c2.as_subtree_inv();
737 c3.view_mappings_put_child(c2.as_subtree());
738 c3.as_subtree_restore(c2);
739
740 let l4 = c3.restore(c2).0;
741 c2.as_page_table_owner_pt_inv();
742
743 c2.inv_children_unroll_all();
744 c3.inv_children_unroll_all();
745 l4.as_page_table_owner_preserves_view_mappings();
746
747 assert(self.view_mappings() == self.continuations[2].view_mappings().union(
748 self.continuations[3].view_mappings(),
749 )) by {
750 assert forall|m: Mapping| #[trigger]
751 self.view_mappings().contains(
752 m,
753 ) implies self.continuations[2].view_mappings().contains(m)
754 || self.continuations[3].view_mappings().contains(m) by {
755 let i = choose|i: int|
756 2 <= i < NR_LEVELS
757 && #[trigger] self.continuations[i].view_mappings().contains(m);
758 };
759 };
760 } else if self.level == 2 {
761 let c1 = self.continuations[1];
762 let c2 = self.continuations[2];
763 let c3 = self.continuations[3];
764
765 c1.as_page_table_owner_preserves_view_mappings();
766 c1.as_subtree_inv();
767 c2.view_mappings_put_child(c1.as_subtree());
768 c2.as_subtree_restore(c1);
769
770 let l3 = c2.restore(c1).0;
771 c1.as_page_table_owner_pt_inv();
772
773 c1.inv_children_unroll_all();
774 c2.inv_children_unroll_all();
775 l3.as_page_table_owner_preserves_view_mappings();
776 l3.as_subtree_inv();
777 c3.as_subtree_restore(l3);
778 c3.view_mappings_put_child(l3.as_subtree());
779
780 let l4 = c3.restore(l3).0;
781 l3.as_page_table_owner_pt_inv();
782
783 c3.inv_children_unroll_all();
784 l4.as_page_table_owner_preserves_view_mappings();
785
786 assert(self.view_mappings() == c1.view_mappings().union(c2.view_mappings()).union(
787 c3.view_mappings(),
788 )) by {
789 assert forall|m: Mapping| self.view_mappings().contains(m) implies (
790 c1.view_mappings().contains(m) || c2.view_mappings().contains(m)
791 || c3.view_mappings().contains(m)) by {
792 let i = choose|i: int|
793 1 <= i < NR_LEVELS
794 && #[trigger] self.continuations[i].view_mappings().contains(m);
795 };
796 };
797 } else {
798 let c0 = self.continuations[0];
800 let c1 = self.continuations[1];
801 let c2 = self.continuations[2];
802 let c3 = self.continuations[3];
803
804 c0.as_page_table_owner_preserves_view_mappings();
805 c0.as_subtree_inv();
806 c1.view_mappings_put_child(c0.as_subtree());
807 c1.as_subtree_restore(c0);
808 let l2 = c1.restore(c0).0;
809 c0.as_page_table_owner_pt_inv();
810
811 c0.inv_children_unroll_all();
812 c1.inv_children_unroll_all();
813 l2.as_page_table_owner_preserves_view_mappings();
814 l2.as_subtree_inv();
815 c2.view_mappings_put_child(l2.as_subtree());
816 c2.as_subtree_restore(l2);
817 let l3 = c2.restore(l2).0;
818 l2.as_page_table_owner_pt_inv();
819
820 c2.inv_children_unroll_all();
821 l3.as_page_table_owner_preserves_view_mappings();
822 l3.as_subtree_inv();
823 c3.view_mappings_put_child(l3.as_subtree());
824 c3.as_subtree_restore(l3);
825 let l4 = c3.restore(l3).0;
826 l3.as_page_table_owner_pt_inv();
827
828 c3.inv_children_unroll_all();
829 l4.as_page_table_owner_preserves_view_mappings();
830
831 assert(self.view_mappings() == c0.view_mappings().union(c1.view_mappings()).union(
832 c2.view_mappings(),
833 ).union(c3.view_mappings())) by {
834 assert forall|m: Mapping| self.view_mappings().contains(m) implies (
835 c0.view_mappings().contains(m) || c1.view_mappings().contains(m)
836 || c2.view_mappings().contains(m) || c3.view_mappings().contains(m)) by {
837 let i = choose|i: int|
838 0 <= i < NR_LEVELS
839 && #[trigger] self.continuations[i].view_mappings().contains(m);
840 };
841 };
842 }
843 }
844
845 pub proof fn view_mapping_inv(self)
851 requires
852 self.inv(),
853 ensures
854 forall|m: Mapping| self.view_mappings().contains(m) ==> #[trigger] m.inv(),
855 {
856 self.as_page_table_owner_preserves_view_mappings();
857 let pto = self.as_page_table_owner();
858 let root_path = self.continuations[3].path();
859 self.inv_continuation(NR_LEVELS as int - 1);
860 pto.view_rec_mapping_inv(root_path);
861 }
862
863 pub proof fn view_mapping_page_size_valid(self)
870 requires
871 self.inv(),
872 ensures
873 forall|m: Mapping| #[trigger]
874 self.view_mappings().contains(m)
875 ==> set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size),
876 {
877 self.as_page_table_owner_preserves_view_mappings();
878 let pto = self.as_page_table_owner();
879 let root_path = self.continuations[3].path();
880 self.inv_continuation(NR_LEVELS - 1);
881 pto.view_rec_mapping_page_size(root_path);
885 }
886
887 pub proof fn as_page_table_owner_view_non_overlapping(self)
894 requires
895 self.inv(),
896 ensures
897 self@.non_overlapping(),
898 {
899 self.as_page_table_owner_preserves_view_mappings();
900 let pto = self.as_page_table_owner();
901 let root_path = self.continuations[3].path();
902
903 assert(root_path.len() == self.continuations[3].tree_level);
904 assert(self.continuations[3].tree_level == 0) by {
905 self.inv_continuation(NR_LEVELS - 1);
906 };
909
910 assert forall|m: Mapping, n: Mapping| #[trigger]
911 self@.mappings.contains(m) && #[trigger] self@.mappings.contains(n) && m
912 != n implies m.va_range.end <= n.va_range.start || n.va_range.end
913 <= m.va_range.start by {
914 assert(self@.mappings == self.view_mappings());
915 assert(pto.view_rec(root_path).contains(m));
916 assert(pto.view_rec(root_path).contains(n));
917 pto.view_rec_disjoint_vaddrs(root_path, m, n);
918 };
919 }
920}
921
922}