1use vstd::{arithmetic::div_mod::lemma_mod_add_multiples_vanish, prelude::*};
2use vstd_extra::{
3 arithmetic::{lemma_nat_align_down_sound, lemma_nat_align_down_within_block, nat_align_down},
4 ghost_tree::*,
5 ownership::*,
6};
7
8use crate::specs::{
9 arch::{NR_ENTRIES, NR_LEVELS},
10 mm::{
11 frame::mapping::meta_to_index,
12 page_table::{
13 cursor::{
14 owners::*,
15 page_size_lemmas::{lemma_page_size_ge_base, lemma_page_size_monotone},
16 },
17 node::EntryOwner,
18 owners::*,
19 vaddr_range_proofs::lemma_page_table_managed_index_bounds,
20 *,
21 },
22 *,
23 },
24};
25
26use crate::arch::mm::PagingConsts;
27use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr, page_size, page_table::*};
28use core::ops::Range;
29
30verus! {
31
32broadcast use group_ghost_tree_lemmas;
33
34pub proof fn subtree_unlock_upgrade<'rcu, C: PageTableConfig>(
40 subtree: OwnerSubtree<C>,
41 path: TreePath<NR_ENTRIES>,
42 guards: Guards,
43 regions: MetaRegionOwners,
44 excepted_addr: usize,
45 excepted_path: TreePath<NR_ENTRIES>,
46)
47 requires
48 subtree.inv(),
49 PageTableOwner::<C>(subtree).pt_inv(),
50 subtree.subtree_satisfies(path, PageTableOwner::<C>::metaregion_sound_pred(regions)),
51 subtree.subtree_satisfies(
52 path,
53 CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr),
54 ),
55 regions.slot_owners[meta_to_index(excepted_addr)].paths_in_pt == set![excepted_path],
56 path == subtree.value().path,
58 path.inv(),
59 path != excepted_path,
61 excepted_path.len() <= path.len() || (exists|k: int|
65 0 <= k < path.len() && #[trigger] excepted_path[k] != path[k]),
66 ensures
67 subtree.subtree_satisfies(path, CursorOwner::<'rcu, C>::node_unlocked(guards)),
68 decreases INC_LEVELS - subtree.level(),
69{
70 reveal(PageTableOwner::pt_inv_at_depth);
71 let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
72 let g = CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr);
73 let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
74
75 if subtree.value().is_node() {
76 if subtree.value().node().slot_vaddr() == excepted_addr {
77 let idx = meta_to_index(excepted_addr);
80
81 assert(set![subtree.value().path].contains(excepted_path));
82 assert(false);
83 }
84 }
85 if subtree.level() < INC_LEVELS - 1 && subtree.value().is_node() {
86 assert forall|i: int|
87 #![trigger subtree.children()[i]]
88 0 <= i < subtree.children().len() && subtree.has_child(i) implies subtree.child(
89 i,
90 ).subtree_satisfies(path.push_tail(i), h) by {
91 let child = subtree.child(i);
92
93 let child_path = path.push_tail(i);
94
95 subtree_unlock_upgrade(
96 child,
97 child_path,
98 guards,
99 regions,
100 excepted_addr,
101 excepted_path,
102 );
103 };
104 } else if subtree.level() < INC_LEVELS - 1 && !subtree.value().is_node() {
105 }
108}
109
110impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
111 pub open spec fn max_steps_subtree(level: usize) -> nat
114 decreases level,
115 {
116 if level <= 1 {
117 NR_ENTRIES as nat
118 } else {
119 (NR_ENTRIES as nat) * (Self::max_steps_subtree((level - 1) as usize) + 1)
120 }
121 }
122
123 pub open spec fn max_steps_partial(self, level: usize) -> nat
135 decreases NR_LEVELS + 1 - level,
136 when level <= NR_LEVELS + 1
137 {
138 if level > NR_LEVELS {
139 0
140 } else {
141 let cont = self.continuations[level - 1];
142 let count: nat = (NR_ENTRIES - cont.idx - 1) as nat;
143 let steps = Self::max_steps_subtree(level) * count;
144 let remaining_steps = self.max_steps_partial((level + 1) as usize);
145 steps + remaining_steps
146 }
147 }
148
149 pub open spec fn max_steps(self) -> nat {
150 if self.at_or_past_barrier_end() {
151 0
152 } else {
153 (self.max_steps_partial(self.level as usize) + Self::max_steps_subtree(
154 self.level as usize,
155 )) as nat
156 }
157 }
158
159 pub proof fn lemma_max_steps_partial_eq(self, other: Self, start: usize)
161 requires
162 1 <= start <= NR_LEVELS + 1,
163 forall|k: int|
164 start - 1 <= k < NR_LEVELS ==> #[trigger] self.continuations[k].idx
165 == other.continuations[k].idx,
166 ensures
167 self.max_steps_partial(start) == other.max_steps_partial(start),
168 decreases NR_LEVELS + 1 - start,
169 {
170 if start <= NR_LEVELS {
171 self.lemma_max_steps_partial_eq(other, (start + 1) as usize);
172 }
173 }
174
175 pub open spec fn push_level_owner(self, guard: PageTableGuard<'rcu, C>) -> Self {
176 let cont = self.continuations[self.level - 1];
177 let (child, cont) = cont.make_cont(
178 pte_index_spec::<C>(self.cur_va(), (self.level - 1) as PagingLevel),
179 guard,
180 );
181 let new_continuations = self.continuations.insert(self.level - 1, cont).insert(
182 self.level - 2,
183 child,
184 );
185
186 let new_level = (self.level - 1) as u8;
187 Self { continuations: new_continuations, level: new_level, popped_too_high: false, ..self }
188 }
189
190 pub proof fn push_level_owner_decreases_steps(self, guard: PageTableGuard<'rcu, C>)
191 requires
192 self.inv(),
193 self.in_barrier_va(),
194 self.level > 1,
195 ensures
196 self.push_level_owner(guard).max_steps() < self.max_steps(),
197 {
198 C::axiom_current_paging_consts_hardcoded();
199 lemma_pte_index_bound::<C>(self.cur_va(), (self.level - 1) as PagingLevel);
200 let new_self = self.push_level_owner(guard);
201 let l = self.level as usize;
202 let lm1 = (self.level - 1) as usize;
203 new_self.lemma_max_steps_partial_eq(self, l);
205 let new_child = new_self.continuations[lm1 - 1];
206
207 vstd::arithmetic::mul::lemma_mul_inequality(
210 (NR_ENTRIES - new_child.idx) as int,
211 NR_ENTRIES as int,
212 Self::max_steps_subtree(lm1) as int,
213 );
214 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
215 Self::max_steps_subtree(lm1) as int,
216 NR_ENTRIES - new_child.idx - 1,
217 1,
218 );
219 vstd::arithmetic::mul::lemma_mul_is_commutative(
220 (NR_ENTRIES - new_child.idx) as int,
221 Self::max_steps_subtree(lm1) as int,
222 );
223
224 }
225
226 pub proof fn push_level_owner_preserves_mappings(self, guard: PageTableGuard<'rcu, C>)
227 requires
228 self.inv(),
229 self.level > 1,
230 self.cur_entry_owner().is_node(),
231 ensures
232 self.push_level_owner(guard)@.mappings == self@.mappings,
233 {
234 C::axiom_current_paging_consts_hardcoded();
235 broadcast use {
236 CursorContinuation::group_lemmas,
237 CursorOwner::group_lemmas,
238 PageTableOwner::group_lemmas,
239 };
240
241 let new_owner = self.push_level_owner(guard);
242 let old_cont = self.continuations[self.level - 1];
243 let (_, modified_cont) = old_cont.make_cont(
244 pte_index_spec::<C>(self.cur_va(), (self.level - 1) as PagingLevel),
245 guard,
246 );
247
248 old_cont.view_mappings_take_child();
249
250 let taken = old_cont.take_child().1;
251
252 assert(modified_cont.children == taken.children) by {};
253
254 assert forall|m: Mapping|
255 self.view_mappings().contains(m) implies new_owner.view_mappings().contains(m) by {
256 let i = choose|i: int|
257 self.level - 1 <= i < NR_LEVELS && (
258 #[trigger] self.continuations[i]).view_mappings().contains(m);
259 if i == self.level - 1 {
260 if old_cont.view_mappings_take_child_spec().contains(m) {
261 assert(new_owner.continuations[self.level - 2].view_mappings().contains(m));
262 } else {
263 assert(new_owner.continuations[self.level - 1].view_mappings().contains(m));
264 }
265 } else {
266 assert(new_owner.continuations[i] == self.continuations[i]);
267 }
268 };
269
270 }
271
272 pub proof fn push_level_owner_preserves_inv(self, guard: PageTableGuard<'rcu, C>)
273 requires
274 self.inv(),
275 self.level > 1,
276 !self.popped_too_high,
277 self.level <= self.guard_level,
278 self.in_barrier_va(),
279 self.cur_entry_owner().is_node(),
281 self.cur_entry_owner().node().relate_guard(guard),
283 forall|i: int|
285 #![trigger self.continuations[i]]
286 self.level - 1 <= i < NR_LEVELS
287 ==> self.continuations[i].guard.inner.inner@.slot_vaddr()
288 != guard.inner.inner@.slot_vaddr(),
289 ensures
290 self.push_level_owner(guard).inv(),
291 {
292 C::axiom_current_paging_consts_hardcoded();
293 lemma_pte_index_bound::<C>(self.cur_va(), (self.level - 1) as PagingLevel);
294 let new_owner = self.push_level_owner(guard);
295
296 let old_cont = self.continuations[self.level - 1];
297
298 let child_node = old_cont.children[old_cont.idx as int].unwrap();
299 let (child, _) = old_cont.make_cont(
300 pte_index_spec::<C>(self.cur_va(), (self.level - 1) as PagingLevel),
301 guard,
302 );
303
304 assert(child.inv_children_rel()) by {
305 assert forall|j: int|
306 0 <= j < NR_ENTRIES && #[trigger] child.children[j] is Some implies {
307 &&& child.children[j].unwrap().value().parent_level == child.level()
308 &&& child.children[j].unwrap().level() == child.tree_level + 1
309 &&& child.children[j].unwrap().value().path.len()
310 == child.entry_own.node().tree_level + 1
311 &&& child.children[j].unwrap().value().match_pte(
312 child.entry_own.node().children_perm.value()[j],
313 child.entry_own.node().level(),
314 )
315 &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
316 child.entry_own,
317 j,
318 Some(child.children[j].unwrap().value()),
319 )
320 &&& child.children[j].unwrap().value().path == child.path().push_tail(j)
321 } by {
322 let gc = child.children[j].unwrap();
323 PageTableOwner(child_node).pt_inv_unroll(j);
324
325 };
326 };
327 assert(child.pt_inv_children()) by {
328 assert forall|j: int|
329 0 <= j < child.children.len()
330 && #[trigger] child.children[j] is Some implies PageTableOwner(
331 child.children[j].unwrap(),
332 ).pt_inv() by {
333 PageTableOwner(child_node).pt_inv_unroll(j);
334
335 };
336 };
337
338 assert(new_owner.continuations[new_owner.level - 1].all_some()) by {
339 assert forall|j: int| 0 <= j < NR_ENTRIES implies child.children[j] is Some by {
340 PageTableOwner(child_node).pt_inv_unroll(j);
341
342 };
343 };
344
345 }
346
347 #[verifier::spinoff_prover]
348 #[verifier::rlimit(20)]
349 pub proof fn push_level_owner_preserves_invs(
350 self,
351 guard: PageTableGuard<'rcu, C>,
352 regions: MetaRegionOwners,
353 guards: Guards,
354 )
355 requires
356 self.inv(),
357 self.level > 1,
358 !self.popped_too_high,
359 self.level <= self.guard_level,
360 self.in_barrier_va(),
361 self.only_current_locked(guards),
362 self.nodes_locked(guards),
363 self.metaregion_sound(regions),
364 self.cur_entry_owner().is_node(),
366 self.cur_entry_owner().node().relate_guard(guard),
368 guards.lock_held(guard.inner.inner@.slot_vaddr()),
370 ensures
371 self.push_level_owner(guard).inv(),
372 self.push_level_owner(guard).children_not_locked(guards),
373 self.push_level_owner(guard).nodes_locked(guards),
374 self.push_level_owner(guard).metaregion_sound(regions),
375 {
376 hide(CursorContinuation::view_mappings);
377 hide(CursorOwner::view_mappings);
378 C::axiom_current_paging_consts_hardcoded();
379 reveal(CursorContinuation::map_children);
380 let new_owner = self.push_level_owner(guard);
381 let old_cont = self.continuations[self.level - 1];
382
383 let (child_cont, modified_cont) = old_cont.make_cont(
384 pte_index_spec::<C>(self.cur_va(), (self.level - 1) as PagingLevel),
385 guard,
386 );
387
388 let cur_entry = self.cur_entry_owner();
389 let cur_entry_addr = cur_entry.node().slot_vaddr();
390 let cur_entry_path = old_cont.path().push_tail(old_cont.idx as int);
391
392 assert forall|i: int|
393 #![trigger self.continuations[i]]
394 self.level - 1 <= i
395 < NR_LEVELS implies self.continuations[i].guard.inner.inner@.slot_vaddr()
396 != guard.inner.inner@.slot_vaddr() by {
397 reveal(CursorOwner::path_metaregion_sound);
398 let cont_i = self.continuations[i];
399
400 if cont_i.guard.inner.inner@.slot_vaddr() == guard.inner.inner@.slot_vaddr() {
401 assert(set![cont_i.path()].contains(cur_entry_path));
402
403 assert(false);
404 }
405 };
406
407 self.push_level_owner_preserves_inv(guard);
408
409 let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
410 let g_except = CursorOwner::<'rcu, C>::node_unlocked_except(guards, cur_entry_addr);
411 let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
412
413 assert forall|i: int|
414 #![trigger new_owner.continuations[i]]
415 new_owner.level - 1 <= i < NR_LEVELS implies new_owner.continuations[i].map_children(
416 h,
417 ) by {
418 if i == self.level - 2 {
419 assert forall|j: int|
420 #![trigger child_cont.children[j]]
421 0 <= j < child_cont.children.len()
422 && child_cont.children[j] is Some implies child_cont.children[j].unwrap().subtree_satisfies(
423 child_cont.path().push_tail(j), h) by {
424 let gc = child_cont.children[j].unwrap();
425 let gc_path = child_cont.path().push_tail(j);
426
427 let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
428 child_subtree.lemma_subtree_satisfies_unroll_once(cur_entry_path, f, j);
429 child_subtree.lemma_subtree_satisfies_unroll_once(cur_entry_path, g_except, j);
430
431 subtree_unlock_upgrade(
432 gc,
433 gc_path,
434 guards,
435 regions,
436 cur_entry_addr,
437 cur_entry_path,
438 );
439 };
440 } else if i == self.level - 1 {
441 assert forall|j: int|
442 #![trigger modified_cont.children[j]]
443 0 <= j < modified_cont.children.len()
444 && modified_cont.children[j] is Some implies modified_cont.children[j].unwrap().subtree_satisfies(
445 modified_cont.path().push_tail(j), h) by {
446 let sibling = old_cont.children[j].unwrap();
447 let sibling_path = old_cont.path().push_tail(j);
448
449 subtree_unlock_upgrade(
450 sibling,
451 sibling_path,
452 guards,
453 regions,
454 cur_entry_addr,
455 cur_entry_path,
456 );
457 };
458 } else {
459 let cont_i = self.continuations[i];
460
461 assert(cur_entry_path[cont_i.tree_level as int] == cont_i.idx);
462
463 assert forall|j: int|
464 #![trigger cont_i.children[j]]
465 0 <= j < cont_i.children.len()
466 && cont_i.children[j] is Some implies cont_i.children[j].unwrap().subtree_satisfies(
467 cont_i.path().push_tail(j), h) by {
468 let child_sub = cont_i.children[j].unwrap();
469 let child_path = cont_i.path().push_tail(j);
470
471 subtree_unlock_upgrade(
472 child_sub,
473 child_path,
474 guards,
475 regions,
476 cur_entry_addr,
477 cur_entry_path,
478 );
479 };
480 }
481 };
482
483 let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
484 let child_subtree = child_cont.as_subtree();
485
486 assert(child_cont.map_children(f)) by {
487 assert forall|j: int|
488 0 <= j < child_cont.children.len()
489 && #[trigger] child_cont.children[j] is Some implies child_cont.children[j].unwrap().subtree_satisfies(
490 child_cont.path().push_tail(j), f) by {
491 child_subtree.lemma_subtree_satisfies_unroll_once(child_cont.path(), f, j);
492
493 };
494 };
495 reveal(CursorOwner::path_metaregion_sound);
496 }
497
498 pub proof fn tracked_push_level_owner(tracked &mut self, guard: PageTableGuard<'rcu, C>)
499 requires
500 old(self).inv(),
501 old(self).level > 1,
502 ensures
503 *final(self) == old(self).push_level_owner(guard),
504 {
505 C::axiom_current_paging_consts_hardcoded();
506 lemma_pte_index_bound::<C>(self.cur_va(), (self.level - 1) as PagingLevel);
507
508 let ghost self0 = *self;
509 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
510 let tracked child = cont.tracked_make_cont(
511 pte_index_spec::<C>(self.cur_va(), (self.level - 1) as PagingLevel),
512 guard,
513 );
514
515 self.continuations.tracked_insert(self.level - 1, cont);
516 self.continuations.tracked_insert(self.level - 2, child);
517
518 assert(self.continuations == self0.continuations.insert(self.level - 1, cont).insert(
519 self.level - 2,
520 child,
521 ));
522
523 self.popped_too_high = false;
524
525 self.level = (self.level - 1) as u8;
526 }
527
528 pub open spec fn pop_level_owner(self) -> (Self, PageTableGuard<'rcu, C>) {
529 let child = self.continuations[self.level - 1];
530 let cont = self.continuations[self.level as int];
531 let (new_cont, guard) = cont.restore(child);
532 let new_continuations = self.continuations.insert(self.level as int, new_cont).remove(
533 self.level - 1,
534 );
535 let new_level = (self.level + 1) as u8;
536 let popped_too_high = if new_level > self.guard_level {
537 true
538 } else {
539 false
540 };
541 (
542 Self {
543 continuations: new_continuations,
544 level: new_level,
545 popped_too_high: popped_too_high,
546 ..self
547 },
548 guard,
549 )
550 }
551
552 #[verifier::rlimit(200)]
553 pub proof fn pop_level_owner_preserves_invs(self, guards: Guards, regions: MetaRegionOwners)
554 requires
555 self.inv(),
556 self.level < NR_LEVELS,
557 self.children_not_locked(guards),
558 self.nodes_locked(guards),
559 self.metaregion_sound(regions),
560 ensures
561 self.pop_level_owner().0.inv(),
562 self.pop_level_owner().0.only_current_locked(guards),
563 self.pop_level_owner().0.nodes_locked(guards),
564 self.pop_level_owner().0.metaregion_sound(regions),
565 {
566 hide(CursorContinuation::view_mappings);
567 hide(CursorOwner::view_mappings);
568 reveal(PageTableOwner::pt_inv_at_depth);
569 let child = self.continuations[self.level - 1];
570 let child_addr = child.entry_own.node().slot_vaddr();
571
572 self.lemma_map_children_implies(
573 CursorOwner::<'rcu, C>::node_unlocked(guards),
574 CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
575 );
576 reveal(CursorContinuation::map_children);
577 reveal(CursorOwner::path_metaregion_sound);
578 }
579
580 pub open spec fn move_forward_owner_spec(self) -> Self
581 decreases NR_LEVELS - self.level,
582 when self.level <= NR_LEVELS
583 {
584 if self.index() + 1 == NR_ENTRIES && self.level == self.guard_level {
585 Self {
586 va: (nat_align_down(self.va as nat, page_size::<C>(self.level) as nat)
587 + page_size::<C>(self.level)) as Vaddr,
588 popped_too_high: false,
589 ..self
590 }
591 } else if self.index() + 1 < NR_ENTRIES {
592 self.inc_index().zero_below_level()
595 } else if self.level < NR_LEVELS {
596 self.pop_level_owner().0.move_forward_owner_spec()
597 } else {
598 Self {
601 va: (self.va + page_size::<C>(C::NR_LEVELS())) as Vaddr,
602 popped_too_high: false,
603 ..self
604 }
605 }
606 }
607
608 pub proof fn lemma_move_forward_increases_va(self)
609 requires
610 self.inv(),
611 self.level <= NR_LEVELS,
612 self.in_barrier_va(),
613 !self.popped_too_high,
614 ensures
615 self.move_forward_owner_spec().va > self.va,
616 {
617 self.lemma_move_forward_va_is_align_up();
618 self.lemma_va_plus_page_size_no_overflow(self.level);
619 lemma_page_size_ge_base::<PagingConsts>(self.level);
620 lemma_nat_align_down_sound(self.va as nat, page_size::<PagingConsts>(self.level) as nat);
621 }
622
623 pub proof fn lemma_move_forward_not_popped_too_high(self)
624 requires
625 self.inv(),
626 self.level <= NR_LEVELS,
627 self.in_barrier_va(),
628 ensures
629 !self.move_forward_owner_spec().popped_too_high,
630 decreases NR_LEVELS - self.level,
631 {
632 reveal(PageTableOwner::pt_inv_at_depth);
633 if self.level == self.guard_level && self.index() + 1 == NR_ENTRIES {
634 return;
635 }
636 if self.index() + 1 >= NR_ENTRIES && self.level < NR_LEVELS {
637 self.pop_level_owner().0.lemma_move_forward_not_popped_too_high();
638 }
639 }
640
641 proof fn lemma_move_forward_owner_popped_too_high_decreases(self)
642 requires
643 self.inv(),
644 self.level <= NR_LEVELS,
645 self.in_barrier_va(),
646 self.popped_too_high,
647 self.continuations[NR_LEVELS - 1].idx + 1 < NR_ENTRIES,
648 ensures
649 self.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(
650 self.level as usize,
651 ) <= self.max_steps(),
652 decreases NR_LEVELS - self.level,
653 {
654 reveal(PageTableOwner::pt_inv_at_depth);
655 let l = self.level as usize;
656 let st_l = Self::max_steps_subtree(l) as int;
657
658 if self.level == self.guard_level && self.index() + 1 == NR_ENTRIES {
659 self.lemma_move_forward_guard_end();
660 return;
661 }
662 if self.index() + 1 < NR_ENTRIES {
663 let inc = self.inc_index();
666
667 let new_state = inc.zero_below_level();
668
669 new_state.lemma_max_steps_partial_eq(self, (self.level + 1) as usize);
670 let self_idx = self.continuations[self.level - 1].idx as int;
671 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
672 st_l,
673 NR_ENTRIES - self_idx - 2,
674 1,
675 );
676
677 } else if self.level < NR_LEVELS {
678 let popped2 = self.pop_level_owner().0;
679 let lp1 = (self.level + 1) as usize;
680 popped2.lemma_max_steps_partial_eq(self, lp1);
681
682 assert(Self::max_steps_subtree(l) * 0nat == 0) by (nonlinear_arith);
683 popped2.lemma_move_forward_owner_popped_too_high_decreases();
684
685 } else {
686 assert(false);
687 }
688 }
689
690 pub proof fn lemma_move_forward_owner_decreases_steps(self)
691 requires
692 self.inv(),
693 self.level <= NR_LEVELS,
694 self.in_barrier_va(),
695 !self.popped_too_high,
696 ensures
697 self.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(
698 self.level as usize,
699 ) <= self.max_steps(),
700 self.move_forward_owner_spec().max_steps() < self.max_steps(),
701 decreases NR_LEVELS - self.level,
702 {
703 reveal(PageTableOwner::pt_inv_at_depth);
704 self.lemma_in_barrier_va_level_le_guard_level();
705 let l = self.level as usize;
706 let st_l = Self::max_steps_subtree(l) as int;
707
708 if self.level == self.guard_level && self.index() + 1 == NR_ENTRIES {
709 self.lemma_move_forward_guard_end();
710 return;
711 }
712 if self.index() + 1 < NR_ENTRIES {
713 let inc = self.inc_index();
714
715 let new_state = inc.zero_below_level();
716
717 new_state.lemma_max_steps_partial_eq(self, (self.level + 1) as usize);
718 let self_idx = self.continuations[self.level - 1].idx as int;
719 let tail = self.max_steps_partial((self.level + 1) as usize) as int;
720 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
721 st_l,
722 NR_ENTRIES - self_idx - 2,
723 1,
724 );
725
726 } else if self.level < NR_LEVELS {
727 let popped = self.pop_level_owner().0;
728 let lp1 = (self.level + 1) as usize;
729 popped.lemma_max_steps_partial_eq(self, lp1);
730
731 assert(Self::max_steps_subtree(l) * 0nat == 0) by (nonlinear_arith);
732
733 if !popped.popped_too_high {
734 popped.lemma_move_forward_owner_decreases_steps();
735
736 } else {
737 popped.lemma_move_forward_owner_popped_too_high_decreases();
738 }
739 } else {
740 assert(false);
741 }
742 }
743
744 #[verifier::spinoff_prover]
746 pub proof fn lemma_move_forward_va_is_align_up(self)
747 requires
748 self.inv(),
749 self.level <= NR_LEVELS,
750 self.in_barrier_va(),
751 !self.popped_too_high,
752 ensures
753 self.move_forward_owner_spec().va == self@.align_up_spec(
754 page_size::<PagingConsts>(self.level),
755 ),
756 decreases NR_LEVELS - self.level,
757 {
758 C::lemma_paging_consts_properties();
759 C::axiom_current_paging_consts_hardcoded();
760 reveal(PageTableOwner::pt_inv_at_depth);
761 if self.level == self.guard_level && self.index() + 1 == NR_ENTRIES {
762 self.lemma_move_forward_guard_end();
763 return;
764 }
765 if self.index() + 1 < NR_ENTRIES {
766 self.inc_and_zero_increases_va();
767 return;
768 }
769 assert(self.level < NR_LEVELS);
770 let popped = self.pop_level_owner().0;
771 assert(self.move_forward_owner_spec().va == popped.move_forward_owner_spec().va);
772 if !popped.popped_too_high {
773 popped.lemma_move_forward_va_is_align_up();
774 popped.lemma_va_plus_page_size_no_overflow(popped.level);
775 } else {
776 popped.inc_and_zero_increases_va();
777 popped.lemma_inc_index_va();
778 }
779
780 self.lemma_va_plus_page_size_no_overflow(self.level);
781 lemma_page_size_next::<C>(self.level);
782 lemma_page_size_ge_base::<PagingConsts>(self.level);
783 lemma_nat_align_down_sound(self.va as nat, page_size::<PagingConsts>(self.level) as nat);
784 let next = self@.align_up_spec(page_size::<PagingConsts>(self.level));
785 lemma_mod_add_multiples_vanish(
786 nat_align_down(self.va as nat, page_size::<PagingConsts>(self.level) as nat) as int,
787 page_size::<PagingConsts>(self.level) as int,
788 );
789 lemma_next_slot_pte_index::<C>(self.va, next, self.level);
790 assert(pte_index_spec::<C>(next, self.level) == 0);
791 lemma_next_slot_pte_index::<C>(popped.va, next, popped.level);
792 assert(self@.align_up_spec(page_size::<PagingConsts>(self.level)) == popped@.align_up_spec(
793 page_size::<PagingConsts>(popped.level),
794 ));
795 }
796
797 pub proof fn lemma_pop_level_owner_preserves_mappings(self)
801 requires
802 self.inv(),
803 self.level < NR_LEVELS,
804 self.in_barrier_va(),
805 ensures
806 self.pop_level_owner().0@.mappings == self@.mappings,
807 {
808 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
809
810 let child = self.continuations[self.level - 1];
811 let parent = self.continuations[self.level as int];
812 let (restored_parent, _) = parent.restore(child);
813 let popped = self.pop_level_owner().0;
814 let child_subtree = child.as_subtree();
815
816 let r = restored_parent;
817 let p = parent.put_child(child_subtree);
818 assert forall|j: int| 0 <= j < r.children.len() implies r.children[j]
819 == p.children[j] by {};
820
821 assert(restored_parent.view_mappings() == parent.put_child(child_subtree).view_mappings())
822 by {};
823
824 parent.view_mappings_put_child(child_subtree);
825 child.as_page_table_owner_preserves_view_mappings();
826
827 assert(popped.view_mappings() == self.view_mappings()) by {
828 assert forall|m: Mapping|
829 self.view_mappings().contains(m) implies popped.view_mappings().contains(m) by {
830 let i = choose|i: int|
831 self.level - 1 <= i < NR_LEVELS && (
832 #[trigger] self.continuations[i]).view_mappings().contains(m);
833 if i == self.level - 1 {
834 assert(popped.continuations[self.level as int].view_mappings().contains(m));
835 } else if i == self.level {
836 assert(popped.continuations[self.level as int].view_mappings().contains(m));
837 } else {
838 assert(popped.continuations[i] == self.continuations[i]);
839 }
840 };
841
842 };
843 }
844
845 pub proof fn lemma_move_forward_owner_preserves_mappings(self)
846 requires
847 self.inv(),
848 self.in_barrier_va(),
849 ensures
850 self.move_forward_owner_spec()@.mappings == self@.mappings,
851 decreases NR_LEVELS - self.level,
852 {
853 reveal(PageTableOwner::pt_inv_at_depth);
854 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
855
856 if self.level == self.guard_level && self.index() + 1 == NR_ENTRIES {
857 return;
858 }
859 if self.index() + 1 < NR_ENTRIES {
860 let inc = self.inc_index();
861 let result = inc.zero_below_level();
862
863 let old_cont = self.continuations[self.level - 1];
864 let new_cont = old_cont.inc_index();
865
866 assert(result.view_mappings() == self.view_mappings()) by {
867 assert forall|m: Mapping|
868 self.view_mappings().contains(m) implies result.view_mappings().contains(m) by {
869 let i = choose|i: int|
870 self.level - 1 <= i < NR_LEVELS && (
871 #[trigger] self.continuations[i]).view_mappings().contains(m);
872 if i == self.level - 1 {
873 assert(result.continuations[i].view_mappings().contains(m));
874 } else {
875 assert(result.continuations[i] == self.continuations[i]);
876 }
877 };
878
879 };
880
881 } else if self.level < NR_LEVELS {
882 let popped = self.pop_level_owner().0;
883
884 self.lemma_pop_level_owner_preserves_mappings();
885 popped.lemma_move_forward_owner_preserves_mappings();
886 }
887 }
888
889 pub proof fn lemma_move_forward_guard_end(self)
891 requires
892 self.inv(),
893 self.in_barrier_va(),
894 self.level == self.guard_level,
895 self.index() + 1 == NR_ENTRIES,
896 ensures
897 self.move_forward_owner_spec().va == self.locked_range().end,
898 self.move_forward_owner_spec().at_or_past_barrier_end(),
899 self.move_forward_owner_spec().inv(),
900 self.move_forward_owner_spec().max_steps() == 0,
901 self.move_forward_owner_spec().va == self@.align_up_spec(
902 page_size::<PagingConsts>(self.level),
903 ),
904 {
905 use vstd::arithmetic::div_mod::*;
906 C::lemma_paging_consts_properties();
907 C::axiom_current_paging_consts_hardcoded();
908 self.lemma_cur_pte_index();
909 self.lemma_locked_range_span();
910 self.lemma_va_plus_page_size_no_overflow(self.level);
911 lemma_page_size_next::<C>(self.level);
912 lemma_pte_index_spec_is_div_mod::<C>(self.va, self.level);
913 let ps = page_size::<C>(self.level) as int;
914 let node_ps = page_size::<C>((self.level + 1) as PagingLevel) as int;
915 lemma_fundamental_div_mod(self.prefix as int, node_ps);
916 lemma_fundamental_div_mod_converse(
917 self.va as int,
918 node_ps,
919 self.prefix as int / node_ps,
920 self.va - self.prefix,
921 );
922 lemma_mod_breakdown(self.va as int, ps, NR_ENTRIES as int);
923 lemma_nat_align_down_sound(self.va as nat, ps as nat);
924 assert(nat_align_down(self.va as nat, ps as nat) + ps == self.prefix + node_ps)
925 by (nonlinear_arith)
926 requires
927 self.va as int % node_ps == self.va - self.prefix,
928 self.va as int % node_ps == ps * (self.va as int / ps % NR_ENTRIES as int)
929 + self.va as int % ps,
930 self.va as int / ps % NR_ENTRIES as int == NR_ENTRIES - 1,
931 node_ps == ps * NR_ENTRIES,
932 nat_align_down(self.va as nat, ps as nat) == self.va - self.va as int % ps,
933 ;
934 let next = self.move_forward_owner_spec().va;
935 self.lemma_locked_range_page_aligned();
936 lemma_page_table_managed_index_bounds::<C>(self.va);
937 lemma_page_size_divides::<C>(self.level, C::NR_LEVELS());
938 lemma_nat_align_down_within_block(
939 self.va as nat,
940 page_size::<C>(self.level) as nat,
941 page_size::<C>(C::NR_LEVELS()) as nat,
942 );
943 lemma_page_size_next::<C>(C::NR_LEVELS());
944 lemma_vaddr_leading_part_is_align_down::<C>(self.va);
945 let root_base = vaddr_leading_part_spec::<C>(self.va);
946 let root_size = page_size::<C>((C::NR_LEVELS() + 1) as PagingLevel);
947 lemma_nat_align_down_sound(self.va as nat, root_size as nat);
948 lemma_same_node_vaddr_leading_part_match::<C>(next, self.va, root_base, C::NR_LEVELS());
949 assert(self.move_forward_owner_spec().inv()) by {
950 reveal(<CursorOwner as Inv>::inv);
951 };
952 }
953}
954
955}