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