Skip to main content

ostd/specs/mm/page_table/cursor/
cursor_steps.rs

1use vstd::prelude::*;
2
3use vstd_extra::ghost_tree::*;
4use vstd_extra::ownership::*;
5
6use crate::mm::page_table::*;
7use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
8use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
9use crate::specs::arch::paging_consts::PagingConsts;
10use crate::specs::mm::Guards;
11use crate::specs::mm::Mapping;
12use crate::specs::mm::MetaRegionOwners;
13use crate::specs::mm::page_table::AbstractVaddr;
14use crate::specs::mm::page_table::cursor::owners::*;
15use crate::specs::mm::page_table::node::EntryOwner;
16use crate::specs::mm::page_table::owners::{INC_LEVELS, OwnerSubtree, PageTableOwner};
17
18use crate::mm::page_table::page_size_spec as page_size;
19use crate::specs::mm::frame::mapping::{frame_to_index, meta_to_frame};
20use crate::specs::mm::page_table::cursor::page_size_lemmas::{
21    lemma_page_size_divides, lemma_page_size_ge_page_size,
22};
23use vstd_extra::arithmetic::{
24    lemma_nat_align_down_sound, lemma_nat_align_down_within_block, nat_align_down, nat_align_up,
25};
26
27use core::ops::Range;
28
29verus! {
30
31/// Paths obtained by push_tail with different indices are different
32pub proof fn push_tail_different_indices_different_paths(
33    path: TreePath<NR_ENTRIES>,
34    i: usize,
35    j: usize,
36)
37    requires
38        path.inv(),
39        0 <= i < NR_ENTRIES,
40        0 <= j < NR_ENTRIES,
41        i != j,
42    ensures
43        path.push_tail(i) != path.push_tail(j),
44{
45    path.push_tail_property(i);
46    path.push_tail_property(j);
47    assert(path.push_tail(i).index(path.len() as int) == i as usize);
48    assert(path.push_tail(j).index(path.len() as int) == j as usize);
49    if path.push_tail(i) == path.push_tail(j) {
50        assert(i == j);  // Contradiction
51    }
52}
53
54/// Paths with different lengths are different
55pub proof fn different_length_different_paths(
56    path1: TreePath<NR_ENTRIES>,
57    path2: TreePath<NR_ENTRIES>,
58)
59    requires
60        path1.len() != path2.len(),
61    ensures
62        path1 != path2,
63{
64    // Trivial: if path1 == path2, then their lengths are equal
65    if path1 == path2 {
66        assert(path1.len() == path2.len());
67    }
68}
69
70/// A path obtained by push_tail has greater length than the original
71pub proof fn push_tail_increases_length(path: TreePath<NR_ENTRIES>, i: usize)
72    requires
73        path.inv(),
74        0 <= i < NR_ENTRIES,
75    ensures
76        path.push_tail(i).len() > path.len(),
77{
78    path.push_tail_property(i);
79}
80
81/// Upgrade `node_unlocked_except` to `node_unlocked` on a subtree where the excepted
82/// entry cannot appear. The precondition `path == subtree.value.path` ties structural
83/// positions to entry paths. `excepted_path` must differ from all descendant paths,
84/// which is guaranteed when `excepted_path != path` and `excepted_path` is not an
85/// extension of `path` (all descendants have paths extending `path`).
86pub proof fn subtree_unlock_upgrade<'rcu, C: PageTableConfig>(
87    subtree: OwnerSubtree<C>,
88    path: TreePath<NR_ENTRIES>,
89    guards: Guards<'rcu>,
90    regions: MetaRegionOwners,
91    excepted_addr: usize,
92    excepted_path: TreePath<NR_ENTRIES>,
93)
94    requires
95        subtree.inv(),
96        PageTableOwner::<C>(subtree).pt_inv(),
97        subtree.tree_predicate_map(path, PageTableOwner::<C>::metaregion_sound_pred(regions)),
98        subtree.tree_predicate_map(
99            path,
100            CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr),
101        ),
102        regions.slot_owners[frame_to_index(meta_to_frame(excepted_addr))].paths_in_pt
103            == set![excepted_path],
104        // Structural path == value path
105        path == subtree.value.path,
106        path.inv(),
107        // excepted_path does not match this subtree root
108        path != excepted_path,
109        // excepted_path is not a descendant (all descendants extend path, so if
110        // excepted_path.len() <= path.len() it can't be a descendant; otherwise
111        // it must diverge at some index below path.len())
112        excepted_path.len() <= path.len() || (exists|k: int|
113            0 <= k < path.len() && #[trigger] excepted_path.index(k) != path.index(k)),
114    ensures
115        subtree.tree_predicate_map(path, CursorOwner::<'rcu, C>::node_unlocked(guards)),
116    decreases INC_LEVELS - subtree.level,
117{
118    let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
119    let g = CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr);
120    let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
121
122    assert(f(subtree.value, path));
123    assert(g(subtree.value, path));
124    if subtree.value.is_node() {
125        if subtree.value.node.unwrap().meta_addr_self() == excepted_addr {
126            // addr == excepted_addr contradicts path != excepted_path
127            // via metaregion_sound's singleton paths_in_pt.
128            let idx = frame_to_index(meta_to_frame(excepted_addr));
129            assert(subtree.value.metaregion_sound(regions));
130            assert(regions.slot_owners[idx].paths_in_pt == set![subtree.value.path]);
131            assert(set![subtree.value.path].contains(excepted_path));
132            assert(false);
133        }
134    }
135    assert(h(subtree.value, path));
136
137    if subtree.level < INC_LEVELS - 1 && subtree.value.is_node() {
138        assert forall|i: int|
139            #![trigger subtree.children[i]]
140            0 <= i < subtree.children.len()
141                && subtree.children[i] is Some implies subtree.children[i].unwrap().tree_predicate_map(
142        path.push_tail(i as usize), h) by {
143            let child = subtree.children[i].unwrap();
144            subtree.map_unroll_once(path, f, i);
145            subtree.map_unroll_once(path, g, i);
146
147            PageTableOwner::<C>(subtree).pt_inv_unroll(i);
148            let child_path = path.push_tail(i as usize);
149            path.push_tail_property(i as usize);
150
151            assert(child_path != excepted_path) by {
152                if excepted_path.len() <= path.len() {
153                } else {
154                    let k = choose|k: int|
155                        0 <= k < path.len() && #[trigger] excepted_path.index(k) != path.index(k);
156                    assert(child_path.index(k) == path.index(k));
157                }
158            };
159
160            assert(excepted_path.len() <= child_path.len() || (exists|k: int|
161                0 <= k < child_path.len() && #[trigger] excepted_path.index(k) != child_path.index(
162                    k,
163                ))) by {
164                if excepted_path.len() <= path.len() {
165                } else {
166                    let k = choose|k: int|
167                        0 <= k < path.len() && #[trigger] excepted_path.index(k) != path.index(k);
168                    assert(child_path.index(k) == path.index(k));
169                }
170            };
171
172            subtree_unlock_upgrade(
173                child,
174                child_path,
175                guards,
176                regions,
177                excepted_addr,
178                excepted_path,
179            );
180        };
181    } else if subtree.level < INC_LEVELS - 1 && !subtree.value.is_node() {
182        // Non-node: pt_inv gives children[i] is None, so tree_predicate_map
183        // has no children to recurse into.
184        assert forall|i: int|
185            #![trigger subtree.children[i]]
186            0 <= i < subtree.children.len()
187                && subtree.children[i] is Some implies subtree.children[i].unwrap().tree_predicate_map(
188        path.push_tail(i as usize), h) by {
189            PageTableOwner::<C>(subtree).pt_inv_non_node(i);
190        };
191    }
192}
193
194impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
195    /// The number of steps it will take to walk through every node of a full
196    /// page table at level `level`
197    pub open spec fn max_steps_subtree(level: usize) -> nat
198        decreases level,
199    {
200        if level <= 1 {
201            NR_ENTRIES as nat
202        } else {
203            (NR_ENTRIES as nat) * (Self::max_steps_subtree((level - 1) as usize) + 1)
204        }
205    }
206
207    /// Per-level "above-current" contribution: count `NR_ENTRIES - cont.idx - 1`
208    /// at every level (the entry at `cont.idx` is being descended into; its
209    /// work is captured at lower levels in the recursion). `max_steps()`
210    /// adds back one `subtree(self.level)` to count the current level's
211    /// in-progress entry.
212    ///
213    /// The base case is `level > NR_LEVELS` (not `== NR_LEVELS`) so that
214    /// `level == NR_LEVELS` itself contributes a non-zero term. This avoids
215    /// degenerate behavior at the root: without it, `max_steps` collapses
216    /// to 0 at the root and `push_level` from the root cannot decrease
217    /// (and the popped_too_high `q` at NR_LEVELS would dominate `self`).
218    pub open spec fn max_steps_partial(self, level: usize) -> nat
219        decreases NR_LEVELS + 1 - level,
220        when level <= NR_LEVELS + 1
221    {
222        if level > NR_LEVELS {
223            0
224        } else {
225            let cont = self.continuations[(level - 1) as int];
226            let count: nat = (NR_ENTRIES - cont.idx - 1) as nat;
227            let steps = Self::max_steps_subtree(level) * count;
228            let remaining_steps = self.max_steps_partial((level + 1) as usize);
229            steps + remaining_steps
230        }
231    }
232
233    pub open spec fn max_steps(self) -> nat {
234        (self.max_steps_partial(self.level as usize) + Self::max_steps_subtree(
235            self.level as usize,
236        )) as nat
237    }
238
239    pub proof fn max_steps_subtree_positive(level: usize)
240        ensures
241            Self::max_steps_subtree(level) > 0,
242        decreases level,
243    {
244        if level > 1 {
245            Self::max_steps_subtree_positive((level - 1) as usize);
246        }
247    }
248
249    /// Two owners with the same idx values from `start` upward have the same max_steps_partial.
250    pub proof fn max_steps_partial_eq(self, other: Self, start: usize)
251        requires
252            1 <= start <= NR_LEVELS + 1,
253            forall|k: int|
254                start - 1 <= k < NR_LEVELS ==> #[trigger] self.continuations[k].idx
255                    == other.continuations[k].idx,
256        ensures
257            self.max_steps_partial(start) == other.max_steps_partial(start),
258        decreases NR_LEVELS + 1 - start,
259    {
260        if start <= NR_LEVELS {
261            self.max_steps_partial_eq(other, (start + 1) as usize);
262        }
263    }
264
265    pub proof fn max_steps_partial_inv(self, other: Self, level: usize)
266        requires
267            self.inv(),
268            other.inv(),
269            self.level == other.level,
270            self.level <= level <= NR_LEVELS + 1,
271            forall|i: int|
272                #![trigger self.continuations[i].idx]
273                #![trigger other.continuations[i].idx]
274                self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].idx
275                    == other.continuations[i].idx,
276        ensures
277            self.max_steps_partial(level) == other.max_steps_partial(level),
278        decreases NR_LEVELS + 1 - level,
279    {
280        if level <= NR_LEVELS {
281            self.max_steps_partial_inv(other, (level + 1) as usize);
282        }
283    }
284
285    pub open spec fn push_level_owner(self, guard: PageTableGuard<'rcu, C>) -> Self {
286        let cont = self.continuations[self.level - 1];
287        let (child, cont) = cont.make_cont(self.va.index[self.level - 2] as usize, guard);
288        let new_continuations = self.continuations.insert(self.level - 1, cont);
289        let new_continuations = new_continuations.insert(self.level - 2, child);
290
291        let new_level = (self.level - 1) as u8;
292        Self { continuations: new_continuations, level: new_level, popped_too_high: false, ..self }
293    }
294
295    pub proof fn push_level_owner_decreases_steps(self, guard: PageTableGuard<'rcu, C>)
296        requires
297            self.inv(),
298            self.level > 1,
299        ensures
300            self.push_level_owner(guard).max_steps() < self.max_steps(),
301    {
302        let new_self = self.push_level_owner(guard);
303        let l = self.level as usize;
304        let lm1 = (self.level - 1) as usize;
305        // Continuations agree at indices [l-1, NR_LEVELS): only [l-2] changed.
306        new_self.max_steps_partial_eq(self, l);
307        // va.index[l-2] < NR_ENTRIES (from va.inv()).
308        assert(self.va.index.contains_key(self.level - 2));
309        let new_child = new_self.continuations[lm1 - 1];
310        assert(new_child.idx < NR_ENTRIES);
311        Self::max_steps_subtree_positive(lm1);
312        Self::max_steps_subtree_positive(l);
313        // subtree(l) == NR * (subtree(lm1) + 1) (from def of max_steps_subtree, l > 1).
314        assert(Self::max_steps_subtree(l) == (NR_ENTRIES as nat) * (Self::max_steps_subtree(lm1)
315            + 1));
316        // subtree(lm1) * (NR - new_child.idx) <= subtree(lm1) * NR < subtree(l).
317        vstd::arithmetic::mul::lemma_mul_inequality(
318            (NR_ENTRIES - new_child.idx) as int,
319            NR_ENTRIES as int,
320            Self::max_steps_subtree(lm1) as int,
321        );
322        vstd::arithmetic::mul::lemma_mul_is_distributive_add(
323            Self::max_steps_subtree(lm1) as int,
324            (NR_ENTRIES - new_child.idx - 1) as int,
325            1,
326        );
327        vstd::arithmetic::mul::lemma_mul_is_commutative(
328            (NR_ENTRIES - new_child.idx) as int,
329            Self::max_steps_subtree(lm1) as int,
330        );
331        vstd::arithmetic::mul::lemma_mul_is_commutative(
332            NR_ENTRIES as int,
333            Self::max_steps_subtree(lm1) as int,
334        );
335        vstd::arithmetic::mul::lemma_mul_is_distributive_add(
336            NR_ENTRIES as int,
337            Self::max_steps_subtree(lm1) as int,
338            1,
339        );
340    }
341
342    pub proof fn push_level_owner_preserves_va(self, guard: PageTableGuard<'rcu, C>)
343        requires
344            self.inv(),
345            self.level > 1,
346        ensures
347            self.push_level_owner(guard).va == self.va,
348            self.push_level_owner(guard).continuations[self.level - 2].idx
349                == self.va.index[self.level - 2],
350    {
351        assert(self.va.index.contains_key(self.level - 2));
352    }
353
354    pub proof fn push_level_owner_preserves_mappings(self, guard: PageTableGuard<'rcu, C>)
355        requires
356            self.inv(),
357            self.level > 1,
358            self.cur_entry_owner().is_node(),
359        ensures
360            self.push_level_owner(guard)@.mappings == self@.mappings,
361    {
362        let new_owner = self.push_level_owner(guard);
363        let old_cont = self.continuations[self.level - 1];
364        let (child_cont, modified_cont) = old_cont.make_cont(
365            self.va.index[self.level - 2] as usize,
366            guard,
367        );
368
369        assert(old_cont.all_some());
370        old_cont.view_mappings_take_child();
371
372        let taken = old_cont.take_child().1;
373
374        assert(modified_cont.children =~= taken.children) by {
375            assert forall|j: int|
376                0 <= j < modified_cont.children.len() implies modified_cont.children[j]
377                == taken.children[j] by {
378                if j == old_cont.idx as int {
379                    assert(modified_cont.children[j] is None);
380                    assert(taken.children[j] is None);
381                } else {
382                    assert(modified_cont.children[j] == old_cont.children[j]);
383                }
384            };
385        };
386        assert(modified_cont.view_mappings() =~= taken.view_mappings()) by {
387            assert(modified_cont.path() == taken.path());
388        };
389
390        old_cont.inv_children_rel_unroll(old_cont.idx as int);
391        let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
392        let child_path = old_cont.path().push_tail(old_cont.idx as usize);
393        assert(child_cont.children == child_subtree.children);
394        assert(child_cont.path() == child_path);
395        assert(child_subtree.value.is_node());
396        assert(child_path.len() < INC_LEVELS - 1) by {
397            assert(old_cont.tree_level < INC_LEVELS - 1);
398            assert(old_cont.entry_own.inv_base());
399            old_cont.path().push_tail_property(old_cont.idx as usize);
400        };
401        old_cont.inv_children_unroll(old_cont.idx as int);
402        assert(child_subtree.inv());
403        let pto = PageTableOwner(child_subtree);
404        assert(pto.view_rec(child_path) =~= child_cont.view_mappings()) by {
405            assert forall|m: Mapping| #[trigger]
406                child_cont.view_mappings().contains(m) implies pto.view_rec(child_path).contains(
407                m,
408            ) by {
409                let j = choose|j: int|
410                    #![auto]
411                    0 <= j < child_cont.children.len() && child_cont.children[j] is Some
412                        && PageTableOwner(child_cont.children[j].unwrap()).view_rec(
413                        child_cont.path().push_tail(j as usize),
414                    ).contains(m);
415                assert(pto.0.children[j] is Some);
416                assert(pto.0.children[j] == child_cont.children[j]);
417            };
418            assert forall|m: Mapping|
419                pto.view_rec(child_path).contains(
420                    m,
421                ) implies #[trigger] child_cont.view_mappings().contains(m) by {
422                let j = choose|j: int|
423                    #![trigger pto.0.children[j]]
424                    0 <= j < pto.0.children.len() && pto.0.children[j] is Some && PageTableOwner(
425                        pto.0.children[j].unwrap(),
426                    ).view_rec(child_path.push_tail(j as usize)).contains(m);
427                assert(child_cont.children[j] == pto.0.children[j]);
428                assert(child_cont.children[j] is Some);
429            };
430        };
431        assert(child_cont.view_mappings() =~= old_cont.view_mappings_take_child_spec());
432
433        assert forall|m: Mapping|
434            self.view_mappings().contains(m) implies new_owner.view_mappings().contains(m) by {
435            let i = choose|i: int|
436                self.level - 1 <= i < NR_LEVELS && (
437                #[trigger] self.continuations[i]).view_mappings().contains(m);
438            if i == self.level - 1 {
439                if old_cont.view_mappings_take_child_spec().contains(m) {
440                    assert(new_owner.continuations[self.level - 2].view_mappings().contains(m));
441                } else {
442                    assert(taken.view_mappings().contains(m));
443                    assert(modified_cont.view_mappings().contains(m));
444                    assert(new_owner.continuations[self.level - 1].view_mappings().contains(m));
445                }
446            } else {
447                assert(new_owner.continuations[i] == self.continuations[i]);
448            }
449        };
450        assert forall|m: Mapping|
451            new_owner.view_mappings().contains(m) implies self.view_mappings().contains(m) by {
452            let i = choose|i: int|
453                new_owner.level - 1 <= i < NR_LEVELS && (
454                #[trigger] new_owner.continuations[i]).view_mappings().contains(m);
455            if i == self.level - 2 {
456                assert(child_cont.view_mappings().contains(m));
457                assert(old_cont.view_mappings_take_child_spec().contains(m));
458                // view_mappings_take_child_spec() = PTO(children[idx]).view_rec(...)
459                // The containment in view_mappings follows directly for i == idx.
460                let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
461                assert(PageTableOwner(child_subtree).view_rec(
462                    old_cont.path().push_tail(old_cont.idx as usize),
463                ).contains(m));
464                assert(old_cont.view_mappings().contains(m));
465                assert(self.continuations[self.level - 1].view_mappings().contains(m));
466            } else if i == self.level - 1 {
467                assert(modified_cont.view_mappings().contains(m));
468                assert(taken.view_mappings().contains(m));
469                // taken.view_mappings() == old_cont.view_mappings() - child_spec ⊆ view_mappings.
470                assert(old_cont.view_mappings().contains(m));
471                assert(self.continuations[self.level - 1].view_mappings().contains(m));
472            } else {
473                assert(self.continuations[i] == new_owner.continuations[i]);
474            }
475        };
476        assert(new_owner.view_mappings() =~= self.view_mappings());
477    }
478
479    pub proof fn push_level_owner_preserves_inv(self, guard: PageTableGuard<'rcu, C>)
480        requires
481            self.inv(),
482            self.level > 1,
483            !self.popped_too_high,
484            self.level <= self.guard_level,
485            self.in_locked_range(),
486            // The current entry is a node (we're descending into it)
487            self.cur_entry_owner().is_node(),
488            // The child node's guard relates to the new guard
489            self.cur_entry_owner().node.unwrap().relate_guard(guard),
490            // Guard distinctness: the new guard points to a different node than all existing continuations
491            forall|i: int|
492                #![trigger self.continuations[i]]
493                self.level - 1 <= i < NR_LEVELS
494                    ==> self.continuations[i].guard.inner.inner@.ptr.addr()
495                    != guard.inner.inner@.ptr.addr(),
496        ensures
497            self.push_level_owner(guard).inv(),
498    {
499        // locking-work: when self.level == self.guard_level, self.inv() does
500        // not supply va.index[guard_level-1] == prefix.index[guard_level-1]
501        // (the conjunct at owners.rs:481-482 requires strict level < guard_level).
502        // After push_level, the new level < guard_level triggers that conjunct.
503        // Derive it from in_locked_range() for all cases.
504        self.in_locked_range_guard_index_eq_prefix();
505
506        let new_owner = self.push_level_owner(guard);
507        let new_level = (self.level - 1) as u8;
508
509        let old_cont = self.continuations[self.level - 1];
510        old_cont.inv_children_unroll(old_cont.idx as int);
511        let child_node = old_cont.children[old_cont.idx as int].unwrap();
512        let (child, modified_cont) = old_cont.make_cont(
513            self.va.index[self.level - 2] as usize,
514            guard,
515        );
516
517        old_cont.inv_children_rel_unroll(old_cont.idx as int);
518        assert(child.entry_own == child_node.value);
519        assert(child.entry_own == self.cur_entry_owner());
520        assert(child.children == child_node.children);
521        assert(child.tree_level == old_cont.tree_level + 1);
522
523        assert(self.va.inv());
524        assert(self.va.index.contains_key(self.level - 2));
525        assert(0 <= self.va.index[self.level - 2] < NR_ENTRIES);
526        assert(child.idx == self.va.index[self.level - 2] as usize);
527
528        assert(child.entry_own.inv()) by {
529            old_cont.inv_children_unroll(old_cont.idx as int);
530        };
531
532        assert(child.entry_own.path.len() == old_cont.entry_own.node.unwrap().tree_level + 1);
533        assert(old_cont.entry_own.node.unwrap().tree_level == old_cont.tree_level) by {
534            assert(old_cont.tree_level == INC_LEVELS - old_cont.level() - 1);
535        };
536        assert(child.entry_own.path.len() == child.tree_level) by {
537            assert(child.tree_level == old_cont.tree_level + 1);
538        };
539
540        assert(child.entry_own.node.unwrap().tree_level == child.entry_own.path.len()) by {
541            assert(child.children[0] is Some);
542            let gc = child.children[0].unwrap();
543            assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
544                child.entry_own,
545                0,
546                Some(gc.value),
547            ));
548            assert(gc.value.path.len() == child.entry_own.node.unwrap().tree_level + 1);
549            assert(gc.value.path == child.entry_own.path.push_tail(0usize));
550            assert(child.entry_own.inv_base());
551            assert(child.entry_own.path.inv());
552            child.entry_own.path.push_tail_property(0usize);
553            assert(child.entry_own.path.push_tail(0usize).len() == child.entry_own.path.len() + 1);
554        };
555
556        assert(child.tree_level == child.entry_own.node.unwrap().tree_level);
557        assert(child.tree_level == INC_LEVELS - child.level() - 1);
558
559        assert(child.inv_children()) by {
560            assert forall|j: int|
561                0 <= j < child.children.len()
562                    && #[trigger] child.children[j] is Some implies child.children[j].unwrap().inv() by {
563                assert(child.children[j] == child_node.children[j]);
564                old_cont.inv_children_unroll(old_cont.idx as int);
565            };
566        };
567        assert(child.inv_children_rel()) by {
568            assert forall|j: int|
569                0 <= j < NR_ENTRIES && #[trigger] child.children[j] is Some implies {
570                &&& child.children[j].unwrap().value.parent_level == child.level()
571                &&& child.children[j].unwrap().level == child.tree_level + 1
572                &&& !child.children[j].unwrap().value.in_scope
573                &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
574                    child.entry_own,
575                    j,
576                    Some(child.children[j].unwrap().value),
577                )
578                &&& child.children[j].unwrap().value.path == child.path().push_tail(j as usize)
579            } by {
580                let gc = child.children[j].unwrap();
581                assert(child.children[j] == child_node.children[j]);
582                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
583                    child.entry_own,
584                    j,
585                    Some(gc.value),
586                ));
587                child.inv_children_unroll(j);
588                assert(gc.inv());
589            };
590        };
591        assert(child.inv());
592
593        assert(new_owner.continuations[new_owner.level - 1].all_some()) by {
594            assert(new_owner.continuations[new_owner.level - 1] == child);
595            assert forall|j: int| 0 <= j < NR_ENTRIES implies child.children[j] is Some by {
596                if child.children[j] is None {
597                    assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
598                        child.entry_own,
599                        j,
600                        None,
601                    ));
602                }
603            };
604        };
605
606        assert(modified_cont.all_but_index_some()) by {
607            assert(modified_cont.children[modified_cont.idx as int] is None);
608            assert forall|i: int|
609                0 <= i < modified_cont.idx implies modified_cont.children[i] is Some by {
610                assert(modified_cont.children[i] == old_cont.children[i]);
611            };
612            assert forall|i: int|
613                modified_cont.idx < i < NR_ENTRIES implies modified_cont.children[i] is Some by {
614                assert(modified_cont.children[i] == old_cont.children[i]);
615            };
616        };
617
618        assert(forall|i: int|
619            new_owner.level <= i < NR_LEVELS ==> {
620                (#[trigger] new_owner.continuations[i]).all_but_index_some()
621            }) by {
622            assert forall|i: int| new_owner.level <= i < NR_LEVELS implies (
623            #[trigger] new_owner.continuations[i]).all_but_index_some() by {
624                if i == self.level - 1 {
625                    assert(new_owner.continuations[i] == modified_cont);
626                } else {
627                    // i >= self.level, unchanged from old state
628                    assert(new_owner.continuations[i] == self.continuations[i]);
629                }
630            };
631        };
632
633        // Flattened: hoist inv_children and inv_children_rel proofs so the
634        // inner `assert forall` blocks live at depth 2.
635        assert(modified_cont.children.len() == NR_ENTRIES);
636        assert(0 <= modified_cont.idx < NR_ENTRIES);
637        assert(modified_cont.inv_children()) by {
638            assert forall|i: int|
639                0 <= i < modified_cont.children.len()
640                    && #[trigger] modified_cont.children[i] is Some implies modified_cont.children[i].unwrap().inv() by {
641                assert(i != modified_cont.idx);
642                assert(modified_cont.children[i] == old_cont.children[i]);
643                old_cont.inv_children_unroll(i);
644            };
645        };
646        assert(modified_cont.inv_children_rel()) by {
647            assert forall|i: int|
648                0 <= i < NR_ENTRIES && #[trigger] modified_cont.children[i] is Some implies {
649                &&& modified_cont.children[i].unwrap().value.parent_level == modified_cont.level()
650                &&& modified_cont.children[i].unwrap().level == modified_cont.tree_level + 1
651                &&& !modified_cont.children[i].unwrap().value.in_scope
652                &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
653                    modified_cont.entry_own,
654                    i,
655                    Some(modified_cont.children[i].unwrap().value),
656                )
657                &&& modified_cont.children[i].unwrap().value.path == modified_cont.path().push_tail(
658                    i as usize,
659                )
660            } by {
661                assert(i != modified_cont.idx);
662                assert(modified_cont.children[i] == old_cont.children[i]);
663                assert(old_cont.inv_children_rel());
664            };
665        };
666        assert(modified_cont.entry_own.is_node());
667        assert(modified_cont.entry_own.inv());
668        assert(modified_cont.entry_own.node.unwrap().relate_guard(modified_cont.guard));
669        assert(modified_cont.tree_level == INC_LEVELS - modified_cont.level() - 1);
670        assert(modified_cont.tree_level < INC_LEVELS - 1);
671        assert(modified_cont.path().len() == modified_cont.tree_level);
672        assert(modified_cont.inv());
673
674        assert(new_owner.level <= 4 ==> {
675            &&& new_owner.continuations.contains_key(3)
676            &&& new_owner.continuations[3].inv()
677            &&& new_owner.continuations[3].level() == 4
678            &&& new_owner.continuations[3].entry_own.parent_level == 5
679            &&& new_owner.va.index[3] == new_owner.continuations[3].idx
680        }) by {
681            if new_owner.level <= 4 {
682                if self.level == 4 {
683                    assert(new_owner.continuations[3] == modified_cont);
684                } else {
685                    assert(new_owner.continuations[3] == self.continuations[3]);
686                }
687            }
688        };
689
690        // Level 3 condition: new_level <= 3 ==> continuations[2] ...
691        assert(new_owner.level <= 3 ==> {
692            &&& new_owner.continuations.contains_key(2)
693            &&& new_owner.continuations[2].inv()
694            &&& new_owner.continuations[2].level() == 3
695            &&& new_owner.continuations[2].entry_own.parent_level == 4
696            &&& new_owner.va.index[2] == new_owner.continuations[2].idx
697            &&& new_owner.continuations[2].guard.inner.inner@.ptr.addr()
698                != new_owner.continuations[3].guard.inner.inner@.ptr.addr()
699            &&& new_owner.continuations[2].path() == new_owner.continuations[3].path().push_tail(
700                new_owner.continuations[3].idx as usize,
701            )
702            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
703                new_owner.continuations[3].entry_own,
704                new_owner.continuations[3].idx as int,
705                Some(new_owner.continuations[2].entry_own),
706            )
707        }) by {
708            if new_owner.level <= 3 {
709                if self.level == 4 {
710                    assert(self.va.index.contains_key(2));
711                    assert(new_owner.continuations[2].guard == guard);
712                    assert(new_owner.continuations[3] == modified_cont);
713                    assert(modified_cont.guard == old_cont.guard);
714                    // guard distinctness
715                    assert(new_owner.continuations[2].guard.inner.inner@.ptr.addr()
716                        != new_owner.continuations[3].guard.inner.inner@.ptr.addr()) by {
717                        assert(self.continuations[self.level - 1].guard.inner.inner@.ptr.addr()
718                            != guard.inner.inner@.ptr.addr());
719                    };
720                    // path consistency: child.path() == modified_cont.path().push_tail(modified_cont.idx)
721                    assert(new_owner.continuations[2].path()
722                        == new_owner.continuations[3].path().push_tail(
723                        new_owner.continuations[3].idx as usize,
724                    )) by {
725                        assert(modified_cont.path() == old_cont.path());
726                        assert(modified_cont.idx == old_cont.idx);
727                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
728                    };
729                    // PTE consistency: from old_cont.inv_children_rel at idx
730                    assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
731                        new_owner.continuations[3].entry_own,
732                        new_owner.continuations[3].idx as int,
733                        Some(new_owner.continuations[2].entry_own),
734                    )) by {
735                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
736                    };
737                } else {
738                    // self.level <= 3: from self.inv()
739                }
740            }
741        };
742
743        // Level 2 condition: new_level <= 2 ==> continuations[1] ...
744        assert(new_owner.level <= 2 ==> {
745            &&& new_owner.continuations.contains_key(1)
746            &&& new_owner.continuations[1].inv()
747            &&& new_owner.continuations[1].level() == 2
748            &&& new_owner.continuations[1].entry_own.parent_level == 3
749            &&& new_owner.va.index[1] == new_owner.continuations[1].idx
750            &&& new_owner.continuations[1].guard.inner.inner@.ptr.addr()
751                != new_owner.continuations[2].guard.inner.inner@.ptr.addr()
752            &&& new_owner.continuations[1].guard.inner.inner@.ptr.addr()
753                != new_owner.continuations[3].guard.inner.inner@.ptr.addr()
754            &&& new_owner.continuations[1].path() == new_owner.continuations[2].path().push_tail(
755                new_owner.continuations[2].idx as usize,
756            )
757            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
758                new_owner.continuations[2].entry_own,
759                new_owner.continuations[2].idx as int,
760                Some(new_owner.continuations[1].entry_own),
761            )
762        }) by {
763            if new_owner.level <= 2 {
764                if self.level == 3 {
765                    assert(self.va.index.contains_key(1));
766                    assert(new_owner.continuations[1].guard == guard);
767                    assert(new_owner.continuations[2] == modified_cont);
768                    assert(modified_cont.guard == old_cont.guard);
769
770                    assert(new_owner.continuations[1].guard.inner.inner@.ptr.addr()
771                        != new_owner.continuations[2].guard.inner.inner@.ptr.addr()) by {
772                        assert(self.continuations[2].guard.inner.inner@.ptr.addr()
773                            != guard.inner.inner@.ptr.addr());
774                    };
775                    assert(new_owner.continuations[1].guard.inner.inner@.ptr.addr()
776                        != new_owner.continuations[3].guard.inner.inner@.ptr.addr()) by {
777                        assert(self.continuations[3].guard.inner.inner@.ptr.addr()
778                            != guard.inner.inner@.ptr.addr());
779                    };
780                    // path: child.path() == modified_cont.path().push_tail(modified_cont.idx)
781                    assert(new_owner.continuations[1].path()
782                        == new_owner.continuations[2].path().push_tail(
783                        new_owner.continuations[2].idx as usize,
784                    )) by {
785                        assert(modified_cont.path() == old_cont.path());
786                        assert(modified_cont.idx == old_cont.idx);
787                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
788                    };
789                    // child properties: level, parent_level from tree_level
790                    assert(old_cont.level() == 3);
791                    assert(child.entry_own.parent_level == 3) by {
792                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
793                    };
794                    // PTE consistency: from old_cont.inv_children_rel at idx
795                    assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
796                        new_owner.continuations[2].entry_own,
797                        new_owner.continuations[2].idx as int,
798                        Some(new_owner.continuations[1].entry_own),
799                    )) by {
800                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
801                    };
802                } else {
803                    // self.level == 2: both continuations unchanged
804                }
805            }
806        };
807
808        // Level 1 condition: new_level == 1 ==> continuations[0] exists and is valid
809        assert(new_owner.level == 1 ==> {
810            &&& new_owner.continuations.contains_key(0)
811            &&& new_owner.continuations[0].inv()
812            &&& new_owner.continuations[0].level() == 1
813            &&& new_owner.continuations[0].entry_own.parent_level == 2
814            &&& new_owner.va.index[0] == new_owner.continuations[0].idx
815            &&& new_owner.continuations[0].guard.inner.inner@.ptr.addr()
816                != new_owner.continuations[1].guard.inner.inner@.ptr.addr()
817            &&& new_owner.continuations[0].guard.inner.inner@.ptr.addr()
818                != new_owner.continuations[2].guard.inner.inner@.ptr.addr()
819            &&& new_owner.continuations[0].guard.inner.inner@.ptr.addr()
820                != new_owner.continuations[3].guard.inner.inner@.ptr.addr()
821            &&& new_owner.continuations[0].path() == new_owner.continuations[1].path().push_tail(
822                new_owner.continuations[1].idx as usize,
823            )
824            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
825                new_owner.continuations[1].entry_own,
826                new_owner.continuations[1].idx as int,
827                Some(new_owner.continuations[0].entry_own),
828            )
829        }) by {
830            if new_owner.level == 1 {
831                // self.level == 2, new_level == 1
832                assert(new_owner.continuations[0].guard == guard);
833                assert(new_owner.continuations[1] == modified_cont);
834                assert(modified_cont.guard == old_cont.guard);
835
836                // Guard distinctness from precondition
837                assert(self.continuations[1].guard.inner.inner@.ptr.addr()
838                    != guard.inner.inner@.ptr.addr());
839                assert(self.continuations[2].guard.inner.inner@.ptr.addr()
840                    != guard.inner.inner@.ptr.addr());
841                assert(self.continuations[3].guard.inner.inner@.ptr.addr()
842                    != guard.inner.inner@.ptr.addr());
843
844                // child.level() == 1: from tree_level arithmetic
845                // old_cont = continuations[1], old_cont.level() == 2 (from self.inv() level <= 2)
846                assert(old_cont.level() == 2);
847                // child.tree_level == old_cont.tree_level + 1
848                // old_cont.tree_level == INC_LEVELS - 2 - 1 == 2
849                // child.tree_level == 3
850                // child.level() == INC_LEVELS - child.tree_level - 1 == 5 - 3 - 1 == 1
851                assert(child.tree_level == INC_LEVELS - child.level() - 1);
852
853                // parent_level == 2: from inv_children_rel on old_cont
854                assert(child.entry_own.parent_level == 2) by {
855                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
856                    assert(child.entry_own.parent_level == old_cont.level());
857                };
858
859                // idx match
860                assert(new_owner.va.index[0] == child.idx);
861
862                // path consistency: child.path() == modified_cont.path().push_tail(modified_cont.idx)
863                assert(child.path() == modified_cont.path().push_tail(modified_cont.idx as usize))
864                    by {
865                    assert(modified_cont.path() == old_cont.path());
866                    assert(modified_cont.idx == old_cont.idx);
867                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
868                    assert(child.entry_own.path == old_cont.path().push_tail(
869                        old_cont.idx as usize,
870                    ));
871                };
872
873                // PTE consistency: from old_cont.inv_children_rel at idx
874                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
875                    new_owner.continuations[1].entry_own,
876                    new_owner.continuations[1].idx as int,
877                    Some(new_owner.continuations[0].entry_own),
878                )) by {
879                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
880                };
881            }
882        };
883
884    }
885
886    pub proof fn push_level_owner_preserves_invs(
887        self,
888        guard: PageTableGuard<'rcu, C>,
889        regions: MetaRegionOwners,
890        guards: Guards<'rcu>,
891    )
892        requires
893            self.inv(),
894            self.level > 1,
895            !self.popped_too_high,
896            self.level <= self.guard_level,
897            self.in_locked_range(),
898            self.only_current_locked(guards),
899            self.nodes_locked(guards),
900            self.metaregion_sound(regions),
901            // The current entry is a node (we're descending into it)
902            self.cur_entry_owner().is_node(),
903            // The child node's guard relates to the new guard
904            self.cur_entry_owner().node.unwrap().relate_guard(guard),
905            // The new guard must be locked in guards
906            guards.lock_held(guard.inner.inner@.ptr.addr()),
907        ensures
908            self.push_level_owner(guard).inv(),
909            self.push_level_owner(guard).children_not_locked(guards),
910            self.push_level_owner(guard).nodes_locked(guards),
911            self.push_level_owner(guard).metaregion_sound(regions),
912    {
913        if self.level == self.guard_level {
914            self.in_locked_range_guard_index_eq_prefix();
915        }
916        reveal(CursorContinuation::inv_children);
917        let new_owner = self.push_level_owner(guard);
918        let old_cont = self.continuations[self.level - 1];
919        old_cont.inv_children_unroll_all();
920        let (child_cont, modified_cont) = old_cont.make_cont(
921            self.va.index[self.level - 2] as usize,
922            guard,
923        );
924
925        let cur_entry = self.cur_entry_owner();
926        let cur_entry_addr = cur_entry.node.unwrap().meta_addr_self();
927        let cur_entry_path = old_cont.path().push_tail(old_cont.idx as usize);
928        self.cont_entries_metaregion(regions);
929
930        assert forall|i: int|
931            #![trigger self.continuations[i]]
932            self.level - 1 <= i
933                < NR_LEVELS implies self.continuations[i].guard.inner.inner@.ptr.addr()
934            != guard.inner.inner@.ptr.addr() by {
935            let cont_i = self.continuations[i];
936
937            if cont_i.guard.inner.inner@.ptr.addr() == guard.inner.inner@.ptr.addr() {
938                let addr = cont_i.entry_own.node.unwrap().meta_addr_self();
939                assert(addr == cur_entry.node.unwrap().meta_addr_self());
940                let idx = frame_to_index(meta_to_frame(addr));
941                assert(regions.slot_owners[idx].paths_in_pt == set![cont_i.path()]);
942                assert(regions.slot_owners[idx].paths_in_pt == set![cur_entry_path]);
943                assert(set![cont_i.path()].contains(cur_entry_path));
944
945                assert(cur_entry_path.len() == old_cont.tree_level + 1) by {
946                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
947                    old_cont.entry_own.path.push_tail_property(old_cont.idx as usize);
948                };
949                assert(cont_i.tree_level <= old_cont.tree_level) by {
950                    if self.level as int == 1 {
951                        assert(old_cont.level() == 1);
952                    } else if self.level as int == 2 {
953                        assert(old_cont.level() == 2);
954                    } else if self.level as int == 3 {
955                        assert(old_cont.level() == 3);
956                    } else {
957                        assert(old_cont.level() == 4);
958                    }
959                };
960                assert(false);
961            }
962        };
963        self.push_level_owner_preserves_inv(guard);
964
965        let excepted_idx = frame_to_index(meta_to_frame(cur_entry_addr));
966        assert(regions.slot_owners[excepted_idx].paths_in_pt == set![cur_entry_path]) by {
967            old_cont.inv_children_rel_unroll(old_cont.idx as int);
968        };
969
970        let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
971        let g_except = CursorOwner::<'rcu, C>::node_unlocked_except(guards, cur_entry_addr);
972        let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
973
974        assert forall|i: int|
975            #![trigger new_owner.continuations[i]]
976            new_owner.level - 1 <= i < NR_LEVELS implies new_owner.continuations[i].map_children(
977            h,
978        ) by {
979            if i == self.level - 2 {
980                assert(new_owner.continuations[i] == child_cont);
981                assert forall|j: int|
982                    #![trigger child_cont.children[j]]
983                    0 <= j < child_cont.children.len()
984                        && child_cont.children[j] is Some implies child_cont.children[j].unwrap().tree_predicate_map(
985                child_cont.path().push_tail(j as usize), h) by {
986                    let gc = child_cont.children[j].unwrap();
987                    let gc_path = child_cont.path().push_tail(j as usize);
988                    child_cont.inv_children_unroll(j);
989                    child_cont.inv_children_rel_unroll(j);
990                    child_cont.path().push_tail_property(j as usize);
991
992                    let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
993                    child_subtree.map_unroll_once(cur_entry_path, f, j);
994                    child_subtree.map_unroll_once(cur_entry_path, g_except, j);
995
996                    assert(child_cont.path() == cur_entry_path);
997                    assert(gc_path == cur_entry_path.push_tail(j as usize));
998                    assert(cur_entry_path.len() < gc_path.len());
999                    child_cont.pt_inv_children_unroll(j);
1000                    subtree_unlock_upgrade(
1001                        gc,
1002                        gc_path,
1003                        guards,
1004                        regions,
1005                        cur_entry_addr,
1006                        cur_entry_path,
1007                    );
1008                };
1009            } else if i == self.level - 1 {
1010                assert(new_owner.continuations[i] == modified_cont);
1011                assert(modified_cont.path() == old_cont.path());
1012                assert forall|j: int|
1013                    #![trigger modified_cont.children[j]]
1014                    0 <= j < modified_cont.children.len()
1015                        && modified_cont.children[j] is Some implies modified_cont.children[j].unwrap().tree_predicate_map(
1016                modified_cont.path().push_tail(j as usize), h) by {
1017                    assert(j != old_cont.idx as int);
1018                    assert(modified_cont.children[j] == old_cont.children[j]);
1019                    let sibling = old_cont.children[j].unwrap();
1020                    let sibling_path = old_cont.path().push_tail(j as usize);
1021                    old_cont.inv_children_unroll(j);
1022                    old_cont.inv_children_rel_unroll(j);
1023                    old_cont.path().push_tail_property(j as usize);
1024
1025                    push_tail_different_indices_different_paths(
1026                        old_cont.path(),
1027                        j as usize,
1028                        old_cont.idx,
1029                    );
1030                    // `cur_entry_path.len() <= sibling_path.len()` previously had its own
1031                    // `by { ... }` block at depth 3; inline its facts instead.
1032                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
1033                    old_cont.path().push_tail_property(old_cont.idx as usize);
1034                    assert(cur_entry_path.len() <= sibling_path.len());
1035                    old_cont.pt_inv_children_unroll(j);
1036                    subtree_unlock_upgrade(
1037                        sibling,
1038                        sibling_path,
1039                        guards,
1040                        regions,
1041                        cur_entry_addr,
1042                        cur_entry_path,
1043                    );
1044                };
1045            } else {
1046                assert(new_owner.continuations[i] == self.continuations[i]);
1047                let cont_i = self.continuations[i];
1048
1049                old_cont.entry_own.path.push_tail_property(old_cont.idx as usize);
1050                if i == self.level as int {
1051                    assert(old_cont.path() == cont_i.path().push_tail(cont_i.idx as usize));
1052                    cont_i.entry_own.path.push_tail_property(cont_i.idx as usize);
1053                } else if i == self.level as int + 1 {
1054                    let cont_sl = self.continuations[self.level as int];
1055                    assert(old_cont.path() == cont_sl.path().push_tail(cont_sl.idx as usize));
1056                    assert(cont_sl.path() == cont_i.path().push_tail(cont_i.idx as usize));
1057                    cont_i.entry_own.path.push_tail_property(cont_i.idx as usize);
1058                    cont_i.path().push_tail(cont_i.idx as usize).push_tail_property(
1059                        cont_sl.idx as usize,
1060                    );
1061                } else {
1062                    let cont_sl = self.continuations[self.level as int];
1063                    let cont_sl1 = self.continuations[self.level as int + 1];
1064                    assert(old_cont.path() == cont_sl.path().push_tail(cont_sl.idx as usize));
1065                    assert(cont_sl.path() == cont_sl1.path().push_tail(cont_sl1.idx as usize));
1066                    assert(cont_sl1.path() == cont_i.path().push_tail(cont_i.idx as usize));
1067                    cont_i.entry_own.path.push_tail_property(cont_i.idx as usize);
1068                    cont_i.path().push_tail(cont_i.idx as usize).push_tail_property(
1069                        cont_sl1.idx as usize,
1070                    );
1071                    cont_sl1.path().push_tail(cont_sl1.idx as usize).push_tail_property(
1072                        cont_sl.idx as usize,
1073                    );
1074                }
1075                assert(cur_entry_path.index(cont_i.tree_level as int) == cont_i.idx as usize);
1076
1077                assert forall|j: int|
1078                    #![trigger cont_i.children[j]]
1079                    0 <= j < cont_i.children.len()
1080                        && cont_i.children[j] is Some implies cont_i.children[j].unwrap().tree_predicate_map(
1081                cont_i.path().push_tail(j as usize), h) by {
1082                    let child_sub = cont_i.children[j].unwrap();
1083                    let child_path = cont_i.path().push_tail(j as usize);
1084                    cont_i.inv_children_unroll(j);
1085                    cont_i.inv_children_rel_unroll(j);
1086                    cont_i.path().push_tail_property(j as usize);
1087
1088                    assert(child_path.index(cont_i.tree_level as int) == j as usize);
1089                    assert(j != cont_i.idx as int);
1090                    assert(child_path.index(cont_i.tree_level as int) != cur_entry_path.index(
1091                        cont_i.tree_level as int,
1092                    ));
1093                    assert(cont_i.tree_level < child_path.len());
1094                    cont_i.pt_inv_children_unroll(j);
1095                    subtree_unlock_upgrade(
1096                        child_sub,
1097                        child_path,
1098                        guards,
1099                        regions,
1100                        cur_entry_addr,
1101                        cur_entry_path,
1102                    );
1103                };
1104            }
1105        };
1106        assert(new_owner.children_not_locked(guards));
1107        assert forall|i: int|
1108            #![trigger new_owner.continuations[i]]
1109            new_owner.level - 1 <= i
1110                < new_owner.guard_level implies new_owner.continuations[i].node_locked(guards) by {
1111            if i == self.level - 2 {
1112                assert(new_owner.continuations[i] == child_cont);
1113                assert(child_cont.guard == guard);
1114            } else if i == self.level - 1 {
1115                assert(new_owner.continuations[i] == modified_cont);
1116                assert(modified_cont.guard == old_cont.guard);
1117            } else {
1118                assert(new_owner.continuations[i] == self.continuations[i]);
1119            }
1120        };
1121        assert(new_owner.nodes_locked(guards));
1122
1123        let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
1124        let child_subtree = child_cont.as_subtree();
1125
1126        assert(child_subtree.inv_children()) by {
1127            assert forall|j: int|
1128                0 <= j < NR_ENTRIES implies match #[trigger] child_subtree.children[j] {
1129                Some(ch) => {
1130                    &&& ch.level == child_subtree.level + 1
1131                    &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1132                        child_subtree.value,
1133                        j,
1134                        Some(ch.value),
1135                    )
1136                },
1137                None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1138                    child_subtree.value,
1139                    j,
1140                    None,
1141                ),
1142            } by {
1143                assert(child_cont.children[j] is Some);
1144                let ch = child_cont.children[j].unwrap();
1145                assert(ch.level == child_cont.tree_level + 1);
1146                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1147                    child_cont.entry_own,
1148                    j,
1149                    Some(ch.value),
1150                ));
1151            };
1152        };
1153        assert forall|j: int|
1154            0 <= j < NR_ENTRIES implies match #[trigger] child_subtree.children[j] {
1155            Some(ch) => ch.inv(),
1156            None => true,
1157        } by {
1158            child_cont.inv_children_unroll(j);
1159        };
1160        assert(child_subtree.inv()) by {
1161            assert(child_subtree.inv_node());
1162        };
1163
1164        // Pre-prove tree_predicate_map for child_subtree (f)
1165        assert(child_subtree.tree_predicate_map(child_cont.path(), f)) by {
1166            assert(f(child_subtree.value, child_cont.path()));
1167            assert forall|j: int|
1168                0 <= j
1169                    < child_subtree.children.len() implies match #[trigger] child_subtree.children[j] {
1170                Some(ch) => ch.tree_predicate_map(child_cont.path().push_tail(j as usize), f),
1171                None => true,
1172            } by {
1173                child_subtree.map_unroll_once(child_cont.path(), f, j);
1174            };
1175        };
1176
1177        // Pre-prove map_children for modified_cont (f)
1178        assert(modified_cont.map_children(f)) by {
1179            assert forall|j: int|
1180                0 <= j < modified_cont.children.len()
1181                    && #[trigger] modified_cont.children[j] is Some implies modified_cont.children[j].unwrap().tree_predicate_map(
1182            modified_cont.path().push_tail(j as usize), f) by {
1183                assert(j != old_cont.idx as int);
1184                assert(modified_cont.children[j] == old_cont.children[j]);
1185            };
1186        };
1187
1188        assert(new_owner.metaregion_sound(regions)) by {
1189            assert forall|i: int| #![auto] new_owner.level - 1 <= i < NR_LEVELS implies {
1190                &&& f(new_owner.continuations[i].entry_own, new_owner.continuations[i].path())
1191                &&& new_owner.continuations[i].map_children(f)
1192            } by {
1193                if i == self.level - 2 {
1194                    assert(new_owner.continuations[i] == child_cont);
1195                } else if i == self.level - 1 {
1196                    assert(new_owner.continuations[i] == modified_cont);
1197                    assert(modified_cont.entry_own == old_cont.entry_own);
1198                    assert(modified_cont.path() == old_cont.path());
1199                } else {
1200                    assert(new_owner.continuations[i] == self.continuations[i]);
1201                }
1202            };
1203        };
1204    }
1205
1206    pub proof fn tracked_push_level_owner(tracked &mut self, guard: PageTableGuard<'rcu, C>)
1207        requires
1208            old(self).inv(),
1209            old(self).level > 1,
1210        ensures
1211            *final(self) == old(self).push_level_owner(guard),
1212    {
1213        assert(self.va.index.contains_key(self.level - 2));
1214
1215        let ghost self0 = *self;
1216        let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
1217        let ghost cont0 = cont;
1218        let tracked child = cont.tracked_make_cont(self.va.index[self.level - 2] as usize, guard);
1219
1220        assert((child, cont) == cont0.make_cont(self.va.index[self.level - 2] as usize, guard));
1221
1222        self.continuations.tracked_insert(self.level - 1, cont);
1223        self.continuations.tracked_insert(self.level - 2, child);
1224
1225        assert(self.continuations == self0.continuations.insert(self.level - 1, cont).insert(
1226            self.level - 2,
1227            child,
1228        ));
1229
1230        self.popped_too_high = false;
1231
1232        self.level = (self.level - 1) as u8;
1233    }
1234
1235    pub open spec fn pop_level_owner(self) -> (Self, PageTableGuard<'rcu, C>) {
1236        let child = self.continuations[self.level - 1];
1237        let cont = self.continuations[self.level as int];
1238        let (new_cont, guard) = cont.restore(child);
1239        let new_continuations = self.continuations.insert(self.level as int, new_cont);
1240        let new_continuations = new_continuations.remove(self.level - 1);
1241        let new_level = (self.level + 1) as u8;
1242        let popped_too_high = if new_level >= self.guard_level {
1243            true
1244        } else {
1245            false
1246        };
1247        (
1248            Self {
1249                continuations: new_continuations,
1250                level: new_level,
1251                popped_too_high: popped_too_high,
1252                ..self
1253            },
1254            guard,
1255        )
1256    }
1257
1258    pub proof fn pop_level_owner_preserves_inv(self)
1259        requires
1260            self.inv(),
1261            self.level < NR_LEVELS,
1262    // [STEP 3] in_locked_range dropped
1263
1264        ensures
1265            self.pop_level_owner().0.inv(),
1266    {
1267        let child = self.continuations[self.level - 1];
1268        assert(child.inv());
1269        assert(child.all_some());
1270        let cont = self.continuations[self.level as int];
1271        assert(cont.inv());
1272        let (new_cont, _) = cont.restore(child);
1273        let new_owner = self.pop_level_owner().0;
1274
1275        let child_node = OwnerSubtree {
1276            value: child.entry_own,
1277            level: child.tree_level,
1278            children: child.children,
1279        };
1280
1281        let nc = self.continuations.insert(self.level as int, new_cont).remove(self.level - 1);
1282        assert(new_owner.continuations == nc);
1283        if self.level < 3 {
1284            assert(nc[3] == self.continuations[3]);
1285        }
1286        if self.level < 2 {
1287            assert(nc[2] == self.continuations[2]);
1288        }
1289        assert(new_cont.all_some()) by {
1290            assert forall|i: int| 0 <= i < NR_ENTRIES implies new_cont.children[i] is Some by {
1291                if i == cont.idx as int {
1292                    assert(new_cont.children[i] == Some(child_node));
1293                } else {
1294                    assert(new_cont.children[i] == cont.children[i]);
1295                }
1296            };
1297        };
1298
1299        assert forall|i: int| new_owner.level <= i < NR_LEVELS implies (
1300        #[trigger] new_owner.continuations[i]).all_but_index_some() by {
1301            if i == self.level as int {
1302                assert(new_owner.continuations[i] == new_cont);
1303                assert(new_cont.all_some());
1304            } else {
1305                assert(new_owner.continuations[i] == self.continuations[i]);
1306            }
1307        };
1308
1309        assert(child.path() == cont.path().push_tail(cont.idx as usize));
1310        assert(child.entry_own.path == new_cont.path().push_tail(cont.idx as usize));
1311        assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1312            new_cont.entry_own,
1313            cont.idx as int,
1314            Some(child.entry_own),
1315        ));
1316
1317        assert(child_node.inv_children()) by {
1318            assert forall|j: int|
1319                0 <= j < NR_ENTRIES implies match #[trigger] child_node.children[j] {
1320                Some(ch) => {
1321                    &&& ch.level == child_node.level + 1
1322                    &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1323                        child_node.value,
1324                        j,
1325                        Some(ch.value),
1326                    )
1327                },
1328                None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1329                    child_node.value,
1330                    j,
1331                    None,
1332                ),
1333            } by {
1334                assert(child.children[j] is Some);
1335                let ch = child.children[j].unwrap();
1336                assert(ch.level == child.tree_level + 1);
1337                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1338                    child.entry_own,
1339                    j,
1340                    Some(ch.value),
1341                ));
1342            };
1343        };
1344        assert forall|j: int| 0 <= j < NR_ENTRIES implies match #[trigger] child_node.children[j] {
1345            Some(ch) => ch.inv(),
1346            None => true,
1347        } by {
1348            child.inv_children_unroll(j);
1349        };
1350        assert(child_node.inv()) by {
1351            assert(child_node.inv_node());
1352        };
1353
1354        assert(new_cont.inv_children()) by {
1355            assert forall|i: int|
1356                0 <= i < new_cont.children.len()
1357                    && #[trigger] new_cont.children[i] is Some implies new_cont.children[i].unwrap().inv() by {
1358                if i == cont.idx as int {
1359                    assert(new_cont.children[i].unwrap() == child_node);
1360                } else {
1361                    assert(new_cont.children[i] == cont.children[i]);
1362                    cont.inv_children_unroll(i);
1363                }
1364            };
1365        };
1366
1367        assert(new_cont.inv_children_rel()) by {
1368            assert forall|i: int|
1369                0 <= i < NR_ENTRIES && #[trigger] new_cont.children[i] is Some implies {
1370                &&& new_cont.children[i].unwrap().value.parent_level == new_cont.level()
1371                &&& new_cont.children[i].unwrap().level == new_cont.tree_level + 1
1372                &&& !new_cont.children[i].unwrap().value.in_scope
1373                &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1374                    new_cont.entry_own,
1375                    i,
1376                    Some(new_cont.children[i].unwrap().value),
1377                )
1378                &&& new_cont.children[i].unwrap().value.path == new_cont.path().push_tail(
1379                    i as usize,
1380                )
1381            } by {
1382                if i == cont.idx as int {
1383                    assert(new_cont.children[i].unwrap() == child_node);
1384                    assert(!child.entry_own.in_scope);
1385                } else {
1386                    assert(new_cont.children[i] == cont.children[i]);
1387                    cont.inv_children_rel_unroll(i);
1388                }
1389            };
1390        };
1391
1392        assert(new_cont.inv()) by {
1393            assert(new_cont.tree_level == INC_LEVELS - new_cont.level() - 1);
1394            assert(new_cont.path().len() == new_cont.tree_level);
1395        };
1396
1397        assert(new_owner.level <= 4 ==> {
1398            &&& new_owner.continuations.contains_key(3)
1399            &&& new_owner.continuations[3].inv()
1400            &&& new_owner.continuations[3].level() == 4
1401            &&& new_owner.continuations[3].entry_own.parent_level
1402                == 5
1403            // `va.index == cont.idx` is inv-guarded by `in_locked_range`
1404            // (above-range cursors keep stale continuations).
1405            &&& new_owner.in_locked_range() ==> new_owner.va.index[3]
1406                == new_owner.continuations[3].idx
1407        }) by {
1408            if self.level as int == 3 {
1409                assert(new_owner.continuations[3] == new_cont);
1410            } else {
1411                assert(new_owner.continuations[3] == self.continuations[3]);
1412            }
1413        };
1414
1415        // Level 3 condition
1416        assert(new_owner.level <= 3 ==> {
1417            &&& new_owner.continuations.contains_key(2)
1418            &&& new_owner.continuations[2].inv()
1419            &&& new_owner.continuations[2].level() == 3
1420            &&& new_owner.continuations[2].entry_own.parent_level == 4
1421            &&& new_owner.in_locked_range() ==> new_owner.va.index[2]
1422                == new_owner.continuations[2].idx
1423            &&& new_owner.continuations[2].guard.inner.inner@.ptr.addr()
1424                != new_owner.continuations[3].guard.inner.inner@.ptr.addr()
1425            &&& new_owner.continuations[2].path() == new_owner.continuations[3].path().push_tail(
1426                new_owner.continuations[3].idx as usize,
1427            )
1428            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1429                new_owner.continuations[3].entry_own,
1430                new_owner.continuations[3].idx as int,
1431                Some(new_owner.continuations[2].entry_own),
1432            )
1433        }) by {
1434            if new_owner.level <= 3 {
1435                if self.level as int == 2 {
1436                    assert(new_owner.continuations[2] == new_cont);
1437                } else {
1438                    assert(new_owner.continuations[2] == self.continuations[2]);
1439                }
1440            }
1441        };
1442
1443        // Level 2 condition
1444        assert(new_owner.level <= 2 ==> {
1445            &&& new_owner.continuations.contains_key(1)
1446            &&& new_owner.continuations[1].inv()
1447            &&& new_owner.continuations[1].level() == 2
1448            &&& new_owner.continuations[1].entry_own.parent_level == 3
1449            &&& new_owner.in_locked_range() ==> new_owner.va.index[1]
1450                == new_owner.continuations[1].idx
1451            &&& new_owner.continuations[1].guard.inner.inner@.ptr.addr()
1452                != new_owner.continuations[2].guard.inner.inner@.ptr.addr()
1453            &&& new_owner.continuations[1].guard.inner.inner@.ptr.addr()
1454                != new_owner.continuations[3].guard.inner.inner@.ptr.addr()
1455            &&& new_owner.continuations[1].path() == new_owner.continuations[2].path().push_tail(
1456                new_owner.continuations[2].idx as usize,
1457            )
1458            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1459                new_owner.continuations[2].entry_own,
1460                new_owner.continuations[2].idx as int,
1461                Some(new_owner.continuations[1].entry_own),
1462            )
1463        }) by {
1464            if new_owner.level <= 2 {
1465                assert(new_owner.continuations[1] == new_cont);
1466            }
1467        };
1468    }
1469
1470    pub proof fn pop_level_owner_preserves_invs(
1471        self,
1472        guards: Guards<'rcu>,
1473        regions: MetaRegionOwners,
1474    )
1475        requires
1476            self.inv(),
1477            self.level < NR_LEVELS,
1478            // [STEP 3] in_locked_range dropped
1479            self.children_not_locked(guards),
1480            self.nodes_locked(guards),
1481            self.metaregion_sound(regions),
1482        ensures
1483            self.pop_level_owner().0.inv(),
1484            self.pop_level_owner().0.only_current_locked(guards),
1485            self.pop_level_owner().0.nodes_locked(guards),
1486            self.pop_level_owner().0.metaregion_sound(regions),
1487    {
1488        let new_owner = self.pop_level_owner().0;
1489        let child = self.continuations[self.level - 1];
1490        let cont = self.continuations[self.level as int];
1491        let (new_cont, _guard) = cont.restore(child);
1492        let child_node = OwnerSubtree {
1493            value: child.entry_own,
1494            level: child.tree_level,
1495            children: child.children,
1496        };
1497
1498        self.pop_level_owner_preserves_inv();
1499
1500        assert(new_owner.va == self.va);
1501
1502        assert(new_owner.nodes_locked(guards)) by {
1503            assert forall|i: int|
1504                #![trigger new_owner.continuations[i]]
1505                new_owner.level - 1 <= i
1506                    < new_owner.guard_level implies new_owner.continuations[i].node_locked(
1507                guards,
1508            ) by {
1509                if i == self.level as int {
1510                    assert(new_owner.continuations[i] == new_cont);
1511                    assert(new_cont.guard == cont.guard);
1512                } else {
1513                    assert(new_owner.continuations[i] == self.continuations[i]);
1514                }
1515            };
1516        };
1517
1518        let child_addr = child.entry_own.node.unwrap().meta_addr_self();
1519        let child_subtree = child.as_subtree();
1520
1521        assert forall|j: int|
1522            0 <= j < NR_ENTRIES implies match #[trigger] child_subtree.children[j] {
1523            Some(ch) => ch.inv(),
1524            None => true,
1525        } by {
1526            child.inv_children_unroll(j);
1527        };
1528        assert(child_subtree.inv());
1529
1530        assert(OwnerSubtree::<C>::implies(
1531            CursorOwner::<'rcu, C>::node_unlocked(guards),
1532            CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
1533        ));
1534        self.map_children_implies(
1535            CursorOwner::<'rcu, C>::node_unlocked(guards),
1536            CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
1537        );
1538
1539        assert(new_owner.only_current_locked(guards)) by {
1540            assert forall|i: int|
1541                #![trigger new_owner.continuations[i]]
1542                new_owner.level - 1 <= i
1543                    < NR_LEVELS implies new_owner.continuations[i].map_children(
1544                CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
1545            ) by {
1546                if i > self.level as int {
1547                    assert(new_owner.continuations[i] == self.continuations[i]);
1548                } else {
1549                    assert(new_owner.continuations[i] == new_cont);
1550                    new_cont.map_children_lift_skip_idx(
1551                        cont,
1552                        cont.idx as int,
1553                        CursorOwner::<'rcu, C>::node_unlocked(guards),
1554                        CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
1555                    );
1556                }
1557            };
1558        };
1559
1560        let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
1561        self.cont_entries_metaregion(regions);
1562
1563        assert(new_owner.metaregion_sound(regions)) by {
1564            assert forall|i: int|
1565                #![auto]
1566                new_owner.level - 1 <= i
1567                    < NR_LEVELS implies new_owner.continuations[i].map_children(f) by {
1568                if i > self.level as int {
1569                } else {
1570                    new_cont.map_children_lift_skip_idx(cont, cont.idx as int, f, f);
1571                }
1572            };
1573        };
1574    }
1575
1576    /// Update va to a new value that shares the same indices at levels >= self.level.
1577    /// This preserves invariants because:
1578    /// 1. The new va satisfies va.inv()
1579    /// 2. The indices at levels >= level match the continuation indices
1580    /// 3. in_locked_range/above_locked_range depend on va but the preconditions ensure consistency
1581    pub proof fn set_va_preserves_inv(self, new_va: AbstractVaddr)
1582        requires
1583            self.inv(),
1584            self.in_locked_range(),
1585            !self.popped_too_high,
1586            self.level <= self.guard_level,
1587            new_va.inv(),
1588            new_va.offset == 0,
1589            new_va.leading_bits == self.prefix.leading_bits,
1590            forall|i: int|
1591                #![auto]
1592                self.level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.va.index[i],
1593            forall|i: int|
1594                #![auto]
1595                self.guard_level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.prefix.index[i],
1596        ensures
1597            self.set_va(new_va).inv(),
1598    {
1599        let r = self.set_va(new_va);
1600
1601        assert(r.in_locked_range()) by {
1602            let gl = self.guard_level;
1603            if gl >= 1 && gl <= NR_LEVELS {
1604                r.va.align_down_to_vaddr_eq_if_upper_indices_eq(r.prefix, gl as int);
1605                r.va.align_down_concrete(gl as int);
1606                r.prefix.align_down_concrete(gl as int);
1607                // Use cursor inv helpers on self (r.prefix == self.prefix).
1608                self.prefix_aligned_to_guard_level();
1609                self.prefix_plus_ps_no_overflow();
1610                r.prefix.aligned_align_up_advances(gl as int);
1611                AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1612                    nat_align_down(
1613                        r.va.to_vaddr() as nat,
1614                        page_size(gl as PagingLevel) as nat,
1615                    ) as Vaddr,
1616                );
1617                AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1618                    nat_align_down(
1619                        r.prefix.to_vaddr() as nat,
1620                        page_size(gl as PagingLevel) as nat,
1621                    ) as Vaddr,
1622                );
1623                lemma_page_size_ge_page_size(gl as PagingLevel);
1624                lemma_nat_align_down_sound(
1625                    r.va.to_vaddr() as nat,
1626                    page_size(gl as PagingLevel) as nat,
1627                );
1628                r.prefix.align_down_shape(gl as int);
1629                r.prefix.align_down(gl as int).reflect_prop(
1630                    nat_align_down(
1631                        r.prefix.to_vaddr() as nat,
1632                        page_size(gl as PagingLevel) as nat,
1633                    ) as Vaddr,
1634                );
1635            }
1636        };
1637
1638        assert(r.continuations[r.level - 1].all_some());
1639        assert(r.level <= 4 ==> {
1640            &&& r.continuations.contains_key(3)
1641            &&& r.continuations[3].inv()
1642            &&& r.continuations[3].level() == 4
1643            &&& r.continuations[3].entry_own.parent_level == 5
1644            &&& r.in_locked_range() ==> r.va.index[3] == r.continuations[3].idx
1645        });
1646
1647        assert(r.level <= 3 ==> {
1648            &&& r.continuations.contains_key(2)
1649            &&& r.continuations[2].inv()
1650            &&& r.continuations[2].level() == 3
1651            &&& r.continuations[2].entry_own.parent_level == 4
1652            &&& r.in_locked_range() ==> r.va.index[2] == r.continuations[2].idx
1653            &&& r.continuations[2].guard.inner.inner@.ptr.addr()
1654                != r.continuations[3].guard.inner.inner@.ptr.addr()
1655            &&& r.continuations[2].path() == r.continuations[3].path().push_tail(
1656                r.continuations[3].idx as usize,
1657            )
1658        });
1659
1660        assert(r.level <= 2 ==> {
1661            &&& r.continuations.contains_key(1)
1662            &&& r.continuations[1].inv()
1663            &&& r.continuations[1].level() == 2
1664            &&& r.continuations[1].entry_own.parent_level == 3
1665            &&& r.in_locked_range() ==> r.va.index[1] == r.continuations[1].idx
1666            &&& r.continuations[1].guard.inner.inner@.ptr.addr()
1667                != r.continuations[2].guard.inner.inner@.ptr.addr()
1668            &&& r.continuations[1].guard.inner.inner@.ptr.addr()
1669                != r.continuations[3].guard.inner.inner@.ptr.addr()
1670            &&& r.continuations[1].path() == r.continuations[2].path().push_tail(
1671                r.continuations[2].idx as usize,
1672            )
1673        });
1674
1675        assert(r.level == 1 ==> {
1676            &&& r.continuations.contains_key(0)
1677            &&& r.continuations[0].inv()
1678            &&& r.continuations[0].level() == 1
1679            &&& r.continuations[0].entry_own.parent_level == 2
1680            &&& r.in_locked_range() ==> r.va.index[0] == r.continuations[0].idx
1681            &&& r.continuations[0].guard.inner.inner@.ptr.addr()
1682                != r.continuations[1].guard.inner.inner@.ptr.addr()
1683            &&& r.continuations[0].guard.inner.inner@.ptr.addr()
1684                != r.continuations[2].guard.inner.inner@.ptr.addr()
1685            &&& r.continuations[0].guard.inner.inner@.ptr.addr()
1686                != r.continuations[3].guard.inner.inner@.ptr.addr()
1687            &&& r.continuations[0].path() == r.continuations[1].path().push_tail(
1688                r.continuations[1].idx as usize,
1689            )
1690        });
1691    }
1692
1693    pub proof fn tracked_pop_level_owner(tracked &mut self) -> (tracked guard: PageTableGuard<
1694        'rcu,
1695        C,
1696    >)
1697        requires
1698            old(self).inv(),
1699            old(self).level < NR_LEVELS,
1700        ensures
1701            *final(self) == old(self).pop_level_owner().0,
1702            guard == old(self).pop_level_owner().1,
1703    {
1704        let ghost self0 = *self;
1705        let tracked mut parent = self.continuations.tracked_remove(self.level as int);
1706        let tracked child = self.continuations.tracked_remove(self.level - 1);
1707
1708        let tracked guard = parent.tracked_restore(child);
1709
1710        self.continuations.tracked_insert(self.level as int, parent);
1711
1712        assert(self.continuations == self0.continuations.insert(self.level as int, parent).remove(
1713            self.level - 1,
1714        ));
1715
1716        self.level = (self.level + 1) as u8;
1717
1718        if self.level >= self.guard_level {
1719            self.popped_too_high = true;
1720        }
1721        guard
1722    }
1723
1724    pub open spec fn move_forward_owner_spec(self) -> Self
1725        recommends
1726            self.inv(),
1727            self.level < NR_LEVELS,
1728            self.in_locked_range(),
1729        decreases NR_LEVELS - self.level,
1730        when self.level <= NR_LEVELS
1731    {
1732        if self.index() + 1 < NR_ENTRIES {
1733            // Standard advance. At the very last in-range top-level slot, this
1734            // produces a "one-past-end" cursor with idx == TOP_LEVEL_INDEX_RANGE.end,
1735            // which the cursor inv allows (relaxed `<= top_end`). Such a cursor is
1736            // `above_locked_range`.
1737            self.inc_index().zero_below_level()
1738        } else if self.level < NR_LEVELS {
1739            self.pop_level_owner().0.move_forward_owner_spec()
1740        } else {
1741            // self.level == NR_LEVELS && self.index() + 1 == NR_ENTRIES.
1742            // Advance to the next leading_bits-chunk via `next_index(NR_LEVELS)`.
1743            Self { va: self.va.next_index(NR_LEVELS as int), popped_too_high: false, ..self }
1744        }
1745    }
1746
1747    pub proof fn move_forward_increases_va(self)
1748        requires
1749            self.inv(),
1750            self.level <= NR_LEVELS,
1751            self.in_locked_range(),
1752            !self.popped_too_high,
1753        ensures
1754            self.move_forward_owner_spec().va.to_vaddr() > self.va.to_vaddr(),
1755        decreases NR_LEVELS - self.level,
1756    {
1757        self.in_locked_range_level_le_guard_level();
1758        if self.index() + 1 < NR_ENTRIES {
1759            self.inc_and_zero_increases_va();
1760        } else if self.level == self.guard_level {
1761            // level == guard_level, index + 1 >= NR_ENTRIES.
1762            // move_forward_owner_spec pops if level < NR_LEVELS, else returns self.
1763            self.in_locked_range_guard_index_eq_prefix();
1764            let k = self.prefix.index[self.guard_level - 1];
1765            assert(self.index() == k);
1766            if self.guard_level < NR_LEVELS {
1767                // Pop to parent. Parent is at guard_level + 1 with popped_too_high.
1768                assert(self.level < NR_LEVELS);
1769                self.pop_level_owner_preserves_inv();
1770                let popped = self.pop_level_owner().0;
1771                // popped.popped_too_high == true, so move_forward on popped
1772                // does inc_index().zero_below_level(). VA increases.
1773                // k == NR_ENTRIES - 1 here, so the parent idx advances.
1774            } else {
1775                // `level == guard_level == NR_LEVELS && index+1 == NR_ENTRIES`
1776                // is unreachable: `cursor_top_idx_strict_lt_nr_entries` derives
1777                // `self.index() + 1 < NR_ENTRIES` from cursor inv +
1778                // LOCKED_END_BOUND, contradicting the outer `else` guard.
1779                self.cursor_top_idx_strict_lt_nr_entries();
1780                assert(false);
1781            }
1782        } else if self.level + 1 < self.guard_level {
1783            assert(self.level < NR_LEVELS);
1784            self.pop_level_owner_preserves_inv();
1785            self.pop_level_owner().0.move_forward_increases_va();
1786        } else {
1787            assert(self.level < NR_LEVELS);
1788            assert(self.guard_level == self.level + 1);
1789            self.in_locked_range_guard_index_eq_prefix();
1790            let k = self.prefix.index[self.guard_level - 1];
1791            assert(self.va.index[self.level as int] == k);
1792            self.pop_level_owner_preserves_inv();
1793            let popped = self.pop_level_owner().0;
1794            assert(self.move_forward_owner_spec() == popped.move_forward_owner_spec());
1795            if k + 1 < NR_ENTRIES {
1796                assert(popped.move_forward_owner_spec() == popped.inc_index().zero_below_level());
1797                popped.inc_and_zero_increases_va();
1798            } else {
1799                // k == NR_ENTRIES - 1: popped state at guard_level wraps. move_forward
1800                // pops further (if guard_level < NR_LEVELS). VA still increases
1801                // because the parent entry advances.
1802            }
1803        }
1804    }
1805
1806    pub proof fn move_forward_not_popped_too_high(self)
1807        requires
1808            self.inv(),
1809            self.level <= NR_LEVELS,
1810            self.in_locked_range(),
1811        ensures
1812            !self.move_forward_owner_spec().popped_too_high,
1813        decreases NR_LEVELS - self.level,
1814    {
1815        if self.index() + 1 < NR_ENTRIES {
1816            self.inc_index().zero_preserves_all_but_va();
1817        } else if self.level < NR_LEVELS {
1818            self.pop_level_owner_preserves_inv();
1819            self.pop_level_owner().0.move_forward_not_popped_too_high();
1820        }
1821    }
1822
1823    /// Variant of `move_forward_owner_decreases_steps` for the popped_too_high
1824    /// case. Same postcondition, but precondition allows `popped_too_high`.
1825    /// Used by the main lemma's case 2b to handle the chain of pops that
1826    /// `move_forward_owner_spec` does internally when popped_too_high.
1827    pub proof fn move_forward_owner_popped_too_high_decreases(self)
1828        requires
1829            self.inv(),
1830            self.level <= NR_LEVELS,
1831            self.in_locked_range(),
1832            self.popped_too_high,
1833            self.continuations[NR_LEVELS - 1].idx + 1 < NR_ENTRIES,
1834        ensures
1835            self.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(
1836                self.level as usize,
1837            ) <= self.max_steps(),
1838        decreases NR_LEVELS - self.level,
1839    {
1840        let l = self.level as usize;
1841        let st_l = Self::max_steps_subtree(l) as int;
1842        Self::max_steps_subtree_positive(l);
1843        if self.index() + 1 < NR_ENTRIES {
1844            // Case A: advance via inc_index().zero_below_level().
1845            // (Mirror of subcase A in the main lemma's case 2b.)
1846            let inc = self.inc_index();
1847            inc.zero_preserves_all_but_va();
1848            let new_state = inc.zero_below_level();
1849            assert(new_state.level == self.level);
1850            assert(new_state.continuations[self.level - 1].idx == self.continuations[self.level
1851                - 1].idx + 1);
1852            new_state.max_steps_partial_eq(self, (self.level + 1) as usize);
1853            let self_idx = self.continuations[self.level - 1].idx as int;
1854            vstd::arithmetic::mul::lemma_mul_is_distributive_add(
1855                st_l,
1856                NR_ENTRIES - self_idx - 2,
1857                1,
1858            );
1859            assert(self.move_forward_owner_spec() == new_state);
1860            assert(new_state.max_steps() + st_l == self.max_steps());
1861        } else if self.level < NR_LEVELS {
1862            // Case B1: pop again (popped2.popped_too_high also true) and recurse.
1863            self.pop_level_owner_preserves_inv();
1864            let popped2 = self.pop_level_owner().0;
1865            let lp1 = (self.level + 1) as usize;
1866            popped2.max_steps_partial_eq(self, lp1);
1867            Self::max_steps_subtree_positive(lp1);
1868
1869            // Bookkeeping (mirrors the main lemma at lines 1683-1695):
1870            assert(self.continuations[self.level - 1].idx + 1 == NR_ENTRIES);
1871            assert((NR_ENTRIES - self.continuations[self.level - 1].idx - 1) as nat == 0nat);
1872            assert(Self::max_steps_subtree(l) * 0nat == 0) by (nonlinear_arith);
1873            assert(self.max_steps_partial(l) == self.max_steps_partial(lp1));
1874            assert(popped2.level == lp1 as u8);
1875            assert(popped2.max_steps() == self.max_steps_partial(lp1) + Self::max_steps_subtree(
1876                lp1,
1877            ));
1878            assert(self.max_steps() == self.max_steps_partial(lp1) + Self::max_steps_subtree(l));
1879
1880            // popped2.popped_too_high holds: popped2.level == self.level + 1
1881            // > self.guard_level (since self.popped_too_high gives
1882            // self.level >= self.guard_level), so popped2 satisfies the
1883            // popped_too_high arm of pop_level_owner.
1884
1885            // Recurse on popped2.
1886            popped2.move_forward_owner_popped_too_high_decreases();
1887            assert(popped2.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(lp1)
1888                <= popped2.max_steps());
1889            // Spec unfolding: in the else-if branch, self.move_forward unfolds
1890            // to popped2.move_forward.
1891            assert(self.move_forward_owner_spec() == popped2.move_forward_owner_spec());
1892            // Stitch: popped2.move_forward.max_steps + subtree(lp1) ≤ popped2.max_steps
1893            //                                          == self.max_steps_partial(lp1) + subtree(lp1)
1894            //   ⟹ popped2.move_forward.max_steps ≤ self.max_steps_partial(lp1)
1895            //   ⟹ popped2.move_forward.max_steps + st_l ≤ self.max_steps()
1896            assert(popped2.move_forward_owner_spec().max_steps() <= self.max_steps_partial(lp1));
1897            assert(self.move_forward_owner_spec().max_steps() + st_l <= self.max_steps());
1898        } else {
1899            // Case C: self.level == NR_LEVELS && self.index() + 1 == NR_ENTRIES.
1900            // Excluded by the lemma's precondition.
1901            assert(false);
1902        }
1903    }
1904
1905    pub proof fn move_forward_owner_decreases_steps(self)
1906        requires
1907            self.inv(),
1908            self.level <= NR_LEVELS,
1909            self.in_locked_range(),
1910            !self.popped_too_high,
1911            // See `move_forward_owner_popped_too_high_decreases` for the
1912            // rationale: rules out the unreachable third-branch corner.
1913            self.continuations[NR_LEVELS - 1].idx + 1 < NR_ENTRIES,
1914        ensures
1915    // "Decrease by ≥ subtree(self.level)" form: needed by `push_level`
1916    // and by the pop+recursion case to compensate for pop_level's
1917    // `+(subtree(L+1) - subtree(L))` increase.
1918
1919            self.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(
1920                self.level as usize,
1921            ) <= self.max_steps(),
1922            self.move_forward_owner_spec().max_steps() < self.max_steps(),
1923        decreases NR_LEVELS - self.level,
1924    {
1925        let l = self.level as usize;
1926        let st_l = Self::max_steps_subtree(l) as int;
1927        Self::max_steps_subtree_positive(l);
1928        if self.index() + 1 < NR_ENTRIES {
1929            // Case 1: increment idx at the current level.
1930            //   new_state.max_steps_partial(L) = old.max_steps_partial(L) - subtree(L)
1931            //   max_steps adds +subtree(L) on both sides → diff = -subtree(L).
1932            let inc = self.inc_index();
1933            inc.zero_preserves_all_but_va();
1934            let new_state = inc.zero_below_level();
1935            assert(new_state.level == self.level);
1936            assert(new_state.continuations[self.level - 1].idx == self.continuations[self.level
1937                - 1].idx + 1);
1938            new_state.max_steps_partial_eq(self, (self.level + 1) as usize);
1939            let self_idx = self.continuations[self.level - 1].idx as int;
1940            let tail = self.max_steps_partial((self.level + 1) as usize) as int;
1941            // st_l * (NR - idx - 1) == st_l * (NR - idx - 2) + st_l * 1.
1942            vstd::arithmetic::mul::lemma_mul_is_distributive_add(
1943                st_l,
1944                NR_ENTRIES - self_idx - 2,
1945                1,
1946            );
1947            // Tie new_state to move_forward_owner_spec and stitch the arithmetic:
1948            //   new_state.max_steps_partial(l) = (NR - self_idx - 2) * st_l + tail
1949            //   new_state.max_steps()          = new_state.max_steps_partial(l) + st_l
1950            //   self.max_steps()               = (NR - self_idx - 1) * st_l + tail + st_l
1951            // Hence new_state.max_steps() + st_l == self.max_steps() (equality, so ≤).
1952            assert(self.move_forward_owner_spec() == new_state);
1953            assert(new_state.max_steps() + st_l == self.max_steps());
1954        } else if self.level < NR_LEVELS {
1955            self.in_locked_range_level_le_guard_level();
1956            self.pop_level_owner_preserves_inv();
1957            let popped = self.pop_level_owner().0;
1958            let lp1 = (self.level + 1) as usize;
1959            popped.max_steps_partial_eq(self, lp1);
1960            Self::max_steps_subtree_positive(lp1);
1961
1962            assert(self.continuations[self.level - 1].idx + 1 == NR_ENTRIES);
1963            assert((NR_ENTRIES - self.continuations[self.level - 1].idx - 1) as nat == 0nat);
1964            assert(Self::max_steps_subtree(l) * 0nat == 0) by (nonlinear_arith);
1965            assert(self.max_steps_partial(l) == self.max_steps_partial(lp1));
1966            assert(popped.level == (self.level + 1) as u8);
1967            assert(popped.max_steps() == self.max_steps_partial(lp1) + Self::max_steps_subtree(
1968                lp1,
1969            ));
1970            assert(self.max_steps() == self.max_steps_partial(lp1) + Self::max_steps_subtree(l));
1971            if !popped.popped_too_high {
1972                popped.move_forward_owner_decreases_steps();
1973                assert(popped.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(lp1)
1974                    <= popped.max_steps());
1975                assert(self.move_forward_owner_spec() == popped.move_forward_owner_spec());
1976                // Stitch: popped.move_forward.max_steps + subtree(lp1) ≤ popped.max_steps
1977                //                                          == self.max_steps_partial(lp1) + subtree(lp1)
1978                //   ⟹ popped.move_forward.max_steps ≤ self.max_steps_partial(lp1)
1979                //   ⟹ popped.move_forward.max_steps + st_l ≤ self.max_steps_partial(lp1) + st_l
1980                //                                          == self.max_steps()
1981                assert(popped.move_forward_owner_spec().max_steps() <= self.max_steps_partial(lp1));
1982                assert(self.move_forward_owner_spec().max_steps() + st_l <= self.max_steps());
1983            } else {
1984                // popped.popped_too_high — delegate to the popped_too_high
1985                // variant, which handles all subcases (advance, recursive pop,
1986                // and the NR_LEVELS leaf) in one call.
1987                popped.move_forward_owner_popped_too_high_decreases();
1988                assert(popped.move_forward_owner_spec().max_steps() + Self::max_steps_subtree(lp1)
1989                    <= popped.max_steps());
1990                assert(self.move_forward_owner_spec() == popped.move_forward_owner_spec());
1991                // Same stitching as the !popped_too_high case:
1992                //   popped.move_forward.max_steps + subtree(lp1) ≤ popped.max_steps
1993                //                                          == self.max_steps_partial(lp1) + subtree(lp1)
1994                //   ⟹ popped.move_forward.max_steps ≤ self.max_steps_partial(lp1)
1995                //   ⟹ popped.move_forward.max_steps + st_l ≤ self.max_steps()
1996                assert(popped.move_forward_owner_spec().max_steps() <= self.max_steps_partial(lp1));
1997                assert(self.move_forward_owner_spec().max_steps() + st_l <= self.max_steps());
1998            }
1999        } else {
2000            self.in_locked_range_level_le_nr_levels();
2001            self.in_locked_range_level_le_guard_level();
2002            self.cursor_top_idx_strict_lt_nr_entries();
2003            assert(false);
2004        }
2005    }
2006
2007    /// Trivial: zero_below_level is defined as Self { va: self.va.align_down(level), ..self }.
2008    pub proof fn zero_below_level_eq_align_down(self)
2009        requires
2010            self.va.inv(),
2011            self.va.offset == 0,
2012            1 <= self.level <= NR_LEVELS,
2013        ensures
2014            self.zero_below_level().va == self.va.align_down(self.level as int),
2015        decreases self.level,
2016    {
2017    }
2018
2019    #[verifier::rlimit(4)]
2020    #[verifier::spinoff_prover]
2021    pub proof fn move_forward_va_is_align_up(self)
2022        requires
2023            self.inv(),
2024            self.level <= NR_LEVELS,
2025            self.in_locked_range(),
2026            !self.popped_too_high,
2027            // At level == guard_level, the wrap case (index+1 == NR_ENTRIES)
2028            // produces a result whose VA does not equal `va.align_up(level)`
2029            // when guard_level == NR_LEVELS (the spec returns self unchanged).
2030            // Callers (e.g. `do_inc_index_or_pop`) already have this from their
2031            // own bounds assume — see [mod.rs:1549].
2032            self.level == self.guard_level ==> self.index() + 1 < NR_ENTRIES,
2033        ensures
2034            self.move_forward_owner_spec().va == self.va.align_up(self.level as int),
2035        decreases NR_LEVELS - self.level,
2036    {
2037        if self.level == self.guard_level {
2038            if self.index() + 1 < NR_ENTRIES {
2039                // Same as the no-carry branch below: use align_up_advances_general.
2040                let inc = self.inc_index();
2041                inc.zero_preserves_all_but_va();
2042                inc.zero_below_level_va();
2043                assert(inc.va.inv()) by {
2044                    assert forall|i: int| 0 <= i < NR_LEVELS implies inc.va.index.contains_key(i)
2045                        && 0 <= #[trigger] inc.va.index[i] && inc.va.index[i] < NR_ENTRIES by {
2046                        if i != self.level - 1 {
2047                            assert(inc.va.index[i] == self.va.index[i]);
2048                        }
2049                    };
2050                };
2051                inc.va.align_down_concrete(self.level as int);
2052                let ps = page_size(self.level as PagingLevel) as nat;
2053                let self_va = self.va.to_vaddr() as nat;
2054                lemma_page_size_ge_page_size(self.level as PagingLevel);
2055                assert(self.va.index[self.level - 1] == self.continuations[self.level - 1].idx);
2056                self.va.index_increment_adds_page_size(self.level as int);
2057                let inc_va = inc.va.to_vaddr() as nat;
2058                assert(inc_va == self_va + ps);
2059                assert(self_va + ps == ps * 1 + self_va) by (nonlinear_arith);
2060                vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(
2061                    1int,
2062                    self_va as int,
2063                    ps as int,
2064                );
2065                vstd::arithmetic::div_mod::lemma_fundamental_div_mod(self_va as int, ps as int);
2066                vstd::arithmetic::div_mod::lemma_mod_bound(self_va as int, ps as int);
2067                vstd::arithmetic::div_mod::lemma_div_pos_is_pos(self_va as int, ps as int);
2068                assert(nat_align_down(inc_va, ps) == nat_align_down(self_va, ps) + ps);
2069                vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va, ps);
2070                assert(vstd_extra::arithmetic::nat_align_down(self_va, ps) + ps
2071                    <= usize::MAX as nat);
2072                self.va.align_up_advances_general(self.level as int);
2073                inc.va.align_down_shape(self.level as int);
2074                self.va.align_down_shape(self.level as int);
2075                AbstractVaddr::to_vaddr_from_vaddr_roundtrip(inc.va.align_down(self.level as int));
2076                AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va.align_up(self.level as int));
2077            }
2078            // The wrap (`index+1 == NR_ENTRIES`) at `level == guard_level` is
2079            // precluded by the strengthened precondition.
2080
2081            return;
2082        }
2083        if self.index() + 1 < NR_ENTRIES {
2084            let inc = self.inc_index();
2085            inc.zero_preserves_all_but_va();
2086            inc.zero_below_level_va();
2087            assert(inc.va.inv()) by {
2088                assert forall|i: int| 0 <= i < NR_LEVELS implies inc.va.index.contains_key(i) && 0
2089                    <= #[trigger] inc.va.index[i] && inc.va.index[i] < NR_ENTRIES by {
2090                    if i != self.level - 1 {
2091                        assert(inc.va.index[i] == self.va.index[i]);
2092                    }
2093                };
2094            };
2095            inc.va.align_down_concrete(self.level as int);
2096            let ps = page_size(self.level as PagingLevel) as nat;
2097            let self_va = self.va.to_vaddr() as nat;
2098            lemma_page_size_ge_page_size(self.level as PagingLevel);
2099            assert(self.va.index[self.level - 1] == self.continuations[self.level - 1].idx);
2100            self.va.index_increment_adds_page_size(self.level as int);
2101            let inc_va = inc.va.to_vaddr() as nat;
2102            assert(inc_va == self_va + ps);
2103            assert(self_va + ps == ps * 1 + self_va) by (nonlinear_arith);
2104            vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(1int, self_va as int, ps as int);
2105            vstd::arithmetic::div_mod::lemma_fundamental_div_mod(self_va as int, ps as int);
2106            vstd::arithmetic::div_mod::lemma_mod_bound(self_va as int, ps as int);
2107            vstd::arithmetic::div_mod::lemma_div_pos_is_pos(self_va as int, ps as int);
2108            // nat_align_down(inc_va, ps) == nat_align_down(self_va, ps) + ps
2109            // (adding a multiple of ps preserves the aligned base).
2110            assert(nat_align_down(inc_va, ps) == nat_align_down(self_va, ps) + ps);
2111            // Sound align_up: self.va.align_up(level).to_vaddr() == nat_align_down(self_va, ps) + ps.
2112            // Overflow bound: nat_align_down(self_va, ps) <= self_va, and self_va + ps == inc_va
2113            // is a valid usize (inc.va.to_vaddr() didn't overflow), so nat_align_down + ps <= inc_va <= usize::MAX.
2114            vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va, ps);
2115            assert(vstd_extra::arithmetic::nat_align_down(self_va, ps) + ps <= usize::MAX as nat);
2116            self.va.align_up_advances_general(self.level as int);
2117            // Now inc.va.align_down(level).to_vaddr() == nat_align_down(inc_va, ps)
2118            //    == nat_align_down(self_va, ps) + ps == self.va.align_up(level).to_vaddr().
2119            // Equal to_vaddr + both satisfy inv ⇒ both equal via from_vaddr uniqueness.
2120            inc.va.align_down_shape(self.level as int);
2121            self.va.align_down_shape(self.level as int);
2122            AbstractVaddr::to_vaddr_from_vaddr_roundtrip(inc.va.align_down(self.level as int));
2123            AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va.align_up(self.level as int));
2124        } else if self.level < NR_LEVELS {
2125            self.in_locked_range_level_le_guard_level();
2126            self.pop_level_owner_preserves_inv();
2127            let popped = self.pop_level_owner().0;
2128            if !popped.popped_too_high {
2129                popped.move_forward_va_is_align_up();
2130            } else {
2131                let inc_p = popped.inc_index();
2132                inc_p.zero_preserves_all_but_va();
2133                inc_p.zero_below_level_va();
2134                assert(inc_p.va.inv()) by {
2135                    assert forall|i: int| 0 <= i < NR_LEVELS implies inc_p.va.index.contains_key(i)
2136                        && 0 <= #[trigger] inc_p.va.index[i] && inc_p.va.index[i] < NR_ENTRIES by {
2137                        if i != popped.level - 1 {
2138                            assert(inc_p.va.index[i] == popped.va.index[i]);
2139                        }
2140                    };
2141                };
2142                inc_p.va.align_down_concrete(popped.level as int);
2143                let ps_p = page_size(popped.level as PagingLevel) as nat;
2144                let popped_va = popped.va.to_vaddr() as nat;
2145                let inc_p_va = inc_p.va.to_vaddr() as nat;
2146                lemma_page_size_ge_page_size(popped.level as PagingLevel);
2147                assert(popped.va.index[popped.level as int - 1]
2148                    == popped.continuations[popped.level as int - 1].idx);
2149                popped.va.index_increment_adds_page_size(popped.level as int);
2150                assert(inc_p_va == popped_va + ps_p);
2151                assert(popped_va + ps_p == ps_p * 1 + popped_va) by (nonlinear_arith);
2152                vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(
2153                    1int,
2154                    popped_va as int,
2155                    ps_p as int,
2156                );
2157                vstd::arithmetic::div_mod::lemma_fundamental_div_mod(popped_va as int, ps_p as int);
2158                vstd::arithmetic::div_mod::lemma_mod_bound(popped_va as int, ps_p as int);
2159                vstd::arithmetic::div_mod::lemma_div_pos_is_pos(popped_va as int, ps_p as int);
2160                // Sound align_up: align_up.to_vaddr() == nat_align_down(popped_va, ps) + ps.
2161                vstd_extra::arithmetic::lemma_nat_align_down_sound(popped_va, ps_p);
2162                assert(vstd_extra::arithmetic::nat_align_down(popped_va, ps_p) + ps_p
2163                    <= usize::MAX as nat);
2164                popped.va.align_up_advances_general(popped.level as int);
2165                assert(nat_align_down(inc_p_va, ps_p) == vstd_extra::arithmetic::nat_align_down(
2166                    popped_va,
2167                    ps_p,
2168                ) + ps_p);
2169                inc_p.va.align_down_shape(popped.level as int);
2170                popped.va.align_down_shape(popped.level as int);
2171                AbstractVaddr::to_vaddr_from_vaddr_roundtrip(
2172                    inc_p.va.align_down(popped.level as int),
2173                );
2174                AbstractVaddr::to_vaddr_from_vaddr_roundtrip(
2175                    popped.va.align_up(popped.level as int),
2176                );
2177                assert(inc_p.va.align_down(popped.level as int) == popped.va.align_up(
2178                    popped.level as int,
2179                ));
2180                assert(popped.index() + 1 < NR_ENTRIES);
2181                assert(popped.move_forward_owner_spec().va == inc_p.zero_below_level().va);
2182            }
2183            assert(self.va.index[self.level as int - 1] == self.continuations[self.level as int
2184                - 1].idx);
2185            self.va.align_up_carry(self.level as int);
2186        }
2187    }
2188
2189    /// After popping a level, the total view_mappings is preserved.
2190    /// The restored parent at index self.level absorbs the child's mappings,
2191    /// and both are within the view_mappings range [self.level, NR_LEVELS).
2192    pub proof fn pop_level_owner_preserves_mappings(self)
2193        requires
2194            self.inv(),
2195            self.level < NR_LEVELS,
2196            self.in_locked_range(),
2197        ensures
2198            self.pop_level_owner().0@.mappings == self@.mappings,
2199    {
2200        let child = self.continuations[self.level - 1];
2201        let parent = self.continuations[self.level as int];
2202        let (restored_parent, _) = parent.restore(child);
2203        let popped = self.pop_level_owner().0;
2204        let child_subtree = child.as_subtree();
2205
2206        assert(child.inv());
2207        assert(child.all_some());
2208        assert(parent.inv());
2209        assert(parent.all_but_index_some());
2210        assert(child.path() == parent.path().push_tail(parent.idx as usize));
2211
2212        assert(child_subtree.inv()) by {
2213            assert(child_subtree.inv_node());
2214            assert forall|i: int|
2215                0 <= i < NR_ENTRIES implies match #[trigger] child_subtree.children[i] {
2216                Some(ch) => {
2217                    &&& ch.level == child_subtree.level + 1
2218                    &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
2219                        child_subtree.value,
2220                        i,
2221                        Some(ch.value),
2222                    )
2223                },
2224                None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
2225                    child_subtree.value,
2226                    i,
2227                    None,
2228                ),
2229            } by {
2230                let ch = child.children[i].unwrap();
2231                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
2232                    child.entry_own,
2233                    i,
2234                    Some(ch.value),
2235                ));
2236            };
2237            assert(child_subtree.inv_children());
2238
2239            assert forall|i: int|
2240                0 <= i < NR_ENTRIES implies match #[trigger] child_subtree.children[i] {
2241                Some(ch) => ch.inv(),
2242                None => true,
2243            } by {
2244                child.inv_children_unroll(i);
2245            };
2246        };
2247
2248        parent.as_subtree_restore(child);
2249
2250        let r = restored_parent;
2251        let p = parent.put_child(child_subtree);
2252        assert forall|j: int| 0 <= j < r.children.len() implies r.children[j] == p.children[j] by {
2253            if j == parent.idx as int {
2254                assert(r.children[j] == Some(child_subtree));
2255            } else {
2256                assert(r.children[j] == parent.children[j]);
2257            }
2258        };
2259        assert(r.children =~= p.children);
2260        assert(restored_parent.view_mappings() =~= parent.put_child(child_subtree).view_mappings())
2261            by {
2262            assert(r.path() == p.path());
2263            assert forall|m: Mapping|
2264                r.view_mappings().contains(m) implies p.view_mappings().contains(m) by {
2265                let j = choose|j: int|
2266                    #![auto]
2267                    0 <= j < r.children.len() && r.children[j] is Some && PageTableOwner(
2268                        r.children[j].unwrap(),
2269                    ).view_rec(r.path().push_tail(j as usize)).contains(m);
2270                assert(p.children[j] is Some);
2271                assert(PageTableOwner(p.children[j].unwrap()).view_rec(
2272                    p.path().push_tail(j as usize),
2273                ).contains(m));
2274            };
2275            assert forall|m: Mapping|
2276                p.view_mappings().contains(m) implies r.view_mappings().contains(m) by {
2277                let j = choose|j: int|
2278                    #![auto]
2279                    0 <= j < p.children.len() && p.children[j] is Some && PageTableOwner(
2280                        p.children[j].unwrap(),
2281                    ).view_rec(p.path().push_tail(j as usize)).contains(m);
2282                assert(r.children[j] is Some);
2283                assert(PageTableOwner(r.children[j].unwrap()).view_rec(
2284                    r.path().push_tail(j as usize),
2285                ).contains(m));
2286            };
2287        };
2288
2289        parent.view_mappings_put_child(child_subtree);
2290        child.as_page_table_owner_preserves_view_mappings();
2291
2292        assert(popped.level == (self.level + 1) as u8);
2293        assert(popped.continuations[self.level as int] == restored_parent);
2294
2295        assert(popped.view_mappings() =~= self.view_mappings()) by {
2296            assert forall|m: Mapping|
2297                self.view_mappings().contains(m) implies popped.view_mappings().contains(m) by {
2298                let i = choose|i: int|
2299                    self.level - 1 <= i < NR_LEVELS && (
2300                    #[trigger] self.continuations[i]).view_mappings().contains(m);
2301                if i == self.level - 1 {
2302                    assert(child.view_mappings().contains(m));
2303                    assert(restored_parent.view_mappings().contains(m));
2304                    assert(popped.continuations[self.level as int].view_mappings().contains(m));
2305                } else if i == self.level as int {
2306                    assert(parent.view_mappings().contains(m));
2307                    assert(restored_parent.view_mappings().contains(m));
2308                    assert(popped.continuations[self.level as int].view_mappings().contains(m));
2309                } else {
2310                    assert(popped.continuations[i] == self.continuations[i]);
2311                }
2312            };
2313            assert forall|m: Mapping|
2314                popped.view_mappings().contains(m) implies self.view_mappings().contains(m) by {
2315                let i = choose|i: int|
2316                    popped.level - 1 <= i < NR_LEVELS && (
2317                    #[trigger] popped.continuations[i]).view_mappings().contains(m);
2318                if i == self.level as int {
2319                    assert(restored_parent.view_mappings().contains(m));
2320                    if child.view_mappings().contains(m) {
2321                        assert(self.continuations[self.level - 1].view_mappings().contains(m));
2322                    } else {
2323                        assert(parent.view_mappings().contains(m));
2324                        assert(self.continuations[self.level as int].view_mappings().contains(m));
2325                    }
2326                } else {
2327                    assert(self.continuations[i] == popped.continuations[i]);
2328                }
2329            };
2330        };
2331    }
2332
2333    pub proof fn move_forward_owner_preserves_mappings(self)
2334        requires
2335            self.inv(),
2336            self.in_locked_range(),
2337        ensures
2338            self.move_forward_owner_spec()@.mappings == self@.mappings,
2339        decreases NR_LEVELS - self.level,
2340    {
2341        if self.index() + 1 < NR_ENTRIES {
2342            let inc = self.inc_index();
2343            let result = inc.zero_below_level();
2344
2345            inc.zero_preserves_all_but_va();
2346            assert(result.continuations =~= inc.continuations);
2347            assert(result.level == inc.level);
2348
2349            let old_cont = self.continuations[self.level - 1];
2350            let new_cont = old_cont.inc_index();
2351            assert(new_cont.children =~= old_cont.children);
2352            assert(new_cont.entry_own == old_cont.entry_own);
2353            assert(new_cont.path() == old_cont.path());
2354
2355            assert(new_cont.view_mappings() =~= old_cont.view_mappings()) by {
2356                assert forall|m: Mapping|
2357                    old_cont.view_mappings().contains(m) implies new_cont.view_mappings().contains(
2358                    m,
2359                ) by {
2360                    let i = choose|i: int|
2361                        #![auto]
2362                        0 <= i < old_cont.children.len() && old_cont.children[i] is Some
2363                            && PageTableOwner(old_cont.children[i].unwrap()).view_rec(
2364                            old_cont.path().push_tail(i as usize),
2365                        ).contains(m);
2366                    assert(new_cont.children[i] is Some);
2367                    assert(PageTableOwner(new_cont.children[i].unwrap()).view_rec(
2368                        new_cont.path().push_tail(i as usize),
2369                    ).contains(m));
2370                };
2371                assert forall|m: Mapping|
2372                    new_cont.view_mappings().contains(m) implies old_cont.view_mappings().contains(
2373                    m,
2374                ) by {
2375                    let i = choose|i: int|
2376                        #![auto]
2377                        0 <= i < new_cont.children.len() && new_cont.children[i] is Some
2378                            && PageTableOwner(new_cont.children[i].unwrap()).view_rec(
2379                            new_cont.path().push_tail(i as usize),
2380                        ).contains(m);
2381                    assert(old_cont.children[i] is Some);
2382                    assert(PageTableOwner(old_cont.children[i].unwrap()).view_rec(
2383                        old_cont.path().push_tail(i as usize),
2384                    ).contains(m));
2385                };
2386            };
2387
2388            assert(result.view_mappings() =~= self.view_mappings()) by {
2389                assert forall|m: Mapping|
2390                    self.view_mappings().contains(m) implies result.view_mappings().contains(m) by {
2391                    let i = choose|i: int|
2392                        self.level - 1 <= i < NR_LEVELS && (
2393                        #[trigger] self.continuations[i]).view_mappings().contains(m);
2394                    if i == self.level - 1 {
2395                        assert(result.continuations[i].view_mappings().contains(m));
2396                    } else {
2397                        assert(result.continuations[i] == self.continuations[i]);
2398                    }
2399                };
2400                assert forall|m: Mapping|
2401                    result.view_mappings().contains(m) implies self.view_mappings().contains(m) by {
2402                    let i = choose|i: int|
2403                        result.level - 1 <= i < NR_LEVELS && (
2404                        #[trigger] result.continuations[i]).view_mappings().contains(m);
2405                    if i == self.level - 1 {
2406                        assert(self.continuations[i].view_mappings().contains(m));
2407                    } else {
2408                        assert(self.continuations[i] == result.continuations[i]);
2409                    }
2410                };
2411            };
2412        } else if self.level < NR_LEVELS {
2413            let popped = self.pop_level_owner().0;
2414
2415            self.pop_level_owner_preserves_inv();
2416            assert(popped.in_locked_range()) by {
2417                assert(popped.va == self.va);
2418                assert(popped.prefix == self.prefix);
2419                assert(popped.guard_level == self.guard_level);
2420            };
2421
2422            self.pop_level_owner_preserves_mappings();
2423            popped.move_forward_owner_preserves_mappings();
2424        }
2425    }
2426}
2427
2428} // verus!