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