Skip to main content

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

1use vstd::prelude::*;
2
3use vstd_extra::ghost_tree::*;
4use vstd_extra::ownership::*;
5
6use crate::mm::page_table::*;
7use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
8use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
9use crate::specs::arch::paging_consts::PagingConsts;
10use crate::specs::mm::page_table::cursor::owners::*;
11use crate::specs::mm::page_table::node::EntryOwner;
12use crate::specs::mm::page_table::node::GuardPerm;
13use crate::specs::mm::page_table::owners::{OwnerSubtree, PageTableOwner, INC_LEVELS};
14use crate::specs::mm::page_table::AbstractVaddr;
15use crate::specs::mm::Guards;
16use crate::specs::mm::Mapping;
17use crate::specs::mm::MetaRegionOwners;
18
19use crate::specs::mm::frame::mapping::{frame_to_index, meta_to_frame};
20use crate::specs::mm::page_table::cursor::page_size_lemmas::{
21    lemma_page_size_ge_page_size,
22    lemma_page_size_divides,
23};
24use vstd_extra::arithmetic::{
25    lemma_nat_align_down_sound,
26    lemma_nat_align_down_within_block,
27    nat_align_down,
28    nat_align_up,
29};
30use crate::mm::page_table::page_size_spec as page_size;
31
32use core::ops::Range;
33
34verus! {
35
36/// Paths obtained by push_tail with different indices are different
37pub proof fn push_tail_different_indices_different_paths(
38    path: TreePath<NR_ENTRIES>,
39    i: usize,
40    j: usize,
41)
42    requires
43        path.inv(),
44        0 <= i < NR_ENTRIES,
45        0 <= j < NR_ENTRIES,
46        i != j,
47    ensures
48        path.push_tail(i) != path.push_tail(j),
49{
50    path.push_tail_property(i);
51    path.push_tail_property(j);
52    assert(path.push_tail(i).index(path.len() as int) == i as usize);
53    assert(path.push_tail(j).index(path.len() as int) == j as usize);
54    if path.push_tail(i) == path.push_tail(j) {
55        assert(i == j); // Contradiction
56    }
57}
58
59/// Paths with different lengths are different
60pub proof fn different_length_different_paths(
61    path1: TreePath<NR_ENTRIES>,
62    path2: TreePath<NR_ENTRIES>,
63)
64    requires
65        path1.len() != path2.len(),
66    ensures
67        path1 != path2,
68{
69    // Trivial: if path1 == path2, then their lengths are equal
70    if path1 == path2 {
71        assert(path1.len() == path2.len());
72    }
73}
74
75/// A path obtained by push_tail has greater length than the original
76pub proof fn push_tail_increases_length(
77    path: TreePath<NR_ENTRIES>,
78    i: usize,
79)
80    requires
81        path.inv(),
82        0 <= i < NR_ENTRIES,
83    ensures
84        path.push_tail(i).len() > path.len(),
85{
86    path.push_tail_property(i);
87}
88
89/// Upgrade `node_unlocked_except` to `node_unlocked` on a subtree where the excepted
90/// entry cannot appear. The precondition `path == subtree.value.path` ties structural
91/// positions to entry paths. `excepted_path` must differ from all descendant paths,
92/// which is guaranteed when `excepted_path != path` and `excepted_path` is not an
93/// extension of `path` (all descendants have paths extending `path`).
94pub proof fn subtree_unlock_upgrade<'rcu, C: PageTableConfig>(
95    subtree: OwnerSubtree<C>,
96    path: TreePath<NR_ENTRIES>,
97    guards: Guards<'rcu, C>,
98    regions: MetaRegionOwners,
99    excepted_addr: usize,
100    excepted_path: TreePath<NR_ENTRIES>,
101)
102    requires
103        subtree.inv(),
104        PageTableOwner::<C>(subtree).pt_inv(),
105        subtree.tree_predicate_map(path, PageTableOwner::<C>::metaregion_sound_pred(regions)),
106        subtree.tree_predicate_map(path, CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr)),
107        regions.slot_owners[frame_to_index(meta_to_frame(excepted_addr))].paths_in_pt
108            == set![excepted_path],
109        // Structural path == value path
110        path == subtree.value.path,
111        path.inv(),
112        // excepted_path does not match this subtree root
113        path != excepted_path,
114        // excepted_path is not a descendant (all descendants extend path, so if
115        // excepted_path.len() <= path.len() it can't be a descendant; otherwise
116        // it must diverge at some index below path.len())
117        excepted_path.len() <= path.len() ||
118            (exists|k: int| 0 <= k < path.len() && #[trigger] excepted_path.index(k) != path.index(k)),
119    ensures
120        subtree.tree_predicate_map(path, CursorOwner::<'rcu, C>::node_unlocked(guards)),
121    decreases INC_LEVELS - subtree.level,
122{
123    let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
124    let g = CursorOwner::<'rcu, C>::node_unlocked_except(guards, excepted_addr);
125    let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
126
127    assert(f(subtree.value, path));
128    assert(g(subtree.value, path));
129    if subtree.value.is_node() {
130        if subtree.value.node.unwrap().meta_perm.addr() == excepted_addr {
131            // addr == excepted_addr contradicts path != excepted_path
132            // via metaregion_sound's singleton paths_in_pt.
133            let idx = frame_to_index(meta_to_frame(excepted_addr));
134            assert(subtree.value.metaregion_sound(regions));
135            assert(regions.slot_owners[idx].paths_in_pt == set![subtree.value.path]);
136            assert(set![subtree.value.path].contains(excepted_path));
137            assert(false);
138        }
139    }
140    assert(h(subtree.value, path));
141
142    if subtree.level < INC_LEVELS - 1 && subtree.value.is_node() {
143        assert forall |i: int|
144            #![trigger subtree.children[i]]
145            0 <= i < subtree.children.len() && subtree.children[i] is Some implies
146            subtree.children[i].unwrap().tree_predicate_map(path.push_tail(i as usize), h) by {
147            let child = subtree.children[i].unwrap();
148            subtree.map_unroll_once(path, f, i);
149            subtree.map_unroll_once(path, g, i);
150
151            PageTableOwner::<C>(subtree).pt_inv_unroll(i);
152            let child_path = path.push_tail(i as usize);
153            path.push_tail_property(i as usize);
154
155            assert(child_path != excepted_path) by {
156                if excepted_path.len() <= path.len() {
157                } else {
158                    let k = choose|k: int| 0 <= k < path.len() && #[trigger] excepted_path.index(k) != path.index(k);
159                    assert(child_path.index(k) == path.index(k));
160                }
161            };
162
163            assert(excepted_path.len() <= child_path.len() ||
164                (exists|k: int| 0 <= k < child_path.len() && #[trigger] excepted_path.index(k) != child_path.index(k))) by {
165                if excepted_path.len() <= path.len() {
166                } else {
167                    let k = choose|k: int| 0 <= k < path.len() && #[trigger] excepted_path.index(k) != path.index(k);
168                    assert(child_path.index(k) == path.index(k));
169                }
170            };
171
172            subtree_unlock_upgrade(child, child_path, guards, regions, excepted_addr, excepted_path);
173        };
174    } else if subtree.level < INC_LEVELS - 1 && !subtree.value.is_node() {
175        // Non-node: pt_inv gives children[i] is None, so tree_predicate_map
176        // has no children to recurse into.
177        assert forall |i: int|
178            #![trigger subtree.children[i]]
179            0 <= i < subtree.children.len() && subtree.children[i] is Some implies
180            subtree.children[i].unwrap().tree_predicate_map(path.push_tail(i as usize), h) by {
181            PageTableOwner::<C>(subtree).pt_inv_non_node(i);
182        };
183    }
184}
185
186impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
187
188    /// The number of steps it will take to walk through every node of a full
189    /// page table at level `level`
190    pub open spec fn max_steps_subtree(level: usize) -> nat
191        decreases level,
192    {
193        if level <= 1 {
194            NR_ENTRIES as nat
195        } else {
196            (NR_ENTRIES as nat) * (Self::max_steps_subtree((level - 1) as usize) + 1)
197        }
198    }
199
200    /// The number of steps it will take to walk through the remaining entries of the page table
201    /// starting at the given level.
202    pub open spec fn max_steps_partial(self, level: usize) -> nat
203        decreases NR_LEVELS - level,
204        when level <= NR_LEVELS
205    {
206        if level == NR_LEVELS {
207            0
208        } else {
209            // How many entries remain at this level?
210            let cont = self.continuations[(level - 1) as int];
211            // Each entry takes at most `max_step_subtree` steps.
212            let steps = Self::max_steps_subtree(level) * ((NR_ENTRIES - cont.idx) as nat);
213            // Then the number of steps for the remaining entries at higher levels
214            let remaining_steps = self.max_steps_partial((level + 1) as usize);
215            steps + remaining_steps
216        }
217    }
218
219    pub open spec fn max_steps(self) -> nat {
220        self.max_steps_partial(self.level as usize)
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,
237            forall |k: int|
238                start - 1 <= k < NR_LEVELS ==> #[trigger] self.continuations[k].idx == other.continuations[k].idx,
239        ensures
240            self.max_steps_partial(start) == other.max_steps_partial(start),
241        decreases NR_LEVELS - start,
242    {
243        if start < NR_LEVELS {
244            self.max_steps_partial_eq(other, (start + 1) as usize);
245        }
246    }
247
248    pub proof fn max_steps_partial_inv(self, other: Self, level: usize)
249        requires
250            self.inv(),
251            other.inv(),
252            self.level == other.level,
253            self.level <= level <= NR_LEVELS,
254            forall |i: int|
255                #![trigger self.continuations[i].idx]
256                #![trigger other.continuations[i].idx]
257            self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].idx == other.continuations[i].idx,
258        ensures
259            self.max_steps_partial(level) == other.max_steps_partial(level),
260        decreases NR_LEVELS - level,
261    {
262        if level < NR_LEVELS {
263            self.max_steps_partial_inv(other, (level + 1) as usize);
264        }
265    }
266
267    pub open spec fn push_level_owner_spec(self, guard_perm: GuardPerm<'rcu, C>) -> Self
268    {
269        let cont = self.continuations[self.level - 1];
270        let (child, cont) = cont.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm);
271        let new_continuations = self.continuations.insert(self.level - 1, cont);
272        let new_continuations = new_continuations.insert(self.level - 2, child);
273
274        let new_level = (self.level - 1) as u8;
275        Self {
276            continuations: new_continuations,
277            level: new_level,
278            popped_too_high: false,
279            ..self
280        }
281    }
282
283    pub proof fn push_level_owner_decreases_steps(self, guard_perm: GuardPerm<'rcu, C>)
284        requires
285            self.inv(),
286            self.level > 0,
287        ensures
288            self.push_level_owner_spec(guard_perm).max_steps() < self.max_steps()
289    { admit() }
290
291    pub proof fn push_level_owner_preserves_va(self, guard_perm: GuardPerm<'rcu, C>)
292        requires
293            self.inv(),
294            self.level > 1,
295        ensures
296            self.push_level_owner_spec(guard_perm).va == self.va,
297            self.push_level_owner_spec(guard_perm).continuations[self.level - 2].idx == self.va.index[self.level - 2],
298    {
299        assert(self.va.index.contains_key(self.level - 2));
300    }
301
302    pub proof fn push_level_owner_preserves_mappings(self, guard_perm: GuardPerm<'rcu, C>)
303        requires
304            self.inv(),
305            self.level > 1,
306            self.cur_entry_owner().is_node(),
307        ensures
308            self.push_level_owner_spec(guard_perm)@.mappings == self@.mappings,
309    {
310        let new_owner = self.push_level_owner_spec(guard_perm);
311        let old_cont = self.continuations[self.level - 1];
312        let (child_cont, modified_cont) = old_cont.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm);
313
314        assert(old_cont.all_some());
315        old_cont.view_mappings_take_child();
316
317        let taken = old_cont.take_child_spec().1;
318
319        assert(modified_cont.children =~= taken.children) by {
320            assert forall |j: int| 0 <= j < modified_cont.children.len()
321                implies modified_cont.children[j] == taken.children[j] by {
322                if j == old_cont.idx as int {
323                    assert(modified_cont.children[j] is None);
324                    assert(taken.children[j] is None);
325                } else {
326                    assert(modified_cont.children[j] == old_cont.children[j]);
327                }
328            };
329        };
330        assert(modified_cont.view_mappings() =~= taken.view_mappings()) by {
331            assert(modified_cont.path() == taken.path());
332        };
333
334        old_cont.inv_children_rel_unroll(old_cont.idx as int);
335        let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
336        let child_path = old_cont.path().push_tail(old_cont.idx as usize);
337        assert(child_cont.children == child_subtree.children);
338        assert(child_cont.path() == child_path);
339        assert(child_subtree.value.is_node());
340        assert(child_path.len() < INC_LEVELS - 1) by {
341            assert(old_cont.tree_level < INC_LEVELS - 1);
342            assert(old_cont.entry_own.inv_base());
343            old_cont.path().push_tail_property(old_cont.idx as usize);
344        };
345        old_cont.inv_children_unroll(old_cont.idx as int);
346        assert(child_subtree.inv());
347        let pto = PageTableOwner(child_subtree);
348        assert(pto.view_rec(child_path) =~= child_cont.view_mappings()) by {
349            assert forall |m: Mapping| #[trigger] child_cont.view_mappings().contains(m) implies
350                pto.view_rec(child_path).contains(m) by {
351                let j = choose |j: int| #![auto]
352                    0 <= j < child_cont.children.len()
353                    && child_cont.children[j] is Some
354                    && PageTableOwner(child_cont.children[j].unwrap()).view_rec(
355                        child_cont.path().push_tail(j as usize)).contains(m);
356                assert(pto.0.children[j] is Some);
357                assert(pto.0.children[j] == child_cont.children[j]);
358            };
359            assert forall |m: Mapping| pto.view_rec(child_path).contains(m) implies
360                #[trigger] child_cont.view_mappings().contains(m) by {
361                let j = choose |j: int|
362                    #![trigger pto.0.children[j]]
363                    0 <= j < pto.0.children.len()
364                    && pto.0.children[j] is Some
365                    && PageTableOwner(pto.0.children[j].unwrap()).view_rec(
366                        child_path.push_tail(j as usize)).contains(m);
367                assert(child_cont.children[j] == pto.0.children[j]);
368                assert(child_cont.children[j] is Some);
369            };
370        };
371        assert(child_cont.view_mappings() =~= old_cont.view_mappings_take_child_spec());
372
373        assert forall |m: Mapping| self.view_mappings().contains(m)
374            implies new_owner.view_mappings().contains(m) by {
375            let i = choose |i: int|
376                self.level - 1 <= i < NR_LEVELS
377                && (#[trigger] self.continuations[i]).view_mappings().contains(m);
378            if i == self.level - 1 {
379                if old_cont.view_mappings_take_child_spec().contains(m) {
380                    assert(new_owner.continuations[self.level - 2].view_mappings().contains(m));
381                } else {
382                    assert(taken.view_mappings().contains(m));
383                    assert(modified_cont.view_mappings().contains(m));
384                    assert(new_owner.continuations[self.level - 1].view_mappings().contains(m));
385                }
386            } else {
387                assert(new_owner.continuations[i] == self.continuations[i]);
388            }
389        };
390        assert forall |m: Mapping| new_owner.view_mappings().contains(m)
391            implies self.view_mappings().contains(m) by {
392            let i = choose |i: int|
393                new_owner.level - 1 <= i < NR_LEVELS
394                && (#[trigger] new_owner.continuations[i]).view_mappings().contains(m);
395            if i == self.level - 2 {
396                assert(child_cont.view_mappings().contains(m));
397                assert(old_cont.view_mappings_take_child_spec().contains(m));
398                // view_mappings_take_child_spec() = PTO(children[idx]).view_rec(...)
399                // The containment in view_mappings follows directly for i == idx.
400                let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
401                assert(PageTableOwner(child_subtree).view_rec(
402                    old_cont.path().push_tail(old_cont.idx as usize)).contains(m));
403                assert(old_cont.view_mappings().contains(m));
404                assert(self.continuations[self.level - 1].view_mappings().contains(m));
405            } else if i == self.level - 1 {
406                assert(modified_cont.view_mappings().contains(m));
407                assert(taken.view_mappings().contains(m));
408                // taken.view_mappings() == old_cont.view_mappings() - child_spec ⊆ view_mappings.
409                assert(old_cont.view_mappings().contains(m));
410                assert(self.continuations[self.level - 1].view_mappings().contains(m));
411            } else {
412                assert(self.continuations[i] == new_owner.continuations[i]);
413            }
414        };
415        assert(new_owner.view_mappings() =~= self.view_mappings());
416    }
417
418    pub proof fn push_level_owner_preserves_inv(self, guard_perm: GuardPerm<'rcu, C>)
419        requires
420            self.inv(),
421            self.level > 1,
422            !self.popped_too_high,
423            self.level < self.guard_level,
424            // The current entry is a node (we're descending into it)
425            self.cur_entry_owner().is_node(),
426            // The child node's guard relates to the new guard_perm
427            self.cur_entry_owner().node.unwrap().relate_guard_perm(guard_perm),
428            // Guard distinctness: the new guard_perm points to a different node than all existing continuations
429            forall |i: int|
430                #![trigger self.continuations[i]]
431                self.level - 1 <= i < NR_LEVELS ==>
432                    self.continuations[i].guard_perm.value().inner.inner@.ptr.addr()
433                        != guard_perm.value().inner.inner@.ptr.addr(),
434        ensures
435            self.push_level_owner_spec(guard_perm).inv(),
436    {
437        let new_owner = self.push_level_owner_spec(guard_perm);
438        let new_level = (self.level - 1) as u8;
439
440        let old_cont = self.continuations[self.level - 1];
441        old_cont.inv_children_unroll(old_cont.idx as int);
442        let child_node = old_cont.children[old_cont.idx as int].unwrap();
443        let (child, modified_cont) = old_cont.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm);
444
445        old_cont.inv_children_rel_unroll(old_cont.idx as int);
446        assert(child.entry_own == child_node.value);
447        assert(child.entry_own == self.cur_entry_owner());
448        assert(child.children == child_node.children);
449        assert(child.tree_level == old_cont.tree_level + 1);
450
451        reveal(CursorContinuation::inv_children);
452
453        assert(self.va.inv());
454        assert(self.va.index.contains_key(self.level - 2));
455        assert(0 <= self.va.index[self.level - 2] < NR_ENTRIES);
456        assert(child.idx == self.va.index[self.level - 2] as usize);
457
458        assert(child.entry_own.inv()) by {
459            old_cont.inv_children_unroll(old_cont.idx as int);
460        };
461
462        assert(child.entry_own.path.len() == old_cont.entry_own.node.unwrap().tree_level + 1);
463        assert(old_cont.entry_own.node.unwrap().tree_level == old_cont.tree_level) by {
464            assert(old_cont.tree_level == INC_LEVELS - old_cont.level() - 1);
465        };
466        assert(child.entry_own.path.len() == child.tree_level) by {
467            assert(child.tree_level == old_cont.tree_level + 1);
468        };
469
470        assert(child.entry_own.node.unwrap().tree_level == child.entry_own.path.len()) by {
471            assert(child.children[0] is Some);
472            let gc = child.children[0].unwrap();
473            assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
474                child.entry_own, 0, Some(gc.value)));
475            assert(gc.value.path.len() == child.entry_own.node.unwrap().tree_level + 1);
476            assert(gc.value.path == child.entry_own.path.push_tail(0usize));
477            assert(child.entry_own.inv_base());
478            assert(child.entry_own.path.inv());
479            child.entry_own.path.push_tail_property(0usize);
480            assert(child.entry_own.path.push_tail(0usize).len() == child.entry_own.path.len() + 1);
481        };
482
483        assert(child.tree_level == child.entry_own.node.unwrap().tree_level);
484        assert(child.tree_level == INC_LEVELS - child.level() - 1);
485
486        assert(child.inv_children()) by {
487            assert forall |j: int| 0 <= j < child.children.len() && #[trigger] child.children[j] is Some
488                implies child.children[j].unwrap().inv() by {
489                assert(child.children[j] == child_node.children[j]);
490                old_cont.inv_children_unroll(old_cont.idx as int);
491            };
492        };
493        assert(child.inv_children_rel()) by {
494            assert forall |j: int| 0 <= j < NR_ENTRIES && #[trigger] child.children[j] is Some
495                implies {
496                    &&& child.children[j].unwrap().value.parent_level == child.level()
497                    &&& child.children[j].unwrap().level == child.tree_level + 1
498                    &&& !child.children[j].unwrap().value.in_scope
499                    &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
500                        child.entry_own, j, Some(child.children[j].unwrap().value))
501                    &&& child.children[j].unwrap().value.path == child.path().push_tail(j as usize)
502                } by {
503                let gc = child.children[j].unwrap();
504                assert(child.children[j] == child_node.children[j]);
505                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
506                    child.entry_own, j, Some(gc.value)));
507                child.inv_children_unroll(j);
508                assert(gc.inv());
509            };
510        };
511        assert(child.inv());
512
513        assert(new_owner.continuations[new_owner.level - 1].all_some()) by {
514            assert(new_owner.continuations[new_owner.level - 1] == child);
515            assert forall |j: int| 0 <= j < NR_ENTRIES implies child.children[j] is Some by {
516                if child.children[j] is None {
517                    assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
518                        child.entry_own, j, None));
519                }
520            };
521        };
522
523        assert(modified_cont.all_but_index_some()) by {
524            assert(modified_cont.children[modified_cont.idx as int] is None);
525            assert forall |i: int| 0 <= i < modified_cont.idx implies
526                modified_cont.children[i] is Some by {
527                assert(modified_cont.children[i] == old_cont.children[i]);
528            };
529            assert forall |i: int| modified_cont.idx < i < NR_ENTRIES implies
530                modified_cont.children[i] is Some by {
531                assert(modified_cont.children[i] == old_cont.children[i]);
532            };
533        };
534
535        assert(forall|i: int| new_owner.level <= i < NR_LEVELS ==> {
536            (#[trigger] new_owner.continuations[i]).all_but_index_some()
537        }) by {
538            assert forall |i: int| new_owner.level <= i < NR_LEVELS implies
539                (#[trigger] new_owner.continuations[i]).all_but_index_some() by {
540                if i == self.level - 1 {
541                    assert(new_owner.continuations[i] == modified_cont);
542                } else {
543                    // i >= self.level, unchanged from old state
544                    assert(new_owner.continuations[i] == self.continuations[i]);
545                }
546            };
547        };
548
549        // Flattened: hoist inv_children and inv_children_rel proofs so the
550        // inner `assert forall` blocks live at depth 2.
551        assert(modified_cont.children.len() == NR_ENTRIES);
552        assert(0 <= modified_cont.idx < NR_ENTRIES);
553        assert(modified_cont.inv_children()) by {
554            assert forall |i: int| 0 <= i < modified_cont.children.len() && #[trigger] modified_cont.children[i] is Some
555                implies modified_cont.children[i].unwrap().inv() by {
556                assert(i != modified_cont.idx);
557                assert(modified_cont.children[i] == old_cont.children[i]);
558                old_cont.inv_children_unroll(i);
559            };
560        };
561        assert(modified_cont.inv_children_rel()) by {
562            assert forall |i: int| 0 <= i < NR_ENTRIES && #[trigger] modified_cont.children[i] is Some
563                implies {
564                    &&& modified_cont.children[i].unwrap().value.parent_level == modified_cont.level()
565                    &&& modified_cont.children[i].unwrap().level == modified_cont.tree_level + 1
566                    &&& !modified_cont.children[i].unwrap().value.in_scope
567                    &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
568                        modified_cont.entry_own, i, Some(modified_cont.children[i].unwrap().value))
569                    &&& modified_cont.children[i].unwrap().value.path == modified_cont.path().push_tail(i as usize)
570                } by {
571                assert(i != modified_cont.idx);
572                assert(modified_cont.children[i] == old_cont.children[i]);
573                assert(old_cont.inv_children_rel());
574            };
575        };
576        assert(modified_cont.entry_own.is_node());
577        assert(modified_cont.entry_own.inv());
578        assert(modified_cont.entry_own.node.unwrap().relate_guard_perm(modified_cont.guard_perm));
579        assert(modified_cont.tree_level == INC_LEVELS - modified_cont.level() - 1);
580        assert(modified_cont.tree_level < INC_LEVELS - 1);
581        assert(modified_cont.path().len() == modified_cont.tree_level);
582        assert(modified_cont.inv());
583
584        assert(new_owner.level <= 4 ==> {
585            &&& new_owner.continuations.contains_key(3)
586            &&& new_owner.continuations[3].inv()
587            &&& new_owner.continuations[3].level() == 4
588            &&& new_owner.continuations[3].entry_own.parent_level == 5
589            &&& new_owner.va.index[3] == new_owner.continuations[3].idx
590        }) by {
591            if new_owner.level <= 4 {
592                if self.level == 4 {
593                    assert(new_owner.continuations[3] == modified_cont);
594                } else {
595                    assert(new_owner.continuations[3] == self.continuations[3]);
596                }
597            }
598        };
599
600        // Level 3 condition: new_level <= 3 ==> continuations[2] ...
601        assert(new_owner.level <= 3 ==> {
602            &&& new_owner.continuations.contains_key(2)
603            &&& new_owner.continuations[2].inv()
604            &&& new_owner.continuations[2].level() == 3
605            &&& new_owner.continuations[2].entry_own.parent_level == 4
606            &&& new_owner.va.index[2] == new_owner.continuations[2].idx
607            &&& new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr() !=
608                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
609            &&& new_owner.continuations[2].path() == new_owner.continuations[3].path().push_tail(new_owner.continuations[3].idx as usize)
610            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
611                    new_owner.continuations[3].entry_own, new_owner.continuations[3].idx as int,
612                    Some(new_owner.continuations[2].entry_own))
613        }) by {
614            if new_owner.level <= 3 {
615                if self.level == 4 {
616                    assert(self.va.index.contains_key(2));
617                    assert(new_owner.continuations[2].guard_perm == guard_perm);
618                    assert(new_owner.continuations[3] == modified_cont);
619                    assert(modified_cont.guard_perm == old_cont.guard_perm);
620                    // guard distinctness
621                    assert(new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr() !=
622                           new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()) by {
623                        assert(self.continuations[self.level - 1].guard_perm.value().inner.inner@.ptr.addr()
624                            != guard_perm.value().inner.inner@.ptr.addr());
625                    };
626                    // path consistency: child.path() == modified_cont.path().push_tail(modified_cont.idx)
627                    assert(new_owner.continuations[2].path() == new_owner.continuations[3].path().push_tail(new_owner.continuations[3].idx as usize)) by {
628                        assert(modified_cont.path() == old_cont.path());
629                        assert(modified_cont.idx == old_cont.idx);
630                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
631                    };
632                    // PTE consistency: from old_cont.inv_children_rel at idx
633                    assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
634                        new_owner.continuations[3].entry_own, new_owner.continuations[3].idx as int,
635                        Some(new_owner.continuations[2].entry_own))) by {
636                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
637                    };
638                } else {
639                    // self.level <= 3: from self.inv()
640                }
641            }
642        };
643
644        // Level 2 condition: new_level <= 2 ==> continuations[1] ...
645        assert(new_owner.level <= 2 ==> {
646            &&& new_owner.continuations.contains_key(1)
647            &&& new_owner.continuations[1].inv()
648            &&& new_owner.continuations[1].level() == 2
649            &&& new_owner.continuations[1].entry_own.parent_level == 3
650            &&& new_owner.va.index[1] == new_owner.continuations[1].idx
651            &&& new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
652                new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
653            &&& new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
654                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
655            &&& new_owner.continuations[1].path() == new_owner.continuations[2].path().push_tail(new_owner.continuations[2].idx as usize)
656            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
657                    new_owner.continuations[2].entry_own, new_owner.continuations[2].idx as int,
658                    Some(new_owner.continuations[1].entry_own))
659        }) by {
660            if new_owner.level <= 2 {
661                if self.level == 3 {
662                    assert(self.va.index.contains_key(1));
663                    assert(new_owner.continuations[1].guard_perm == guard_perm);
664                    assert(new_owner.continuations[2] == modified_cont);
665                    assert(modified_cont.guard_perm == old_cont.guard_perm);
666
667                    assert(new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
668                           new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr()) by {
669                        assert(self.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
670                            != guard_perm.value().inner.inner@.ptr.addr());
671                    };
672                    assert(new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
673                           new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()) by {
674                        assert(self.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
675                            != guard_perm.value().inner.inner@.ptr.addr());
676                    };
677                    // path: child.path() == modified_cont.path().push_tail(modified_cont.idx)
678                    assert(new_owner.continuations[1].path() == new_owner.continuations[2].path().push_tail(new_owner.continuations[2].idx as usize)) by {
679                        assert(modified_cont.path() == old_cont.path());
680                        assert(modified_cont.idx == old_cont.idx);
681                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
682                    };
683                    // child properties: level, parent_level from tree_level
684                    assert(old_cont.level() == 3);
685                    assert(child.entry_own.parent_level == 3) by {
686                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
687                    };
688                    // PTE consistency: from old_cont.inv_children_rel at idx
689                    assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
690                        new_owner.continuations[2].entry_own, new_owner.continuations[2].idx as int,
691                        Some(new_owner.continuations[1].entry_own))) by {
692                        old_cont.inv_children_rel_unroll(old_cont.idx as int);
693                    };
694                } else {
695                    // self.level == 2: both continuations unchanged
696                }
697            }
698        };
699
700        // Level 1 condition: new_level == 1 ==> continuations[0] exists and is valid
701        assert(new_owner.level == 1 ==> {
702            &&& new_owner.continuations.contains_key(0)
703            &&& new_owner.continuations[0].inv()
704            &&& new_owner.continuations[0].level() == 1
705            &&& new_owner.continuations[0].entry_own.parent_level == 2
706            &&& new_owner.va.index[0] == new_owner.continuations[0].idx
707            &&& new_owner.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
708                new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr()
709            &&& new_owner.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
710                new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
711            &&& new_owner.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
712                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
713            &&& new_owner.continuations[0].path() == new_owner.continuations[1].path().push_tail(new_owner.continuations[1].idx as usize)
714            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
715                    new_owner.continuations[1].entry_own, new_owner.continuations[1].idx as int,
716                    Some(new_owner.continuations[0].entry_own))
717        }) by {
718            if new_owner.level == 1 {
719                // self.level == 2, new_level == 1
720                assert(new_owner.continuations[0].guard_perm == guard_perm);
721                assert(new_owner.continuations[1] == modified_cont);
722                assert(modified_cont.guard_perm == old_cont.guard_perm);
723
724                // Guard distinctness from precondition
725                assert(self.continuations[1].guard_perm.value().inner.inner@.ptr.addr()
726                    != guard_perm.value().inner.inner@.ptr.addr());
727                assert(self.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
728                    != guard_perm.value().inner.inner@.ptr.addr());
729                assert(self.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
730                    != guard_perm.value().inner.inner@.ptr.addr());
731
732                // child.level() == 1: from tree_level arithmetic
733                // old_cont = continuations[1], old_cont.level() == 2 (from self.inv() level <= 2)
734                assert(old_cont.level() == 2);
735                // child.tree_level == old_cont.tree_level + 1
736                // old_cont.tree_level == INC_LEVELS - 2 - 1 == 2
737                // child.tree_level == 3
738                // child.level() == INC_LEVELS - child.tree_level - 1 == 5 - 3 - 1 == 1
739                assert(child.tree_level == INC_LEVELS - child.level() - 1);
740
741                // parent_level == 2: from inv_children_rel on old_cont
742                assert(child.entry_own.parent_level == 2) by {
743                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
744                    assert(child.entry_own.parent_level == old_cont.level());
745                };
746
747                // idx match
748                assert(new_owner.va.index[0] == child.idx);
749
750                // path consistency: child.path() == modified_cont.path().push_tail(modified_cont.idx)
751                assert(child.path() == modified_cont.path().push_tail(modified_cont.idx as usize)) by {
752                    assert(modified_cont.path() == old_cont.path());
753                    assert(modified_cont.idx == old_cont.idx);
754                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
755                    assert(child.entry_own.path == old_cont.path().push_tail(old_cont.idx as usize));
756                };
757
758                // PTE consistency: from old_cont.inv_children_rel at idx
759                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
760                    new_owner.continuations[1].entry_own, new_owner.continuations[1].idx as int,
761                    Some(new_owner.continuations[0].entry_own))) by {
762                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
763                };
764            }
765        };
766
767    }
768
769    pub proof fn push_level_owner_preserves_invs(self, guard_perm: GuardPerm<'rcu, C>, regions: MetaRegionOwners, guards: Guards<'rcu, C>)
770        requires
771            self.inv(),
772            self.level > 1,
773            !self.popped_too_high,
774            self.level < self.guard_level,
775            self.only_current_locked(guards),
776            self.nodes_locked(guards),
777            self.metaregion_sound(regions),
778            // The current entry is a node (we're descending into it)
779            self.cur_entry_owner().is_node(),
780            // The child node's guard relates to the new guard_perm
781            self.cur_entry_owner().node.unwrap().relate_guard_perm(guard_perm),
782            // The new guard_perm must be locked in guards
783            guards.lock_held(guard_perm.value().inner.inner@.ptr.addr()),
784        ensures
785            self.push_level_owner_spec(guard_perm).inv(),
786            self.push_level_owner_spec(guard_perm).children_not_locked(guards),
787            self.push_level_owner_spec(guard_perm).nodes_locked(guards),
788            self.push_level_owner_spec(guard_perm).metaregion_sound(regions),
789    {
790        reveal(CursorContinuation::inv_children);
791        let new_owner = self.push_level_owner_spec(guard_perm);
792        let old_cont = self.continuations[self.level - 1];
793        old_cont.inv_children_unroll_all();
794        let (child_cont, modified_cont) = old_cont.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm);
795
796        let cur_entry = self.cur_entry_owner();
797        let cur_entry_addr = cur_entry.node.unwrap().meta_perm.addr();
798        let cur_entry_path = old_cont.path().push_tail(old_cont.idx as usize);
799        self.cont_entries_metaregion(regions);
800
801        assert forall |i: int|
802            #![trigger self.continuations[i]]
803            self.level - 1 <= i < NR_LEVELS implies
804                self.continuations[i].guard_perm.value().inner.inner@.ptr.addr()
805                    != guard_perm.value().inner.inner@.ptr.addr() by {
806            let cont_i = self.continuations[i];
807
808            if cont_i.guard_perm.value().inner.inner@.ptr.addr()
809                == guard_perm.value().inner.inner@.ptr.addr()
810            {
811                let addr = cont_i.entry_own.node.unwrap().meta_perm.addr();
812                assert(addr == cur_entry.node.unwrap().meta_perm.addr());
813                let idx = frame_to_index(meta_to_frame(addr));
814                assert(regions.slot_owners[idx].paths_in_pt == set![cont_i.path()]);
815                assert(regions.slot_owners[idx].paths_in_pt == set![cur_entry_path]);
816                assert(set![cont_i.path()].contains(cur_entry_path));
817
818                assert(cur_entry_path.len() == old_cont.tree_level + 1) by {
819                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
820                    old_cont.entry_own.path.push_tail_property(old_cont.idx as usize);
821                };
822                assert(cont_i.tree_level <= old_cont.tree_level) by {
823                    if self.level as int == 1 {
824                        assert(old_cont.level() == 1);
825                    } else if self.level as int == 2 {
826                        assert(old_cont.level() == 2);
827                    } else if self.level as int == 3 {
828                        assert(old_cont.level() == 3);
829                    } else {
830                        assert(old_cont.level() == 4);
831                    }
832                };
833                assert(false);
834            }
835        };
836        self.push_level_owner_preserves_inv(guard_perm);
837
838        let excepted_idx = frame_to_index(meta_to_frame(cur_entry_addr));
839        assert(regions.slot_owners[excepted_idx].paths_in_pt == set![cur_entry_path]) by {
840            old_cont.inv_children_rel_unroll(old_cont.idx as int);
841        };
842
843        let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
844        let g_except = CursorOwner::<'rcu, C>::node_unlocked_except(guards, cur_entry_addr);
845        let h = CursorOwner::<'rcu, C>::node_unlocked(guards);
846
847        // Flattened: hoist the outer `assert(children_not_locked) by { ... }`
848        // wrapper so the per-level `assert forall` sits at depth 1 and its
849        // inner `assert forall |j|` / `assert ... by` blocks are at depth 2.
850        assert forall |i: int|
851            #![trigger new_owner.continuations[i]]
852            new_owner.level - 1 <= i < NR_LEVELS implies
853            new_owner.continuations[i].map_children(h) by {
854
855            if i == self.level - 2 {
856                assert(new_owner.continuations[i] == child_cont);
857                assert forall |j: int|
858                    #![trigger child_cont.children[j]]
859                    0 <= j < child_cont.children.len() && child_cont.children[j] is Some implies
860                    child_cont.children[j].unwrap().tree_predicate_map(
861                        child_cont.path().push_tail(j as usize), h) by {
862                    let gc = child_cont.children[j].unwrap();
863                    let gc_path = child_cont.path().push_tail(j as usize);
864                    child_cont.inv_children_unroll(j);
865                    child_cont.inv_children_rel_unroll(j);
866                    child_cont.path().push_tail_property(j as usize);
867
868                    let child_subtree = old_cont.children[old_cont.idx as int].unwrap();
869                    child_subtree.map_unroll_once(cur_entry_path, f, j);
870                    child_subtree.map_unroll_once(cur_entry_path, g_except, j);
871
872                    assert(child_cont.path() == cur_entry_path);
873                    assert(gc_path == cur_entry_path.push_tail(j as usize));
874                    assert(cur_entry_path.len() < gc_path.len());
875                    child_cont.pt_inv_children_unroll(j);
876                    subtree_unlock_upgrade(gc, gc_path, guards, regions,
877                        cur_entry_addr, cur_entry_path);
878                };
879            } else if i == self.level - 1 {
880                assert(new_owner.continuations[i] == modified_cont);
881                assert(modified_cont.path() == old_cont.path());
882                assert forall |j: int|
883                    #![trigger modified_cont.children[j]]
884                    0 <= j < modified_cont.children.len() && modified_cont.children[j] is Some implies
885                    modified_cont.children[j].unwrap().tree_predicate_map(
886                        modified_cont.path().push_tail(j as usize), h) by {
887                    assert(j != old_cont.idx as int);
888                    assert(modified_cont.children[j] == old_cont.children[j]);
889                    let sibling = old_cont.children[j].unwrap();
890                    let sibling_path = old_cont.path().push_tail(j as usize);
891                    old_cont.inv_children_unroll(j);
892                    old_cont.inv_children_rel_unroll(j);
893                    old_cont.path().push_tail_property(j as usize);
894
895                    push_tail_different_indices_different_paths(old_cont.path(), j as usize, old_cont.idx);
896                    // `cur_entry_path.len() <= sibling_path.len()` previously had its own
897                    // `by { ... }` block at depth 3; inline its facts instead.
898                    old_cont.inv_children_rel_unroll(old_cont.idx as int);
899                    old_cont.path().push_tail_property(old_cont.idx as usize);
900                    assert(cur_entry_path.len() <= sibling_path.len());
901                    old_cont.pt_inv_children_unroll(j);
902                    subtree_unlock_upgrade(sibling, sibling_path, guards, regions,
903                        cur_entry_addr, cur_entry_path);
904                };
905            } else {
906                assert(new_owner.continuations[i] == self.continuations[i]);
907                let cont_i = self.continuations[i];
908
909                // The `cur_entry_path.index(...) == cont_i.idx` fact used to be
910                // proved inside an inner `assert(...) by { ... }` block at depth 3.
911                // Inlined with its helper lemma calls below.
912                old_cont.entry_own.path.push_tail_property(old_cont.idx as usize);
913                if i == self.level as int {
914                    assert(old_cont.path() == cont_i.path().push_tail(cont_i.idx as usize));
915                    cont_i.entry_own.path.push_tail_property(cont_i.idx as usize);
916                } else if i == self.level as int + 1 {
917                    let cont_sl = self.continuations[self.level as int];
918                    assert(old_cont.path() == cont_sl.path().push_tail(cont_sl.idx as usize));
919                    assert(cont_sl.path() == cont_i.path().push_tail(cont_i.idx as usize));
920                    cont_i.entry_own.path.push_tail_property(cont_i.idx as usize);
921                    cont_i.path().push_tail(cont_i.idx as usize).push_tail_property(cont_sl.idx as usize);
922                } else {
923                    let cont_sl = self.continuations[self.level as int];
924                    let cont_sl1 = self.continuations[self.level as int + 1];
925                    assert(old_cont.path() == cont_sl.path().push_tail(cont_sl.idx as usize));
926                    assert(cont_sl.path() == cont_sl1.path().push_tail(cont_sl1.idx as usize));
927                    assert(cont_sl1.path() == cont_i.path().push_tail(cont_i.idx as usize));
928                    cont_i.entry_own.path.push_tail_property(cont_i.idx as usize);
929                    cont_i.path().push_tail(cont_i.idx as usize).push_tail_property(cont_sl1.idx as usize);
930                    cont_sl1.path().push_tail(cont_sl1.idx as usize).push_tail_property(cont_sl.idx as usize);
931                }
932                assert(cur_entry_path.index(cont_i.tree_level as int) == cont_i.idx as usize);
933
934                assert forall |j: int|
935                    #![trigger cont_i.children[j]]
936                    0 <= j < cont_i.children.len() && cont_i.children[j] is Some implies
937                    cont_i.children[j].unwrap().tree_predicate_map(
938                        cont_i.path().push_tail(j as usize), h) by {
939                    let child_sub = cont_i.children[j].unwrap();
940                    let child_path = cont_i.path().push_tail(j as usize);
941                    cont_i.inv_children_unroll(j);
942                    cont_i.inv_children_rel_unroll(j);
943                    cont_i.path().push_tail_property(j as usize);
944
945                    assert(child_path.index(cont_i.tree_level as int) == j as usize);
946                    assert(j != cont_i.idx as int);
947                    assert(child_path.index(cont_i.tree_level as int)
948                        != cur_entry_path.index(cont_i.tree_level as int));
949                    assert(cont_i.tree_level < child_path.len());
950                    cont_i.pt_inv_children_unroll(j);
951                    subtree_unlock_upgrade(child_sub, child_path, guards, regions,
952                        cur_entry_addr, cur_entry_path);
953                };
954            }
955        };
956        assert(new_owner.children_not_locked(guards));
957        assert forall |i: int|
958            #![trigger new_owner.continuations[i]]
959            new_owner.level - 1 <= i < NR_LEVELS implies
960            new_owner.continuations[i].node_locked(guards) by {
961
962            if i == self.level - 2 {
963                assert(new_owner.continuations[i] == child_cont);
964                assert(child_cont.guard_perm == guard_perm);
965            } else if i == self.level - 1 {
966                assert(new_owner.continuations[i] == modified_cont);
967                assert(modified_cont.guard_perm == old_cont.guard_perm);
968            } else {
969                assert(new_owner.continuations[i] == self.continuations[i]);
970            }
971        };
972        assert(new_owner.nodes_locked(guards));
973
974        let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
975        let child_subtree = child_cont.as_subtree();
976
977        assert(child_subtree.inv_children()) by {
978            assert forall |j: int| 0 <= j < NR_ENTRIES implies
979                match #[trigger] child_subtree.children[j] {
980                    Some(ch) => {
981                        &&& ch.level == child_subtree.level + 1
982                        &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, j, Some(ch.value))
983                    },
984                    None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, j, None),
985                }
986            by {
987                assert(child_cont.children[j] is Some);
988                let ch = child_cont.children[j].unwrap();
989                assert(ch.level == child_cont.tree_level + 1);
990                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
991                    child_cont.entry_own, j, Some(ch.value)));
992            };
993        };
994        assert forall |j: int| 0 <= j < NR_ENTRIES implies
995            match #[trigger] child_subtree.children[j] {
996                Some(ch) => ch.inv(),
997                None => true,
998            }
999        by {
1000            child_cont.inv_children_unroll(j);
1001        };
1002        assert(child_subtree.inv()) by {
1003            assert(child_subtree.inv_node());
1004        };
1005
1006        // Pre-prove tree_predicate_map for child_subtree (f)
1007        assert(child_subtree.tree_predicate_map(child_cont.path(), f)) by {
1008            assert(f(child_subtree.value, child_cont.path()));
1009            assert forall |j: int| 0 <= j < child_subtree.children.len() implies
1010                match #[trigger] child_subtree.children[j] {
1011                    Some(ch) => ch.tree_predicate_map(child_cont.path().push_tail(j as usize), f),
1012                    None => true,
1013                }
1014            by { child_subtree.map_unroll_once(child_cont.path(), f, j); };
1015        };
1016
1017        // Pre-prove map_children for modified_cont (f)
1018        assert(modified_cont.map_children(f)) by {
1019            assert forall |j: int|
1020                0 <= j < modified_cont.children.len() && #[trigger] modified_cont.children[j] is Some implies
1021                modified_cont.children[j].unwrap().tree_predicate_map(modified_cont.path().push_tail(j as usize), f) by {
1022                assert(j != old_cont.idx as int);
1023                assert(modified_cont.children[j] == old_cont.children[j]);
1024            };
1025        };
1026
1027        assert(new_owner.metaregion_sound(regions)) by {
1028            assert forall |i: int| #![auto]
1029                new_owner.level - 1 <= i < NR_LEVELS implies {
1030                    &&& f(new_owner.continuations[i].entry_own, new_owner.continuations[i].path())
1031                    &&& new_owner.continuations[i].map_children(f)
1032                } by {
1033                if i == self.level - 2 {
1034                    assert(new_owner.continuations[i] == child_cont);
1035                } else if i == self.level - 1 {
1036                    assert(new_owner.continuations[i] == modified_cont);
1037                    assert(modified_cont.entry_own == old_cont.entry_own);
1038                    assert(modified_cont.path() == old_cont.path());
1039                } else {
1040                    assert(new_owner.continuations[i] == self.continuations[i]);
1041                }
1042            };
1043        };
1044    }
1045
1046    #[verifier::returns(proof)]
1047    pub proof fn push_level_owner(tracked &mut self, tracked guard_perm: Tracked<GuardPerm<'rcu, C>>)
1048        requires
1049            old(self).inv(),
1050            old(self).level > 1,
1051        ensures
1052            *final(self) == old(self).push_level_owner_spec(guard_perm@),
1053    {
1054        assert(self.va.index.contains_key(self.level - 2));
1055
1056        let ghost self0 = *self;
1057        let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
1058        let ghost cont0 = cont;
1059        let tracked child = cont.make_cont(self.va.index[self.level - 2] as usize, guard_perm);
1060
1061        assert((child, cont) == cont0.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm@));
1062
1063        self.continuations.tracked_insert(self.level - 1, cont);
1064        self.continuations.tracked_insert(self.level - 2, child);
1065
1066        assert(self.continuations == self0.continuations.insert(self.level - 1, cont).insert(self.level - 2, child));
1067
1068        self.popped_too_high = false;
1069
1070        self.level = (self.level - 1) as u8;
1071    }
1072
1073    pub open spec fn pop_level_owner_spec(self) -> (Self, GuardPerm<'rcu, C>)
1074    {
1075        let child = self.continuations[self.level - 1];
1076        let cont = self.continuations[self.level as int];
1077        let (new_cont, guard_perm) = cont.restore_spec(child);
1078        let new_continuations = self.continuations.insert(self.level as int, new_cont);
1079        let new_continuations = new_continuations.remove(self.level - 1);
1080        let new_level = (self.level + 1) as u8;
1081        let popped_too_high = if new_level >= self.guard_level { true } else { false };
1082        (Self {
1083            continuations: new_continuations,
1084            level: new_level,
1085            popped_too_high: popped_too_high,
1086            ..self
1087        }, guard_perm)
1088    }
1089
1090    pub proof fn pop_level_owner_preserves_inv(self)
1091        requires
1092            self.inv(),
1093            self.level < NR_LEVELS,
1094            self.in_locked_range(),
1095        ensures
1096            self.pop_level_owner_spec().0.inv(),
1097    {
1098        let child = self.continuations[self.level - 1];
1099        assert(child.inv());
1100        assert(child.all_some());
1101        let cont = self.continuations[self.level as int];
1102        assert(cont.inv());
1103        let (new_cont, _) = cont.restore_spec(child);
1104        let new_owner = self.pop_level_owner_spec().0;
1105
1106        let child_node = OwnerSubtree {
1107            value: child.entry_own,
1108            level: child.tree_level,
1109            children: child.children,
1110        };
1111
1112        let nc = self.continuations.insert(self.level as int, new_cont).remove(self.level - 1);
1113        assert(new_owner.continuations == nc);
1114        if self.level < 3 {
1115            assert(nc[3] == self.continuations[3]);
1116        }
1117        if self.level < 2 {
1118            assert(nc[2] == self.continuations[2]);
1119        }
1120        assert(new_cont.all_some()) by {
1121            assert forall |i: int| 0 <= i < NR_ENTRIES implies new_cont.children[i] is Some by {
1122                if i == cont.idx as int {
1123                    assert(new_cont.children[i] == Some(child_node));
1124                } else {
1125                    assert(new_cont.children[i] == cont.children[i]);
1126                }
1127            };
1128        };
1129
1130        assert forall |i: int| new_owner.level <= i < NR_LEVELS implies
1131            (#[trigger] new_owner.continuations[i]).all_but_index_some() by {
1132            if i == self.level as int {
1133                assert(new_owner.continuations[i] == new_cont);
1134                assert(new_cont.all_some());
1135            } else {
1136                assert(new_owner.continuations[i] == self.continuations[i]);
1137            }
1138        };
1139
1140        assert(child.path() == cont.path().push_tail(cont.idx as usize));
1141        assert(child.entry_own.path == new_cont.path().push_tail(cont.idx as usize));
1142        assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1143                new_cont.entry_own, cont.idx as int, Some(child.entry_own)));
1144
1145        assert(child_node.inv_children()) by {
1146            assert forall |j: int| 0 <= j < NR_ENTRIES implies
1147                match #[trigger] child_node.children[j] {
1148                    Some(ch) => {
1149                        &&& ch.level == child_node.level + 1
1150                        &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_node.value, j, Some(ch.value))
1151                    },
1152                    None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_node.value, j, None),
1153                }
1154            by {
1155                assert(child.children[j] is Some);
1156                let ch = child.children[j].unwrap();
1157                assert(ch.level == child.tree_level + 1);
1158                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1159                    child.entry_own, j, Some(ch.value)));
1160            };
1161        };
1162        assert forall |j: int| 0 <= j < NR_ENTRIES implies
1163            match #[trigger] child_node.children[j] {
1164                Some(ch) => ch.inv(),
1165                None => true,
1166            }
1167        by {
1168            child.inv_children_unroll(j);
1169        };
1170        assert(child_node.inv()) by {
1171            assert(child_node.inv_node());
1172        };
1173
1174        assert(new_cont.inv_children()) by {
1175            assert forall |i: int| 0 <= i < new_cont.children.len() && #[trigger] new_cont.children[i] is Some
1176                implies new_cont.children[i].unwrap().inv() by {
1177                if i == cont.idx as int {
1178                    assert(new_cont.children[i].unwrap() == child_node);
1179                } else {
1180                    assert(new_cont.children[i] == cont.children[i]);
1181                    cont.inv_children_unroll(i);
1182                }
1183            };
1184        };
1185
1186        assert(new_cont.inv_children_rel()) by {
1187            assert forall |i: int| 0 <= i < NR_ENTRIES && #[trigger] new_cont.children[i] is Some
1188                implies {
1189                    &&& new_cont.children[i].unwrap().value.parent_level == new_cont.level()
1190                    &&& new_cont.children[i].unwrap().level == new_cont.tree_level + 1
1191                    &&& !new_cont.children[i].unwrap().value.in_scope
1192                    &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1193                        new_cont.entry_own, i, Some(new_cont.children[i].unwrap().value))
1194                    &&& new_cont.children[i].unwrap().value.path == new_cont.path().push_tail(i as usize)
1195                } by {
1196                if i == cont.idx as int {
1197                    assert(new_cont.children[i].unwrap() == child_node);
1198                    assert(!child.entry_own.in_scope);
1199                } else {
1200                    assert(new_cont.children[i] == cont.children[i]);
1201                    cont.inv_children_rel_unroll(i);
1202                }
1203            };
1204        };
1205
1206        assert(new_cont.inv()) by {
1207            assert(new_cont.tree_level == INC_LEVELS - new_cont.level() - 1);
1208            assert(new_cont.path().len() == new_cont.tree_level);
1209        };
1210
1211        assert(new_owner.level <= 4 ==> {
1212            &&& new_owner.continuations.contains_key(3)
1213            &&& new_owner.continuations[3].inv()
1214            &&& new_owner.continuations[3].level() == 4
1215            &&& new_owner.continuations[3].entry_own.parent_level == 5
1216            &&& new_owner.va.index[3] == new_owner.continuations[3].idx
1217        }) by {
1218            if self.level as int == 3 {
1219                assert(new_owner.continuations[3] == new_cont);
1220            } else {
1221                assert(new_owner.continuations[3] == self.continuations[3]);
1222            }
1223        };
1224
1225        // Level 3 condition
1226        assert(new_owner.level <= 3 ==> {
1227            &&& new_owner.continuations.contains_key(2)
1228            &&& new_owner.continuations[2].inv()
1229            &&& new_owner.continuations[2].level() == 3
1230            &&& new_owner.continuations[2].entry_own.parent_level == 4
1231            &&& new_owner.va.index[2] == new_owner.continuations[2].idx
1232            &&& new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr() !=
1233                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
1234            &&& new_owner.continuations[2].path() == new_owner.continuations[3].path().push_tail(new_owner.continuations[3].idx as usize)
1235            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1236                    new_owner.continuations[3].entry_own, new_owner.continuations[3].idx as int,
1237                    Some(new_owner.continuations[2].entry_own))
1238        }) by {
1239            if new_owner.level <= 3 {
1240                if self.level as int == 2 {
1241                    assert(new_owner.continuations[2] == new_cont);
1242                } else {
1243                    assert(new_owner.continuations[2] == self.continuations[2]);
1244                }
1245            }
1246        };
1247
1248        // Level 2 condition
1249        assert(new_owner.level <= 2 ==> {
1250            &&& new_owner.continuations.contains_key(1)
1251            &&& new_owner.continuations[1].inv()
1252            &&& new_owner.continuations[1].level() == 2
1253            &&& new_owner.continuations[1].entry_own.parent_level == 3
1254            &&& new_owner.va.index[1] == new_owner.continuations[1].idx
1255            &&& new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
1256                new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
1257            &&& new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
1258                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
1259            &&& new_owner.continuations[1].path() == new_owner.continuations[2].path().push_tail(new_owner.continuations[2].idx as usize)
1260            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1261                    new_owner.continuations[2].entry_own, new_owner.continuations[2].idx as int,
1262                    Some(new_owner.continuations[1].entry_own))
1263        }) by {
1264            if new_owner.level <= 2 {
1265                assert(new_owner.continuations[1] == new_cont);
1266            }
1267        };
1268    }
1269
1270    pub proof fn pop_level_owner_preserves_invs(self, guards: Guards<'rcu, C>, regions: MetaRegionOwners)
1271        requires
1272            self.inv(),
1273            self.level < NR_LEVELS,
1274            self.in_locked_range(),
1275            self.children_not_locked(guards),
1276            self.nodes_locked(guards),
1277            self.metaregion_sound(regions),
1278        ensures
1279            self.pop_level_owner_spec().0.inv(),
1280            self.pop_level_owner_spec().0.only_current_locked(guards),
1281            self.pop_level_owner_spec().0.nodes_locked(guards),
1282            self.pop_level_owner_spec().0.metaregion_sound(regions),
1283    {
1284        let new_owner = self.pop_level_owner_spec().0;
1285        let child = self.continuations[self.level - 1];
1286        let cont = self.continuations[self.level as int];
1287        let (new_cont, _guard_perm) = cont.restore_spec(child);
1288        let child_node = OwnerSubtree {
1289            value: child.entry_own,
1290            level: child.tree_level,
1291            children: child.children,
1292        };
1293
1294        self.pop_level_owner_preserves_inv();
1295
1296        assert(new_owner.va == self.va);
1297
1298        assert(new_owner.nodes_locked(guards)) by {
1299            assert forall |i: int|
1300                #![trigger new_owner.continuations[i]]
1301                new_owner.level - 1 <= i < NR_LEVELS implies
1302                new_owner.continuations[i].node_locked(guards) by {
1303                    if i == self.level as int {
1304                        assert(new_owner.continuations[i] == new_cont);
1305                        assert(new_cont.guard_perm == cont.guard_perm);
1306                    } else {
1307                        assert(new_owner.continuations[i] == self.continuations[i]);
1308                    }
1309                };
1310        };
1311
1312        let child_addr = child.entry_own.node.unwrap().meta_perm.addr();
1313        let child_subtree = child.as_subtree();
1314
1315        assert forall |j: int| 0 <= j < NR_ENTRIES implies
1316            match #[trigger] child_subtree.children[j] {
1317                Some(ch) => ch.inv(),
1318                None => true,
1319            }
1320        by { child.inv_children_unroll(j); };
1321        assert(child_subtree.inv());
1322
1323        assert(OwnerSubtree::<C>::implies(
1324            CursorOwner::<'rcu, C>::node_unlocked(guards),
1325            CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
1326        ));
1327        self.map_children_implies(
1328            CursorOwner::<'rcu, C>::node_unlocked(guards),
1329            CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
1330        );
1331
1332        assert(new_owner.only_current_locked(guards)) by {
1333            assert forall |i: int|
1334                #![trigger new_owner.continuations[i]]
1335                new_owner.level - 1 <= i < NR_LEVELS implies
1336                new_owner.continuations[i].map_children(
1337                    CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr)) by {
1338                if i > self.level as int {
1339                    assert(new_owner.continuations[i] == self.continuations[i]);
1340                } else {
1341                    assert(new_owner.continuations[i] == new_cont);
1342                    new_cont.map_children_lift_skip_idx(
1343                        cont,
1344                        cont.idx as int,
1345                        CursorOwner::<'rcu, C>::node_unlocked(guards),
1346                        CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
1347                    );
1348                }
1349            };
1350        };
1351
1352        let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
1353        self.cont_entries_metaregion(regions);
1354
1355        assert(new_owner.metaregion_sound(regions)) by {
1356            assert forall |i: int| #![auto]
1357                new_owner.level - 1 <= i < NR_LEVELS implies
1358                    new_owner.continuations[i].map_children(f)
1359            by {
1360                if i > self.level as int {
1361                } else {
1362                    new_cont.map_children_lift_skip_idx(cont, cont.idx as int, f, f);
1363                }
1364            };
1365        };
1366    }
1367
1368    /// Update va to a new value that shares the same indices at levels >= self.level.
1369    /// This preserves invariants because:
1370    /// 1. The new va satisfies va.inv()
1371    /// 2. The indices at levels >= level match the continuation indices
1372    /// 3. in_locked_range/above_locked_range depend on va but the preconditions ensure consistency
1373    pub proof fn set_va_preserves_inv(self, new_va: AbstractVaddr)
1374        requires
1375            self.inv(),
1376            !self.popped_too_high,
1377            self.level < self.guard_level,
1378            new_va.inv(),
1379            new_va.offset == 0,
1380            new_va.leading_bits == self.prefix.leading_bits,
1381            forall |i: int| #![auto] self.level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.va.index[i],
1382            forall |i: int| #![auto] self.guard_level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.prefix.index[i],
1383        ensures
1384            self.set_va_spec(new_va).inv(),
1385    {
1386        let r = self.set_va_spec(new_va);
1387
1388        assert(r.in_locked_range()) by {
1389            let gl = self.guard_level;
1390            if gl >= 1 && gl <= NR_LEVELS {
1391                r.va.align_down_to_vaddr_eq_if_upper_indices_eq(r.prefix, gl as int);
1392                r.va.align_down_concrete(gl as int);
1393                r.prefix.align_down_concrete(gl as int);
1394                r.prefix.align_diff(gl as int);
1395                r.prefix.align_up_concrete(gl as int);
1396                AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1397                    nat_align_down(r.va.to_vaddr() as nat, page_size(gl as PagingLevel) as nat) as Vaddr);
1398                AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1399                    nat_align_down(r.prefix.to_vaddr() as nat, page_size(gl as PagingLevel) as nat) as Vaddr);
1400                AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1401                    nat_align_up(r.prefix.to_vaddr() as nat, page_size(gl as PagingLevel) as nat) as Vaddr);
1402                lemma_page_size_ge_page_size(gl as PagingLevel);
1403                lemma_nat_align_down_sound(r.va.to_vaddr() as nat, page_size(gl as PagingLevel) as nat);
1404                r.prefix.align_down_shape(gl as int);
1405                r.prefix.align_down(gl as int).reflect_prop(
1406                    nat_align_down(r.prefix.to_vaddr() as nat, page_size(gl as PagingLevel) as nat) as Vaddr);
1407                r.prefix.align_up(gl as int).reflect_prop(
1408                    nat_align_up(r.prefix.to_vaddr() as nat, page_size(gl as PagingLevel) as nat) as Vaddr);
1409            }
1410        };
1411
1412        assert(r.continuations[r.level - 1].all_some());
1413        assert(r.level <= 4 ==> {
1414            &&& r.continuations.contains_key(3)
1415            &&& r.continuations[3].inv()
1416            &&& r.continuations[3].level() == 4
1417            &&& r.continuations[3].entry_own.parent_level == 5
1418            &&& r.va.index[3] == r.continuations[3].idx
1419        });
1420
1421        assert(r.level <= 3 ==> {
1422            &&& r.continuations.contains_key(2)
1423            &&& r.continuations[2].inv()
1424            &&& r.continuations[2].level() == 3
1425            &&& r.continuations[2].entry_own.parent_level == 4
1426            &&& r.va.index[2] == r.continuations[2].idx
1427            &&& r.continuations[2].guard_perm.value().inner.inner@.ptr.addr() !=
1428                r.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
1429            &&& r.continuations[2].path() == r.continuations[3].path().push_tail(r.continuations[3].idx as usize)
1430        });
1431
1432        assert(r.level <= 2 ==> {
1433            &&& r.continuations.contains_key(1)
1434            &&& r.continuations[1].inv()
1435            &&& r.continuations[1].level() == 2
1436            &&& r.continuations[1].entry_own.parent_level == 3
1437            &&& r.va.index[1] == r.continuations[1].idx
1438            &&& r.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
1439                r.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
1440            &&& r.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
1441                r.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
1442            &&& r.continuations[1].path() == r.continuations[2].path().push_tail(r.continuations[2].idx as usize)
1443        });
1444
1445        assert(r.level == 1 ==> {
1446            &&& r.continuations.contains_key(0)
1447            &&& r.continuations[0].inv()
1448            &&& r.continuations[0].level() == 1
1449            &&& r.continuations[0].entry_own.parent_level == 2
1450            &&& r.va.index[0] == r.continuations[0].idx
1451            &&& r.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
1452                r.continuations[1].guard_perm.value().inner.inner@.ptr.addr()
1453            &&& r.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
1454                r.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
1455            &&& r.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
1456                r.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
1457            &&& r.continuations[0].path() == r.continuations[1].path().push_tail(r.continuations[1].idx as usize)
1458        });
1459    }
1460
1461    #[verifier::returns(proof)]
1462    pub proof fn pop_level_owner(tracked &mut self) -> (tracked guard_perm: GuardPerm<'rcu, C>)
1463        requires
1464            old(self).inv(),
1465            old(self).level < NR_LEVELS,
1466        ensures
1467            *final(self) == old(self).pop_level_owner_spec().0,
1468            guard_perm == old(self).pop_level_owner_spec().1,
1469    {
1470        let ghost self0 = *self;
1471        let tracked mut parent = self.continuations.tracked_remove(self.level as int);
1472        let tracked child = self.continuations.tracked_remove(self.level - 1);
1473
1474        let tracked guard_perm = parent.restore(child);
1475
1476        self.continuations.tracked_insert(self.level as int, parent);
1477
1478        assert(self.continuations == self0.continuations.insert(self.level as int, parent).remove(self.level - 1));
1479
1480        self.level = (self.level + 1) as u8;
1481
1482        if self.level >= self.guard_level {
1483            self.popped_too_high = true;
1484        }
1485
1486        guard_perm
1487    }
1488
1489    pub open spec fn move_forward_owner_spec(self) -> Self
1490        recommends
1491            self.inv(),
1492            self.level < NR_LEVELS,
1493            self.in_locked_range(),
1494        decreases NR_LEVELS - self.level when self.level <= NR_LEVELS
1495    {
1496        if self.index() + 1 < NR_ENTRIES {
1497            // Standard advance. At the very last in-range top-level slot, this
1498            // produces a "one-past-end" cursor with idx == TOP_LEVEL_INDEX_RANGE.end,
1499            // which the cursor inv allows (relaxed `<= top_end`). Such a cursor is
1500            // `above_locked_range`.
1501            self.inc_index().zero_below_level()
1502        } else if self.level < NR_LEVELS {
1503            self.pop_level_owner_spec().0.move_forward_owner_spec()
1504        } else {
1505            // Should never happen
1506            Self {
1507                popped_too_high: false,
1508                ..self
1509            }
1510        }
1511    }
1512
1513    pub proof fn move_forward_increases_va(self)
1514        requires
1515            self.inv(),
1516            self.level <= NR_LEVELS,
1517            self.in_locked_range(),
1518            !self.popped_too_high,
1519        ensures
1520            self.move_forward_owner_spec().va.to_vaddr() > self.va.to_vaddr(),
1521        decreases NR_LEVELS - self.level
1522    {
1523        self.in_locked_range_level_lt_guard_level();
1524        assert(self.level < NR_LEVELS);
1525        if self.index() + 1 < NR_ENTRIES {
1526            self.inc_and_zero_increases_va();
1527        } else if self.level + 1 < self.guard_level {
1528            self.pop_level_owner_preserves_inv();
1529            self.pop_level_owner_spec().0.move_forward_increases_va();
1530        } else {
1531            assert(self.guard_level == self.level + 1);
1532            assert(self.va.index[self.level as int] == 0);
1533            self.pop_level_owner_preserves_inv();
1534            let popped = self.pop_level_owner_spec().0;
1535            assert(self.move_forward_owner_spec() == popped.move_forward_owner_spec());
1536            assert(popped.move_forward_owner_spec() == popped.inc_index().zero_below_level());
1537            popped.inc_and_zero_increases_va();
1538        }
1539    }
1540
1541    pub proof fn move_forward_not_popped_too_high(self)
1542        requires
1543            self.inv(),
1544            self.level <= NR_LEVELS,
1545            self.in_locked_range(),
1546        ensures
1547            !self.move_forward_owner_spec().popped_too_high,
1548       decreases NR_LEVELS - self.level,
1549    {
1550        if self.index() + 1 < NR_ENTRIES {
1551            self.inc_index().zero_preserves_all_but_va();
1552        } else if self.level < NR_LEVELS {
1553            self.pop_level_owner_preserves_inv();
1554            self.pop_level_owner_spec().0.move_forward_not_popped_too_high();
1555        }
1556    }
1557
1558    pub proof fn move_forward_owner_decreases_steps(self)
1559        requires
1560            self.inv(),
1561            self.level <= NR_LEVELS,
1562            self.in_locked_range(),
1563            !self.popped_too_high,
1564        ensures
1565            self.move_forward_owner_spec().max_steps() < self.max_steps()
1566        decreases NR_LEVELS - self.level,
1567    {
1568        if self.index() + 1 < NR_ENTRIES {
1569            let inc = self.inc_index();
1570            inc.zero_preserves_all_but_va();
1571            Self::max_steps_subtree_positive(self.level as usize);
1572            if self.level < NR_LEVELS {
1573                inc.zero_below_level().max_steps_partial_eq(self, (self.level + 1) as usize);
1574            }
1575            vstd::arithmetic::mul::lemma_mul_is_distributive_add(
1576                Self::max_steps_subtree(self.level as usize) as int,
1577                (NR_ENTRIES - self.index() - 1) as int, 1);
1578            if self.level as usize == NR_LEVELS {
1579                self.in_locked_range_level_lt_nr_levels();
1580            }
1581        } else if self.level < NR_LEVELS {
1582            self.in_locked_range_level_lt_guard_level();
1583            self.pop_level_owner_preserves_inv();
1584            let popped = self.pop_level_owner_spec().0;
1585            popped.max_steps_partial_eq(self, (self.level + 1) as usize);
1586            Self::max_steps_subtree_positive(self.level as usize);
1587            Self::max_steps_subtree_positive((self.level + 1) as usize);
1588            if !popped.popped_too_high {
1589                popped.move_forward_owner_decreases_steps();
1590            } else {
1591                // popped.popped_too_high means popped.level >= popped.guard_level.
1592                // pop_level_owner_spec sets popped_too_high iff new_level >= guard_level,
1593                // and new_level == self.level + 1, so self.level + 1 == self.guard_level.
1594                assert(popped.level == self.level + 1);
1595                assert(popped.level == self.guard_level);
1596                assert(popped.guard_level == self.guard_level);
1597                // From cursor inv: !self.popped_too_high && self.level < self.guard_level
1598                // ==> self.va.index[self.guard_level - 1] == 0. So popped.va.index[L] == 0,
1599                // which means popped.continuations[L].idx == 0 (cursor inv tying va.index to cont.idx).
1600                assert(self.va.index[self.guard_level - 1] == 0);
1601                assert(popped.va == self.va);
1602                assert(popped.continuations[popped.level - 1].idx == 0);
1603                assert(popped.index() == 0);
1604                // popped.move_forward_owner_spec() unfolds to inc_index().zero_below_level()
1605                // because popped.index() + 1 == 1 < NR_ENTRIES.
1606                let inc = popped.inc_index();
1607                let q = inc.zero_below_level();
1608                assert(popped.move_forward_owner_spec() == q);
1609                inc.zero_preserves_all_but_va();
1610                // q has continuations[i] == popped.continuations[i] for all i (inc only changes
1611                // cont[popped.level - 1] = cont[L], zero_below_level doesn't touch cont).
1612                // max_steps_partial at L+2 (which only sees cont[L+1..]) is unaffected.
1613                let lp1 = (self.level + 1) as usize;
1614                let lp2 = (self.level + 2) as usize;
1615                // self.cont[L].idx == 0 (mirrors popped.cont[L].idx via va.index[L] == 0)
1616                assert(self.va.index[self.level as int] == 0);
1617                assert(self.continuations[self.level as int].idx == 0);
1618                // Establish that self.max_steps_partial(lp1) and q.max_steps_partial(lp1)
1619                // share the same tail at lp2.
1620                if (self.level + 1) < NR_LEVELS {
1621                    q.max_steps_partial_eq(self, lp2);
1622                }
1623                // Compute self.max_steps_partial(L) explicitly.
1624                // self.cont[L-1].idx == NR_ENTRIES - 1 (we are in the !idx+1<NR_ENTRIES branch).
1625                assert(self.continuations[self.level - 1].idx + 1 == NR_ENTRIES);
1626                // q.cont[L].idx == 1 (popped.cont[L].idx == 0, then inc).
1627                assert(q.continuations[self.level as int].idx == 1);
1628                // Arithmetic: max_steps_subtree(L+1) * (NR_ENTRIES - 1) + 1 * max_steps_subtree(L+1)
1629                //           == max_steps_subtree(L+1) * NR_ENTRIES.
1630                let st_l = Self::max_steps_subtree(self.level as usize) as int;
1631                let st_lp1 = Self::max_steps_subtree(lp1) as int;
1632                vstd::arithmetic::mul::lemma_mul_is_distributive_add(
1633                    st_lp1, (NR_ENTRIES - 1) as int, 1);
1634                vstd::arithmetic::mul::lemma_mul_is_distributive_add(
1635                    st_l, (NR_ENTRIES - 1) as int, 1);
1636            }
1637        } else {
1638            self.in_locked_range_level_lt_nr_levels();
1639        }
1640    }
1641
1642    /// Trivial: zero_below_level is defined as Self { va: self.va.align_down(level), ..self }.
1643    pub proof fn zero_below_level_eq_align_down(self)
1644        requires
1645            self.va.inv(),
1646            self.va.offset == 0,
1647            1 <= self.level <= NR_LEVELS,
1648        ensures
1649            self.zero_below_level().va == self.va.align_down(self.level as int),
1650        decreases self.level,
1651    {}
1652
1653    pub proof fn move_forward_va_is_align_up(self)
1654        requires
1655            self.inv(),
1656            self.level <= NR_LEVELS,
1657            self.in_locked_range(),
1658            !self.popped_too_high,
1659        ensures
1660            self.move_forward_owner_spec().va == self.va.align_up(self.level as int),
1661        decreases NR_LEVELS - self.level
1662    {
1663        if self.index() + 1 < NR_ENTRIES {
1664            let inc = self.inc_index();
1665            inc.zero_preserves_all_but_va();
1666            inc.zero_below_level_va();
1667            self.va.align_up_concrete(self.level as int);
1668            assert(inc.va.inv()) by {
1669                assert forall |i: int| 0 <= i < NR_LEVELS implies
1670                    inc.va.index.contains_key(i) && 0 <= #[trigger] inc.va.index[i] && inc.va.index[i] < NR_ENTRIES
1671                by { if i != self.level - 1 { assert(inc.va.index[i] == self.va.index[i]); } };
1672            };
1673            inc.va.align_down_concrete(self.level as int);
1674            let ps = page_size(self.level as PagingLevel) as nat;
1675            let self_va = self.va.to_vaddr() as nat;
1676            self.va.align_diff(self.level as int);
1677            lemma_page_size_ge_page_size(self.level as PagingLevel);
1678            assert(self.va.index[self.level - 1] == self.continuations[self.level - 1].idx);
1679            self.va.index_increment_adds_page_size(self.level as int);
1680            assert(self_va + ps == ps * 1 + self_va) by (nonlinear_arith);
1681            vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(1int, self_va as int, ps as int);
1682            vstd::arithmetic::div_mod::lemma_fundamental_div_mod(self_va as int, ps as int);
1683            vstd::arithmetic::div_mod::lemma_mod_bound(self_va as int, ps as int);
1684            vstd::arithmetic::div_mod::lemma_div_pos_is_pos(self_va as int, ps as int);
1685        } else if self.level < NR_LEVELS {
1686            self.in_locked_range_level_lt_guard_level();
1687            self.pop_level_owner_preserves_inv();
1688            let popped = self.pop_level_owner_spec().0;
1689            if !popped.popped_too_high {
1690                popped.move_forward_va_is_align_up();
1691            } else {
1692                let inc_p = popped.inc_index();
1693                inc_p.zero_preserves_all_but_va();
1694                inc_p.zero_below_level_va();
1695                popped.va.align_up_concrete(popped.level as int);
1696                assert(inc_p.va.inv()) by {
1697                    assert forall |i: int| 0 <= i < NR_LEVELS implies
1698                        inc_p.va.index.contains_key(i) && 0 <= #[trigger] inc_p.va.index[i] && inc_p.va.index[i] < NR_ENTRIES
1699                    by { if i != popped.level - 1 { assert(inc_p.va.index[i] == popped.va.index[i]); } };
1700                };
1701                inc_p.va.align_down_concrete(popped.level as int);
1702                let ps_p = page_size(popped.level as PagingLevel) as nat;
1703                let popped_va = popped.va.to_vaddr() as nat;
1704                let inc_p_va = inc_p.va.to_vaddr() as nat;
1705                popped.va.align_diff(popped.level as int);
1706                lemma_page_size_ge_page_size(popped.level as PagingLevel);
1707                assert(popped.va.index[popped.level as int - 1] == popped.continuations[popped.level as int - 1].idx);
1708                popped.va.index_increment_adds_page_size(popped.level as int);
1709                assert(popped_va + ps_p == ps_p * 1 + popped_va) by (nonlinear_arith);
1710                vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(1int, popped_va as int, ps_p as int);
1711                vstd::arithmetic::div_mod::lemma_fundamental_div_mod(popped_va as int, ps_p as int);
1712                vstd::arithmetic::div_mod::lemma_mod_bound(popped_va as int, ps_p as int);
1713                vstd::arithmetic::div_mod::lemma_div_pos_is_pos(popped_va as int, ps_p as int);
1714                assert(nat_align_down(inc_p_va, ps_p) == nat_align_up(popped_va, ps_p));
1715                assert(inc_p.va.align_down(popped.level as int) == popped.va.align_up(popped.level as int));
1716                // popped.idx + 1 < NR_ENTRIES — derive from popped_too_high state and inv.
1717                // (The popped state has level == guard_level, and idx == va.index[level-1] == 0
1718                //  because of cursor inv line 526, so idx + 1 == 1 < NR_ENTRIES.)
1719                assert(popped.index() + 1 < NR_ENTRIES);
1720                assert(popped.move_forward_owner_spec().va == inc_p.zero_below_level().va);
1721            }
1722            assert(self.va.index[self.level as int - 1] == self.continuations[self.level as int - 1].idx);
1723            self.va.align_up_carry(self.level as int);
1724        } else {
1725        }
1726    }
1727
1728    /// After popping a level, the total view_mappings is preserved.
1729    /// The restored parent at index self.level absorbs the child's mappings,
1730    /// and both are within the view_mappings range [self.level, NR_LEVELS).
1731    pub proof fn pop_level_owner_preserves_mappings(self)
1732        requires
1733            self.inv(),
1734            self.level < NR_LEVELS,
1735            self.in_locked_range(),
1736        ensures
1737            self.pop_level_owner_spec().0@.mappings == self@.mappings,
1738    {
1739        let child = self.continuations[self.level - 1];
1740        let parent = self.continuations[self.level as int];
1741        let (restored_parent, _) = parent.restore_spec(child);
1742        let popped = self.pop_level_owner_spec().0;
1743        let child_subtree = child.as_subtree();
1744
1745        assert(child.inv());
1746        assert(child.all_some());
1747        assert(parent.inv());
1748        assert(parent.all_but_index_some());
1749        assert(child.path() == parent.path().push_tail(parent.idx as usize));
1750
1751        assert(child_subtree.inv()) by {
1752            assert(child_subtree.inv_node());
1753            assert forall |i: int| 0 <= i < NR_ENTRIES implies
1754                match #[trigger] child_subtree.children[i] {
1755                    Some(ch) => {
1756                        &&& ch.level == child_subtree.level + 1
1757                        &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, i, Some(ch.value))
1758                    },
1759                    None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, i, None),
1760                }
1761            by {
1762                let ch = child.children[i].unwrap();
1763                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
1764                    child.entry_own, i, Some(ch.value)));
1765            };
1766            assert(child_subtree.inv_children());
1767
1768            assert forall |i: int| 0 <= i < NR_ENTRIES implies
1769                match #[trigger] child_subtree.children[i] {
1770                    Some(ch) => ch.inv(),
1771                    None => true,
1772                }
1773            by {
1774                child.inv_children_unroll(i);
1775            };
1776        };
1777
1778        parent.as_subtree_restore(child);
1779
1780        let r = restored_parent;
1781        let p = parent.put_child_spec(child_subtree);
1782        assert forall |j: int| 0 <= j < r.children.len()
1783            implies r.children[j] == p.children[j] by {
1784            if j == parent.idx as int {
1785                assert(r.children[j] == Some(child_subtree));
1786            } else {
1787                assert(r.children[j] == parent.children[j]);
1788            }
1789        };
1790        assert(r.children =~= p.children);
1791        assert(restored_parent.view_mappings() =~=
1792            parent.put_child_spec(child_subtree).view_mappings()) by {
1793            assert(r.path() == p.path());
1794            assert forall |m: Mapping| r.view_mappings().contains(m)
1795                implies p.view_mappings().contains(m) by {
1796                let j = choose |j: int| #![auto]
1797                    0 <= j < r.children.len()
1798                    && r.children[j] is Some
1799                    && PageTableOwner(r.children[j].unwrap()).view_rec(
1800                        r.path().push_tail(j as usize)).contains(m);
1801                assert(p.children[j] is Some);
1802                assert(PageTableOwner(p.children[j].unwrap()).view_rec(
1803                    p.path().push_tail(j as usize)).contains(m));
1804            };
1805            assert forall |m: Mapping| p.view_mappings().contains(m)
1806                implies r.view_mappings().contains(m) by {
1807                let j = choose |j: int| #![auto]
1808                    0 <= j < p.children.len()
1809                    && p.children[j] is Some
1810                    && PageTableOwner(p.children[j].unwrap()).view_rec(
1811                        p.path().push_tail(j as usize)).contains(m);
1812                assert(r.children[j] is Some);
1813                assert(PageTableOwner(r.children[j].unwrap()).view_rec(
1814                    r.path().push_tail(j as usize)).contains(m));
1815            };
1816        };
1817
1818        parent.view_mappings_put_child(child_subtree);
1819        child.as_page_table_owner_preserves_view_mappings();
1820
1821        assert(popped.level == (self.level + 1) as u8);
1822        assert(popped.continuations[self.level as int] == restored_parent);
1823
1824        assert(popped.view_mappings() =~= self.view_mappings()) by {
1825            assert forall |m: Mapping| self.view_mappings().contains(m)
1826                implies popped.view_mappings().contains(m) by {
1827                let i = choose |i: int|
1828                    self.level - 1 <= i < NR_LEVELS
1829                    && (#[trigger] self.continuations[i]).view_mappings().contains(m);
1830                if i == self.level - 1 {
1831                    assert(child.view_mappings().contains(m));
1832                    assert(restored_parent.view_mappings().contains(m));
1833                    assert(popped.continuations[self.level as int].view_mappings().contains(m));
1834                } else if i == self.level as int {
1835                    assert(parent.view_mappings().contains(m));
1836                    assert(restored_parent.view_mappings().contains(m));
1837                    assert(popped.continuations[self.level as int].view_mappings().contains(m));
1838                } else {
1839                    assert(popped.continuations[i] == self.continuations[i]);
1840                }
1841            };
1842            assert forall |m: Mapping| popped.view_mappings().contains(m)
1843                implies self.view_mappings().contains(m) by {
1844                let i = choose |i: int|
1845                    popped.level - 1 <= i < NR_LEVELS
1846                    && (#[trigger] popped.continuations[i]).view_mappings().contains(m);
1847                if i == self.level as int {
1848                    assert(restored_parent.view_mappings().contains(m));
1849                    if child.view_mappings().contains(m) {
1850                        assert(self.continuations[self.level - 1].view_mappings().contains(m));
1851                    } else {
1852                        assert(parent.view_mappings().contains(m));
1853                        assert(self.continuations[self.level as int].view_mappings().contains(m));
1854                    }
1855                } else {
1856                    assert(self.continuations[i] == popped.continuations[i]);
1857                }
1858            };
1859        };
1860    }
1861
1862    pub proof fn move_forward_owner_preserves_mappings(self)
1863    requires
1864        self.inv(),
1865        self.in_locked_range(),
1866    ensures
1867        self.move_forward_owner_spec()@.mappings == self@.mappings,
1868    decreases NR_LEVELS - self.level,
1869    {
1870        if self.index() + 1 < NR_ENTRIES {
1871            let inc = self.inc_index();
1872            let result = inc.zero_below_level();
1873
1874            inc.zero_preserves_all_but_va();
1875            assert(result.continuations =~= inc.continuations);
1876            assert(result.level == inc.level);
1877
1878            let old_cont = self.continuations[self.level - 1];
1879            let new_cont = old_cont.inc_index();
1880            assert(new_cont.children =~= old_cont.children);
1881            assert(new_cont.entry_own == old_cont.entry_own);
1882            assert(new_cont.path() == old_cont.path());
1883
1884            assert(new_cont.view_mappings() =~= old_cont.view_mappings()) by {
1885                assert forall |m: Mapping| old_cont.view_mappings().contains(m)
1886                    implies new_cont.view_mappings().contains(m) by {
1887                    let i = choose |i: int| #![auto]
1888                        0 <= i < old_cont.children.len()
1889                        && old_cont.children[i] is Some
1890                        && PageTableOwner(old_cont.children[i].unwrap()).view_rec(
1891                            old_cont.path().push_tail(i as usize)).contains(m);
1892                    assert(new_cont.children[i] is Some);
1893                    assert(PageTableOwner(new_cont.children[i].unwrap()).view_rec(
1894                        new_cont.path().push_tail(i as usize)).contains(m));
1895                };
1896                assert forall |m: Mapping| new_cont.view_mappings().contains(m)
1897                    implies old_cont.view_mappings().contains(m) by {
1898                    let i = choose |i: int| #![auto]
1899                        0 <= i < new_cont.children.len()
1900                        && new_cont.children[i] is Some
1901                        && PageTableOwner(new_cont.children[i].unwrap()).view_rec(
1902                            new_cont.path().push_tail(i as usize)).contains(m);
1903                    assert(old_cont.children[i] is Some);
1904                    assert(PageTableOwner(old_cont.children[i].unwrap()).view_rec(
1905                        old_cont.path().push_tail(i as usize)).contains(m));
1906                };
1907            };
1908
1909            assert(result.view_mappings() =~= self.view_mappings()) by {
1910                assert forall |m: Mapping| self.view_mappings().contains(m)
1911                    implies result.view_mappings().contains(m) by {
1912                    let i = choose |i: int|
1913                        self.level - 1 <= i < NR_LEVELS
1914                        && (#[trigger] self.continuations[i]).view_mappings().contains(m);
1915                    if i == self.level - 1 {
1916                        assert(result.continuations[i].view_mappings().contains(m));
1917                    } else {
1918                        assert(result.continuations[i] == self.continuations[i]);
1919                    }
1920                };
1921                assert forall |m: Mapping| result.view_mappings().contains(m)
1922                    implies self.view_mappings().contains(m) by {
1923                    let i = choose |i: int|
1924                        result.level - 1 <= i < NR_LEVELS
1925                        && (#[trigger] result.continuations[i]).view_mappings().contains(m);
1926                    if i == self.level - 1 {
1927                        assert(self.continuations[i].view_mappings().contains(m));
1928                    } else {
1929                        assert(self.continuations[i] == result.continuations[i]);
1930                    }
1931                };
1932            };
1933        } else if self.level < NR_LEVELS {
1934            let popped = self.pop_level_owner_spec().0;
1935
1936            self.pop_level_owner_preserves_inv();
1937            assert(popped.in_locked_range()) by {
1938                assert(popped.va == self.va);
1939                assert(popped.prefix == self.prefix);
1940                assert(popped.guard_level == self.guard_level);
1941            };
1942
1943            self.pop_level_owner_preserves_mappings();
1944            popped.move_forward_owner_preserves_mappings();
1945        }
1946    }
1947
1948    // NOTE: move_forward_owner_preserves_in_locked_range was removed because it is UNSOUND.
1949}
1950
1951}
1952
1953 
1954 
1955