1use core::ops::Range;
2
3use vstd::prelude::*;
4
5use vstd_extra::{
6 arithmetic::{lemma_nat_align_down_sound, nat_align_down},
7 ghost_tree::*,
8 ownership::*,
9};
10
11use crate::specs::{
12 arch::{NR_ENTRIES, NR_LEVELS},
13 mm::{
14 Guards, Mapping, MetaRegionOwners,
15 frame::mapping::frame_to_index,
16 page_table::{
17 AbstractVaddr,
18 cursor::{owners::*, page_size_lemmas::lemma_page_size_ge_page_size},
19 node::EntryOwner,
20 owners::{INC_LEVELS, OwnerSubtree, PageTableOwner},
21 },
22 },
23};
24
25use crate::mm::{
26 Paddr, PagingConstsTrait, PagingLevel, Vaddr, frame::meta::mapping::meta_to_frame, page_size,
27 page_table::*,
28};
29
30use crate::arch::mm::PagingConsts;
31
32verus! {
33
34broadcast use group_ghost_tree_lemmas;
35
36pub proof fn push_tail_different_indices_different_paths(path: TreePath<NR_ENTRIES>, i: int, j: int)
38 requires
39 path.inv(),
40 0 <= i < NR_ENTRIES,
41 0 <= j < NR_ENTRIES,
42 i != j,
43 ensures
44 path.push_tail(i) != path.push_tail(j),
45{
46}
47
48pub proof fn different_length_different_paths(
50 path1: TreePath<NR_ENTRIES>,
51 path2: TreePath<NR_ENTRIES>,
52)
53 requires
54 path1.len() != path2.len(),
55 ensures
56 path1 != path2,
57{
58}
59
60pub proof fn push_tail_increases_length(path: TreePath<NR_ENTRIES>, i: int)
62 requires
63 path.inv(),
64 0 <= i < NR_ENTRIES,
65 ensures
66 path.push_tail(i).len() > path.len(),
67{
68}
69
70pub proof fn subtree_unlock_upgrade<'rcu, C: PageTableConfig>(
76 subtree: OwnerSubtree<C>,
77 path: TreePath<NR_ENTRIES>,
78 guards: Guards<'rcu>,
79 regions: MetaRegionOwners,
80 excepted_addr: usize,
81 excepted_path: TreePath<NR_ENTRIES>,
82)
83 requires
84 subtree.inv(),
85 PageTableOwner::<C>(subtree).pt_inv(),
86 subtree.subtree_satisfies(path, PageTableOwner::<C>::metaregion_sound_pred(regions)),
87 subtree.subtree_satisfies(
88 path,
89 CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr),
90 ),
91 regions.slot_owners[frame_to_index(meta_to_frame(excepted_addr))].paths_in_pt
92 == set![excepted_path],
93 path == subtree.value().path,
95 path.inv(),
96 path != excepted_path,
98 excepted_path.len() <= path.len() || (exists|k: int|
102 0 <= k < path.len() && #[trigger] excepted_path[k] != path[k]),
103 ensures
104 subtree.subtree_satisfies(path, CursorOwner::<'rcu, C>::node_unlocked(guards)),
105 decreases INC_LEVELS - subtree.level(),
106{
107 let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
108 let g = CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr);
109 let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
110
111 if subtree.value().is_node() {
112 if subtree.value().node().meta_vaddr() == excepted_addr {
113 let idx = frame_to_index(meta_to_frame(excepted_addr));
116
117 assert(set![subtree.value().path].contains(excepted_path));
118 assert(false);
119 }
120 }
121 if subtree.level() < INC_LEVELS - 1 && subtree.value().is_node() {
122 assert forall|i: int|
123 #![trigger subtree.children()[i]]
124 0 <= i < subtree.children().len() && subtree.has_child(i) implies subtree.child(
125 i,
126 ).subtree_satisfies(path.push_tail(i), h) by {
127 let child = subtree.child(i);
128
129 let child_path = path.push_tail(i);
130
131 subtree_unlock_upgrade(
132 child,
133 child_path,
134 guards,
135 regions,
136 excepted_addr,
137 excepted_path,
138 );
139 };
140 } else if subtree.level() < INC_LEVELS - 1 && !subtree.value().is_node() {
141 }
144}
145
146impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
147 pub open spec fn max_steps_subtree(level: usize) -> nat
150 decreases level,
151 {
152 if level <= 1 {
153 NR_ENTRIES as nat
154 } else {
155 (NR_ENTRIES as nat) * (Self::max_steps_subtree((level - 1) as usize) + 1)
156 }
157 }
158
159 pub open spec fn max_steps_partial(self, level: usize) -> nat
171 decreases NR_LEVELS + 1 - level,
172 when level <= NR_LEVELS + 1
173 {
174 if level > NR_LEVELS {
175 0
176 } else {
177 let cont = self.continuations[(level - 1) as int];
178 let count: nat = (NR_ENTRIES - cont.idx - 1) as nat;
179 let steps = Self::max_steps_subtree(level) * count;
180 let remaining_steps = self.max_steps_partial((level + 1) as usize);
181 steps + remaining_steps
182 }
183 }
184
185 pub open spec fn max_steps(self) -> nat {
186 (self.max_steps_partial(self.level as usize) + Self::max_steps_subtree(
187 self.level as usize,
188 )) as nat
189 }
190
191 pub proof fn max_steps_subtree_positive(level: usize)
192 ensures
193 Self::max_steps_subtree(level) > 0,
194 decreases level,
195 {
196 }
197
198 pub proof fn max_steps_partial_eq(self, other: Self, start: usize)
200 requires
201 1 <= start <= NR_LEVELS + 1,
202 forall|k: int|
203 start - 1 <= k < NR_LEVELS ==> #[trigger] self.continuations[k].idx
204 == other.continuations[k].idx,
205 ensures
206 self.max_steps_partial(start) == other.max_steps_partial(start),
207 decreases NR_LEVELS + 1 - start,
208 {
209 if start <= NR_LEVELS {
210 self.max_steps_partial_eq(other, (start + 1) as usize);
211 }
212 }
213
214 pub proof fn max_steps_partial_inv(self, other: Self, level: usize)
215 requires
216 self.inv(),
217 other.inv(),
218 self.level == other.level,
219 self.level <= level <= NR_LEVELS + 1,
220 forall|i: int|
221 #![trigger self.continuations[i].idx]
222 #![trigger other.continuations[i].idx]
223 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].idx
224 == other.continuations[i].idx,
225 ensures
226 self.max_steps_partial(level) == other.max_steps_partial(level),
227 decreases NR_LEVELS + 1 - level,
228 {
229 if level <= NR_LEVELS {
230 self.max_steps_partial_inv(other, (level + 1) as usize);
231 }
232 }
233
234 pub open spec fn push_level_owner(self, guard: PageTableGuard<'rcu, C>) -> Self {
235 let cont = self.continuations[self.level - 1];
236 let (child, cont) = cont.make_cont(self.va.index[self.level - 2] as usize, guard);
237 let new_continuations = self.continuations.insert(self.level - 1, cont).insert(
238 self.level - 2,
239 child,
240 );
241
242 let new_level = (self.level - 1) as u8;
243 Self { continuations: new_continuations, level: new_level, popped_too_high: false, ..self }
244 }
245
246 pub proof fn push_level_owner_decreases_steps(self, guard: PageTableGuard<'rcu, C>)
247 requires
248 self.inv(),
249 self.level > 1,
250 ensures
251 self.push_level_owner(guard).max_steps() < self.max_steps(),
252 {
253 let new_self = self.push_level_owner(guard);
254 let l = self.level as usize;
255 let lm1 = (self.level - 1) as usize;
256 new_self.max_steps_partial_eq(self, l);
258 assert(self.va.index.contains_key(self.level - 2));
260 let new_child = new_self.continuations[lm1 - 1];
261
262 vstd::arithmetic::mul::lemma_mul_inequality(
265 (NR_ENTRIES - new_child.idx) as int,
266 NR_ENTRIES as int,
267 Self::max_steps_subtree(lm1) as int,
268 );
269 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
270 Self::max_steps_subtree(lm1) as int,
271 (NR_ENTRIES - new_child.idx - 1) as int,
272 1,
273 );
274 vstd::arithmetic::mul::lemma_mul_is_commutative(
275 (NR_ENTRIES - new_child.idx) as int,
276 Self::max_steps_subtree(lm1) as int,
277 );
278
279 }
280
281 pub proof fn push_level_owner_preserves_va(self, guard: PageTableGuard<'rcu, C>)
282 requires
283 self.inv(),
284 self.level > 1,
285 ensures
286 self.push_level_owner(guard).va == self.va,
287 self.push_level_owner(guard).continuations[self.level - 2].idx
288 == self.va.index[self.level - 2],
289 {
290 assert(self.va.index.contains_key(self.level - 2));
291 }
292
293 pub proof fn push_level_owner_preserves_mappings(self, guard: PageTableGuard<'rcu, C>)
294 requires
295 self.inv(),
296 self.level > 1,
297 self.cur_entry_owner().is_node(),
298 ensures
299 self.push_level_owner(guard)@.mappings == self@.mappings,
300 {
301 broadcast use {
302 CursorContinuation::group_lemmas,
303 CursorOwner::group_lemmas,
304 PageTableOwner::group_lemmas,
305 };
306
307 let new_owner = self.push_level_owner(guard);
308 let old_cont = self.continuations[self.level - 1];
309 let (_, modified_cont) = old_cont.make_cont(self.va.index[self.level - 2] as usize, guard);
310
311 old_cont.view_mappings_take_child();
312
313 let taken = old_cont.take_child().1;
314
315 assert(modified_cont.children == taken.children) by {};
316
317 assert forall|m: Mapping|
318 self.view_mappings().contains(m) implies new_owner.view_mappings().contains(m) by {
319 let i = choose|i: int|
320 self.level - 1 <= i < NR_LEVELS && (
321 #[trigger] self.continuations[i]).view_mappings().contains(m);
322 if i == self.level - 1 {
323 if old_cont.view_mappings_take_child_spec().contains(m) {
324 assert(new_owner.continuations[self.level - 2].view_mappings().contains(m));
325 } else {
326 assert(new_owner.continuations[self.level - 1].view_mappings().contains(m));
327 }
328 } else {
329 assert(new_owner.continuations[i] == self.continuations[i]);
330 }
331 };
332
333 }
334
335 pub proof fn push_level_owner_preserves_inv(self, guard: PageTableGuard<'rcu, C>)
336 requires
337 self.inv(),
338 self.level > 1,
339 !self.popped_too_high,
340 self.level <= self.guard_level,
341 self.in_locked_range(),
342 self.cur_entry_owner().is_node(),
344 self.cur_entry_owner().node().relate_guard(guard),
346 forall|i: int|
348 #![trigger self.continuations[i]]
349 self.level - 1 <= i < NR_LEVELS
350 ==> self.continuations[i].guard.inner.inner@.ptr.addr()
351 != guard.inner.inner@.ptr.addr(),
352 ensures
353 self.push_level_owner(guard).inv(),
354 {
355 self.in_locked_range_guard_index_eq_prefix();
361
362 let new_owner = self.push_level_owner(guard);
363
364 let old_cont = self.continuations[self.level - 1];
365
366 let child_node = old_cont.children[old_cont.idx as int].unwrap();
367 let (child, _) = old_cont.make_cont(self.va.index[self.level - 2] as usize, guard);
368
369 assert(self.va.index.contains_key(self.level - 2));
370
371 assert(child.inv_children_rel()) by {
372 assert forall|j: int|
373 0 <= j < NR_ENTRIES && #[trigger] child.children[j] is Some implies {
374 &&& child.children[j].unwrap().value().parent_level == child.level()
375 &&& child.children[j].unwrap().level() == child.tree_level + 1
376 &&& child.children[j].unwrap().value().path.len()
377 == child.entry_own.node().tree_level + 1
378 &&& child.children[j].unwrap().value().match_pte(
379 child.entry_own.node().children_perm.value()[j],
380 child.entry_own.node().level,
381 )
382 &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
383 child.entry_own,
384 j,
385 Some(child.children[j].unwrap().value()),
386 )
387 &&& child.children[j].unwrap().value().path == child.path().push_tail(j)
388 } by {
389 let gc = child.children[j].unwrap();
390 PageTableOwner(child_node).pt_inv_unroll(j);
391
392 };
393 };
394 assert(child.pt_inv_children()) by {
395 assert forall|j: int|
396 0 <= j < child.children.len()
397 && #[trigger] child.children[j] is Some implies PageTableOwner(
398 child.children[j].unwrap(),
399 ).pt_inv() by {
400 PageTableOwner(child_node).pt_inv_unroll(j);
401
402 };
403 };
404
405 assert(new_owner.continuations[new_owner.level - 1].all_some()) by {
406 assert forall|j: int| 0 <= j < NR_ENTRIES implies child.children[j] is Some by {
407 PageTableOwner(child_node).pt_inv_unroll(j);
408
409 };
410 };
411
412 }
413
414 pub proof fn push_level_owner_preserves_invs(
415 self,
416 guard: PageTableGuard<'rcu, C>,
417 regions: MetaRegionOwners,
418 guards: Guards<'rcu>,
419 )
420 requires
421 self.inv(),
422 self.level > 1,
423 !self.popped_too_high,
424 self.level <= self.guard_level,
425 self.in_locked_range(),
426 self.only_current_locked(guards),
427 self.nodes_locked(guards),
428 self.metaregion_sound(regions),
429 self.cur_entry_owner().is_node(),
431 self.cur_entry_owner().node().relate_guard(guard),
433 guards.lock_held(guard.inner.inner@.ptr.addr()),
435 ensures
436 self.push_level_owner(guard).inv(),
437 self.push_level_owner(guard).children_not_locked(guards),
438 self.push_level_owner(guard).nodes_locked(guards),
439 self.push_level_owner(guard).metaregion_sound(regions),
440 {
441 let new_owner = self.push_level_owner(guard);
442 let old_cont = self.continuations[self.level - 1];
443
444 let (child_cont, modified_cont) = old_cont.make_cont(
445 self.va.index[self.level - 2] as usize,
446 guard,
447 );
448
449 let cur_entry = self.cur_entry_owner();
450 let cur_entry_addr = cur_entry.node().meta_vaddr();
451 let cur_entry_path = old_cont.path().push_tail(old_cont.idx as int);
452
453 assert forall|i: int|
454 #![trigger self.continuations[i]]
455 self.level - 1 <= i
456 < NR_LEVELS implies self.continuations[i].guard.inner.inner@.ptr.addr()
457 != guard.inner.inner@.ptr.addr() by {
458 let cont_i = self.continuations[i];
459
460 if cont_i.guard.inner.inner@.ptr.addr() == guard.inner.inner@.ptr.addr() {
461 let addr = cont_i.entry_own.node().meta_vaddr();
462 assert(addr == cur_entry.node().meta_vaddr());
463 let idx = frame_to_index(meta_to_frame(addr));
464 assert(regions.slot_owners[idx].paths_in_pt == set![cont_i.path()]);
465 assert(regions.slot_owners[idx].paths_in_pt == set![cur_entry_path]);
466 assert(set![cont_i.path()].contains(cur_entry_path));
467
468 assert(cur_entry_path.len() == old_cont.tree_level + 1) by {
469 old_cont.inv_children_rel_unroll(old_cont.idx as int);
470 };
471 assert(false);
472 }
473 };
474
475 self.push_level_owner_preserves_inv(guard);
476
477 let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
478 let g_except = CursorOwner::<'rcu, C>::node_unlocked_except(guards, cur_entry_addr);
479 let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
480
481 assert forall|i: int|
482 #![trigger new_owner.continuations[i]]
483 new_owner.level - 1 <= i < NR_LEVELS implies new_owner.continuations[i].map_children(
484 h,
485 ) by {
486 if i == self.level - 2 {
487 assert forall|j: int|
488 #![trigger child_cont.children[j]]
489 0 <= j < child_cont.children.len()
490 && child_cont.children[j] is Some implies child_cont.children[j].unwrap().subtree_satisfies(
491 child_cont.path().push_tail(j), h) by {
492 let gc = child_cont.children[j].unwrap();
493 let gc_path = child_cont.path().push_tail(j);
494
495 let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
496 child_subtree.lemma_subtree_satisfies_unroll_once(cur_entry_path, f, j);
497 child_subtree.lemma_subtree_satisfies_unroll_once(cur_entry_path, g_except, j);
498
499 subtree_unlock_upgrade(
500 gc,
501 gc_path,
502 guards,
503 regions,
504 cur_entry_addr,
505 cur_entry_path,
506 );
507 };
508 } else if i == self.level - 1 {
509 assert forall|j: int|
510 #![trigger modified_cont.children[j]]
511 0 <= j < modified_cont.children.len()
512 && modified_cont.children[j] is Some implies modified_cont.children[j].unwrap().subtree_satisfies(
513 modified_cont.path().push_tail(j), h) by {
514 let sibling = old_cont.children[j].unwrap();
515 let sibling_path = old_cont.path().push_tail(j);
516
517 subtree_unlock_upgrade(
518 sibling,
519 sibling_path,
520 guards,
521 regions,
522 cur_entry_addr,
523 cur_entry_path,
524 );
525 };
526 } else {
527 let cont_i = self.continuations[i];
528
529 assert(cur_entry_path[cont_i.tree_level as int] == cont_i.idx as int);
530
531 assert forall|j: int|
532 #![trigger cont_i.children[j]]
533 0 <= j < cont_i.children.len()
534 && cont_i.children[j] is Some implies cont_i.children[j].unwrap().subtree_satisfies(
535 cont_i.path().push_tail(j), h) by {
536 let child_sub = cont_i.children[j].unwrap();
537 let child_path = cont_i.path().push_tail(j);
538
539 subtree_unlock_upgrade(
540 child_sub,
541 child_path,
542 guards,
543 regions,
544 cur_entry_addr,
545 cur_entry_path,
546 );
547 };
548 }
549 };
550
551 let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
552 let child_subtree = child_cont.as_subtree();
553
554 assert(child_cont.map_children(f)) by {
555 assert forall|j: int|
556 0 <= j < child_cont.children.len()
557 && #[trigger] child_cont.children[j] is Some implies child_cont.children[j].unwrap().subtree_satisfies(
558 child_cont.path().push_tail(j), f) by {
559 child_subtree.lemma_subtree_satisfies_unroll_once(child_cont.path(), f, j);
560
561 };
562 };
563
564 }
565
566 pub proof fn tracked_push_level_owner(tracked &mut self, guard: PageTableGuard<'rcu, C>)
567 requires
568 old(self).inv(),
569 old(self).level > 1,
570 ensures
571 *final(self) == old(self).push_level_owner(guard),
572 {
573 assert(self.va.index.contains_key(self.level - 2));
574
575 let ghost self0 = *self;
576 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
577 let tracked child = cont.tracked_make_cont(self.va.index[self.level - 2] as usize, guard);
578
579 self.continuations.tracked_insert(self.level - 1, cont);
580 self.continuations.tracked_insert(self.level - 2, child);
581
582 assert(self.continuations == self0.continuations.insert(self.level - 1, cont).insert(
583 self.level - 2,
584 child,
585 ));
586
587 self.popped_too_high = false;
588
589 self.level = (self.level - 1) as u8;
590 }
591
592 pub open spec fn pop_level_owner(self) -> (Self, PageTableGuard<'rcu, C>) {
593 let child = self.continuations[self.level - 1];
594 let cont = self.continuations[self.level as int];
595 let (new_cont, guard) = cont.restore(child);
596 let new_continuations = self.continuations.insert(self.level as int, new_cont).remove(
597 self.level - 1,
598 );
599 let new_level = (self.level + 1) as u8;
600 let popped_too_high = if new_level >= self.guard_level {
601 true
602 } else {
603 false
604 };
605 (
606 Self {
607 continuations: new_continuations,
608 level: new_level,
609 popped_too_high: popped_too_high,
610 ..self
611 },
612 guard,
613 )
614 }
615
616 pub proof fn pop_level_owner_preserves_inv(self)
617 requires
618 self.inv(),
619 self.level < NR_LEVELS,
620 ensures
621 self.pop_level_owner().0.inv(),
622 {
623 }
624
625 pub proof fn pop_level_owner_preserves_invs(
626 self,
627 guards: Guards<'rcu>,
628 regions: MetaRegionOwners,
629 )
630 requires
631 self.inv(),
632 self.level < NR_LEVELS,
633 self.children_not_locked(guards),
634 self.nodes_locked(guards),
635 self.metaregion_sound(regions),
636 ensures
637 self.pop_level_owner().0.inv(),
638 self.pop_level_owner().0.only_current_locked(guards),
639 self.pop_level_owner().0.nodes_locked(guards),
640 self.pop_level_owner().0.metaregion_sound(regions),
641 {
642 let child = self.continuations[self.level - 1];
643 let child_addr = child.entry_own.node().meta_vaddr();
644
645 self.map_children_implies(
646 CursorOwner::<'rcu, C>::node_unlocked(guards),
647 CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
648 );
649
650 }
651
652 pub proof fn set_va_preserves_inv(self, new_va: AbstractVaddr)
658 requires
659 self.inv(),
660 self.in_locked_range(),
661 !self.popped_too_high,
662 self.level <= self.guard_level,
663 new_va.inv(),
664 new_va.offset == 0,
665 new_va.leading_bits == self.prefix.leading_bits,
666 forall|i: int|
667 #![auto]
668 self.level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.va.index[i],
669 forall|i: int|
670 #![auto]
671 self.guard_level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.prefix.index[i],
672 ensures
673 self.set_va(new_va).inv(),
674 {
675 let r = self.set_va(new_va);
676
677 assert(r.in_locked_range()) by {
678 let gl = self.guard_level;
679 if gl >= 1 && gl <= NR_LEVELS {
680 r.va.align_down_to_vaddr_eq_if_upper_indices_eq(r.prefix, gl as int);
681 r.va.align_down_concrete(gl as int);
682 r.prefix.align_down_concrete(gl as int);
683 self.prefix_aligned_to_guard_level();
685 self.prefix_plus_ps_no_overflow();
686 r.prefix.aligned_align_up_advances(gl as int);
687 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
688 nat_align_down(
689 r.va.to_vaddr() as nat,
690 page_size(gl as PagingLevel) as nat,
691 ) as Vaddr,
692 );
693 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
694 nat_align_down(
695 r.prefix.to_vaddr() as nat,
696 page_size(gl as PagingLevel) as nat,
697 ) as Vaddr,
698 );
699
700 lemma_nat_align_down_sound(
701 r.va.to_vaddr() as nat,
702 page_size(gl as PagingLevel) as nat,
703 );
704
705 }
706 };
707
708 }
709
710 pub open spec fn move_forward_owner_spec(self) -> Self
711 recommends
712 self.inv(),
713 self.level < NR_LEVELS,
714 self.in_locked_range(),
715 decreases NR_LEVELS - self.level,
716 when self.level <= NR_LEVELS
717 {
718 if self.index() + 1 < NR_ENTRIES {
719 self.inc_index().zero_below_level()
724 } else if self.level < NR_LEVELS {
725 self.pop_level_owner().0.move_forward_owner_spec()
726 } else {
727 Self { va: self.va.next_index(NR_LEVELS as int), popped_too_high: false, ..self }
730 }
731 }
732
733 pub proof fn move_forward_increases_va(self)
734 requires
735 self.inv(),
736 self.level <= NR_LEVELS,
737 self.in_locked_range(),
738 !self.popped_too_high,
739 ensures
740 self.move_forward_owner_spec().va.to_vaddr() > self.va.to_vaddr(),
741 decreases NR_LEVELS - self.level,
742 {
743 if self.index() + 1 < NR_ENTRIES {
744 self.inc_and_zero_increases_va();
745 } else if self.level == self.guard_level {
746 self.in_locked_range_guard_index_eq_prefix();
749 let k = self.prefix.index[self.guard_level - 1];
750
751 if self.guard_level < NR_LEVELS {
752 } else {
754 assert(false);
759 }
760 } else if self.level + 1 < self.guard_level {
761 self.pop_level_owner().0.move_forward_increases_va();
762 } else {
763 let k = self.prefix.index[self.guard_level - 1];
764
765 let popped = self.pop_level_owner().0;
766
767 if k + 1 < NR_ENTRIES {
768 assert(popped.move_forward_owner_spec() == popped.inc_index().zero_below_level());
769 popped.inc_and_zero_increases_va();
770 }
771 }
772 }
773
774 pub proof fn move_forward_not_popped_too_high(self)
775 requires
776 self.inv(),
777 self.level <= NR_LEVELS,
778 self.in_locked_range(),
779 ensures
780 !self.move_forward_owner_spec().popped_too_high,
781 decreases NR_LEVELS - self.level,
782 {
783 if self.index() + 1 >= NR_ENTRIES && self.level < NR_LEVELS {
784 self.pop_level_owner().0.move_forward_not_popped_too_high();
785 }
786 }
787
788 pub proof fn move_forward_owner_popped_too_high_decreases(self)
793 requires
794 self.inv(),
795 self.level <= NR_LEVELS,
796 self.in_locked_range(),
797 self.popped_too_high,
798 self.continuations[NR_LEVELS - 1].idx + 1 < NR_ENTRIES,
799 ensures
800 self.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(
801 self.level as usize,
802 ) <= self.max_steps(),
803 decreases NR_LEVELS - self.level,
804 {
805 let l = self.level as usize;
806 let st_l = Self::max_steps_subtree(l) as int;
807
808 if self.index() + 1 < NR_ENTRIES {
809 let inc = self.inc_index();
812
813 let new_state = inc.zero_below_level();
814
815 new_state.max_steps_partial_eq(self, (self.level + 1) as usize);
816 let self_idx = self.continuations[self.level - 1].idx as int;
817 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
818 st_l,
819 NR_ENTRIES - self_idx - 2,
820 1,
821 );
822
823 } else if self.level < NR_LEVELS {
824 let popped2 = self.pop_level_owner().0;
826 let lp1 = (self.level + 1) as usize;
827 popped2.max_steps_partial_eq(self, lp1);
828
829 assert(Self::max_steps_subtree(l) * 0nat == 0) by (nonlinear_arith);
830
831 popped2.move_forward_owner_popped_too_high_decreases();
838
839 } else {
840 assert(false);
843 }
844 }
845
846 pub proof fn move_forward_owner_decreases_steps(self)
847 requires
848 self.inv(),
849 self.level <= NR_LEVELS,
850 self.in_locked_range(),
851 !self.popped_too_high,
852 self.continuations[NR_LEVELS - 1].idx + 1 < NR_ENTRIES,
855 ensures
856 self.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(
861 self.level as usize,
862 ) <= self.max_steps(),
863 self.move_forward_owner_spec().max_steps() < self.max_steps(),
864 decreases NR_LEVELS - self.level,
865 {
866 let l = self.level as usize;
867 let st_l = Self::max_steps_subtree(l) as int;
868
869 if self.index() + 1 < NR_ENTRIES {
870 let inc = self.inc_index();
874
875 let new_state = inc.zero_below_level();
876
877 new_state.max_steps_partial_eq(self, (self.level + 1) as usize);
878 let self_idx = self.continuations[self.level - 1].idx as int;
879 let tail = self.max_steps_partial((self.level + 1) as usize) as int;
880 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
882 st_l,
883 NR_ENTRIES - self_idx - 2,
884 1,
885 );
886 } else if self.level < NR_LEVELS {
893 let popped = self.pop_level_owner().0;
894 let lp1 = (self.level + 1) as usize;
895 popped.max_steps_partial_eq(self, lp1);
896
897 assert(Self::max_steps_subtree(l) * 0nat == 0) by (nonlinear_arith);
898
899 if !popped.popped_too_high {
900 popped.move_forward_owner_decreases_steps();
901
902 } else {
903 popped.move_forward_owner_popped_too_high_decreases();
907 }
908 } else {
909 assert(false);
910 }
911 }
912
913 pub proof fn zero_below_level_eq_align_down(self)
915 requires
916 self.va.inv(),
917 self.va.offset == 0,
918 1 <= self.level <= NR_LEVELS,
919 ensures
920 self.zero_below_level().va == self.va.align_down(self.level as int),
921 decreases self.level,
922 {
923 }
924
925 #[verifier::spinoff_prover]
926 pub proof fn move_forward_va_is_align_up(self)
927 requires
928 self.inv(),
929 self.level <= NR_LEVELS,
930 self.in_locked_range(),
931 !self.popped_too_high,
932 self.level == self.guard_level ==> self.index() + 1 < NR_ENTRIES,
938 ensures
939 self.move_forward_owner_spec().va == self.va.align_up(self.level as int),
940 decreases NR_LEVELS - self.level,
941 {
942 if self.level == self.guard_level {
943 if self.index() + 1 < NR_ENTRIES {
944 let inc = self.inc_index();
946
947 assert(inc.va.inv()) by {
948 assert forall|i: int| 0 <= i < NR_LEVELS implies inc.va.index.contains_key(i)
949 && 0 <= #[trigger] inc.va.index[i] && inc.va.index[i] < NR_ENTRIES by {
950 if i != self.level - 1 {
951 }
952 };
953 };
954 inc.va.align_down_concrete(self.level as int);
955 let ps = page_size(self.level as PagingLevel) as nat;
956 let self_va = self.va.to_vaddr() as nat;
957 lemma_page_size_ge_page_size(self.level as PagingLevel);
958
959 self.va.index_increment_adds_page_size(self.level as int);
960
961 let inc_va = inc.va.to_vaddr() as nat;
962 assert(inc_va == self_va + ps);
963 vstd::arithmetic::div_mod::lemma_mod_add_multiples_vanish(
964 self_va as int,
965 ps as int,
966 );
967 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(self_va as int, ps as int);
968
969 self.va.align_up_advances_general(self.level as int);
970
971 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va.align_up(self.level as int));
972 }
973 return;
977 }
978 if self.index() + 1 < NR_ENTRIES {
979 let inc = self.inc_index();
980
981 inc.va.align_down_concrete(self.level as int);
982 let ps = page_size(self.level as PagingLevel) as nat;
983 let self_va = self.va.to_vaddr() as nat;
984 lemma_page_size_ge_page_size(self.level as PagingLevel);
985
986 self.va.index_increment_adds_page_size(self.level as int);
987
988 let inc_va = inc.va.to_vaddr() as nat;
989 assert(inc_va == self_va + ps);
990 vstd::arithmetic::div_mod::lemma_mod_add_multiples_vanish(self_va as int, ps as int);
991
992 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(self_va as int, ps as int);
993
994 self.va.align_up_advances_general(self.level as int);
995
996 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va.align_up(self.level as int));
997 } else if self.level < NR_LEVELS {
998 let popped = self.pop_level_owner().0;
999 if !popped.popped_too_high {
1000 popped.move_forward_va_is_align_up();
1001 } else {
1002 let inc_p = popped.inc_index();
1003
1004 assert(inc_p.va.inv()) by {
1005 assert forall|i: int| 0 <= i < NR_LEVELS implies inc_p.va.index.contains_key(i)
1006 && 0 <= #[trigger] inc_p.va.index[i] && inc_p.va.index[i] < NR_ENTRIES by {
1007 if i != popped.level - 1 {
1008 }
1009 };
1010 };
1011 inc_p.va.align_down_concrete(popped.level as int);
1012 let ps_p = page_size(popped.level as PagingLevel) as nat;
1013 let popped_va = popped.va.to_vaddr() as nat;
1014 lemma_page_size_ge_page_size(popped.level as PagingLevel);
1015
1016 popped.va.index_increment_adds_page_size(popped.level as int);
1017
1018 vstd::arithmetic::div_mod::lemma_mod_add_multiples_vanish(
1019 popped_va as int,
1020 ps_p as int,
1021 );
1022 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(popped_va as int, ps_p as int);
1023
1024 popped.va.align_up_advances_general(popped.level as int);
1027
1028 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(
1029 popped.va.align_up(popped.level as int),
1030 );
1031
1032 assert(popped.move_forward_owner_spec().va == inc_p.zero_below_level().va);
1033 }
1034
1035 self.va.align_up_carry(self.level as int);
1036 }
1037 }
1038
1039 pub proof fn pop_level_owner_preserves_mappings(self)
1043 requires
1044 self.inv(),
1045 self.level < NR_LEVELS,
1046 self.in_locked_range(),
1047 ensures
1048 self.pop_level_owner().0@.mappings == self@.mappings,
1049 {
1050 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
1051
1052 let child = self.continuations[self.level - 1];
1053 let parent = self.continuations[self.level as int];
1054 let (restored_parent, _) = parent.restore(child);
1055 let popped = self.pop_level_owner().0;
1056 let child_subtree = child.as_subtree();
1057
1058 let r = restored_parent;
1059 let p = parent.put_child(child_subtree);
1060 assert forall|j: int| 0 <= j < r.children.len() implies r.children[j]
1061 == p.children[j] by {};
1062
1063 assert(restored_parent.view_mappings() == parent.put_child(child_subtree).view_mappings())
1064 by {};
1065
1066 parent.view_mappings_put_child(child_subtree);
1067 child.as_page_table_owner_preserves_view_mappings();
1068
1069 assert(popped.view_mappings() == self.view_mappings()) by {
1070 assert forall|m: Mapping|
1071 self.view_mappings().contains(m) implies popped.view_mappings().contains(m) by {
1072 let i = choose|i: int|
1073 self.level - 1 <= i < NR_LEVELS && (
1074 #[trigger] self.continuations[i]).view_mappings().contains(m);
1075 if i == self.level - 1 {
1076 assert(popped.continuations[self.level as int].view_mappings().contains(m));
1077 } else if i == self.level {
1078 assert(popped.continuations[self.level as int].view_mappings().contains(m));
1079 } else {
1080 assert(popped.continuations[i] == self.continuations[i]);
1081 }
1082 };
1083
1084 };
1085 }
1086
1087 pub proof fn move_forward_owner_preserves_mappings(self)
1088 requires
1089 self.inv(),
1090 self.in_locked_range(),
1091 ensures
1092 self.move_forward_owner_spec()@.mappings == self@.mappings,
1093 decreases NR_LEVELS - self.level,
1094 {
1095 broadcast use {CursorContinuation::group_lemmas, CursorOwner::group_lemmas};
1096
1097 if self.index() + 1 < NR_ENTRIES {
1098 let inc = self.inc_index();
1099 let result = inc.zero_below_level();
1100
1101 let old_cont = self.continuations[self.level - 1];
1102 let new_cont = old_cont.inc_index();
1103
1104 assert(result.view_mappings() == self.view_mappings()) by {
1105 assert forall|m: Mapping|
1106 self.view_mappings().contains(m) implies result.view_mappings().contains(m) by {
1107 let i = choose|i: int|
1108 self.level - 1 <= i < NR_LEVELS && (
1109 #[trigger] self.continuations[i]).view_mappings().contains(m);
1110 if i == self.level - 1 {
1111 assert(result.continuations[i].view_mappings().contains(m));
1112 } else {
1113 assert(result.continuations[i] == self.continuations[i]);
1114 }
1115 };
1116
1117 };
1118
1119 } else if self.level < NR_LEVELS {
1120 let popped = self.pop_level_owner().0;
1121
1122 self.pop_level_owner_preserves_mappings();
1123 popped.move_forward_owner_preserves_mappings();
1124 }
1125 }
1126}
1127
1128}