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 core::ops::Range;
20
21verus! {
22
23/// Paths obtained by push_tail with different indices are different
24pub proof fn push_tail_different_indices_different_paths(
25    path: TreePath<NR_ENTRIES>,
26    i: usize,
27    j: usize,
28)
29    requires
30        path.inv(),
31        0 <= i < NR_ENTRIES,
32        0 <= j < NR_ENTRIES,
33        i != j,
34    ensures
35        path.push_tail(i) != path.push_tail(j),
36{
37    path.push_tail_property(i);
38    path.push_tail_property(j);
39    assert(path.push_tail(i).index(path.len() as int) == i as usize);
40    assert(path.push_tail(j).index(path.len() as int) == j as usize);
41    if path.push_tail(i) == path.push_tail(j) {
42        assert(i == j); // Contradiction
43    }
44}
45
46/// Paths with different lengths are different
47pub proof fn different_length_different_paths(
48    path1: TreePath<NR_ENTRIES>,
49    path2: TreePath<NR_ENTRIES>,
50)
51    requires
52        path1.len() != path2.len(),
53    ensures
54        path1 != path2,
55{
56    // Trivial: if path1 == path2, then their lengths are equal
57    if path1 == path2 {
58        assert(path1.len() == path2.len());
59    }
60}
61
62/// A path obtained by push_tail has greater length than the original
63pub proof fn push_tail_increases_length(
64    path: TreePath<NR_ENTRIES>,
65    i: usize,
66)
67    requires
68        path.inv(),
69        0 <= i < NR_ENTRIES,
70    ensures
71        path.push_tail(i).len() > path.len(),
72{
73    path.push_tail_property(i);
74}
75
76impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
77
78    /// The number of steps it will take to walk through every node of a full
79    /// page table at level `level`
80    pub open spec fn max_steps_subtree(level: usize) -> usize
81        decreases level,
82    {
83        if level <= 1 {
84            NR_ENTRIES
85        } else {
86            // One step to push down a level, then the number for that subtree
87            (NR_ENTRIES * (Self::max_steps_subtree((level - 1) as usize) + 1)) as usize
88        }
89    }
90
91    /// The number of steps it will take to walk through the remaining entries of the page table
92    /// starting at the given level.
93    pub open spec fn max_steps_partial(self, level: usize) -> usize
94        decreases NR_LEVELS - level,
95        when level <= NR_LEVELS
96    {
97        if level == NR_LEVELS {
98            0
99        } else {
100            // How many entries remain at this level?
101            let cont = self.continuations[(level - 1) as int];
102            // Each entry takes at most `max_step_subtree` steps.
103            let steps = Self::max_steps_subtree(level) * (NR_ENTRIES - cont.idx);
104            // Then the number of steps for the remaining entries at higher levels
105            let remaining_steps = self.max_steps_partial((level + 1) as usize);
106            (steps + remaining_steps) as usize
107        }
108    }
109
110    pub open spec fn max_steps(self) -> usize {
111        self.max_steps_partial(self.level as usize)
112    }
113
114    pub proof fn max_steps_partial_inv(self, other: Self, level: usize)
115        requires
116            self.inv(),
117            other.inv(),
118            self.level == other.level,
119            self.level <= level <= NR_LEVELS,
120            forall |i: int|
121                #![trigger self.continuations[i].idx]
122                #![trigger other.continuations[i].idx]
123            self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].idx == other.continuations[i].idx,
124        ensures
125            self.max_steps_partial(level) == other.max_steps_partial(level),
126        decreases NR_LEVELS - level,
127    {
128        if level < NR_LEVELS {
129            self.max_steps_partial_inv(other, (level + 1) as usize);
130        }
131    }
132
133    pub open spec fn push_level_owner_spec(self, guard_perm: GuardPerm<'rcu, C>) -> Self
134    {
135        let cont = self.continuations[self.level - 1];
136        let (child, cont) = cont.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm);
137        let new_continuations = self.continuations.insert(self.level - 1, cont);
138        let new_continuations = new_continuations.insert(self.level - 2, child);
139
140        let new_level = (self.level - 1) as u8;
141        Self {
142            continuations: new_continuations,
143            level: new_level,
144            popped_too_high: false,
145            ..self
146        }
147    }
148
149    pub proof fn push_level_owner_decreases_steps(self, guard_perm: GuardPerm<'rcu, C>)
150        requires
151            self.inv(),
152            self.level > 0,
153        ensures
154            self.push_level_owner_spec(guard_perm).max_steps() < self.max_steps()
155    { admit() }
156
157    pub proof fn push_level_owner_preserves_va(self, guard_perm: GuardPerm<'rcu, C>)
158        requires
159            self.inv(),
160            self.level > 1,
161        ensures
162            self.push_level_owner_spec(guard_perm).va == self.va,
163            self.push_level_owner_spec(guard_perm).continuations[self.level - 2].idx == self.va.index[self.level - 2],
164    {
165        assert(self.va.index.contains_key(self.level - 2));
166    }
167
168    pub proof fn push_level_owner_preserves_mappings(self, guard_perm: GuardPerm<'rcu, C>)
169        requires
170            self.inv(),
171            self.level > 1,
172        ensures
173            self.push_level_owner_spec(guard_perm)@.mappings == self@.mappings,
174    { admit() }
175
176    pub proof fn push_level_owner_preserves_inv(self, guard_perm: GuardPerm<'rcu, C>)
177        requires
178            self.inv(),
179            self.level > 1,
180            forall |i: int|
181                #![trigger self.continuations[i]]
182                self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].guard_perm.addr() != guard_perm.addr(),
183        ensures
184            self.push_level_owner_spec(guard_perm).inv(),
185    {
186        admit();
187        let new_owner = self.push_level_owner_spec(guard_perm);
188        let new_level = (self.level - 1) as u8;
189
190        let old_cont = self.continuations[self.level - 1];
191        old_cont.inv_children_unroll(old_cont.idx as int);
192        let child_node = old_cont.children[old_cont.idx as int].unwrap();
193        let (child, modified_cont) = old_cont.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm);
194
195        assert(child.inv()) by { admit() };
196
197        assert(new_owner.level == new_level);
198        assert(new_owner.va == self.va);
199        assert(new_owner.guard_level == self.guard_level);
200        assert(new_owner.prefix == self.prefix);
201        assert(new_owner.popped_too_high == false);
202        assert(new_owner.continuations[self.level - 1] == modified_cont);
203        assert(new_owner.continuations[self.level - 2] == child);
204
205        assert(modified_cont.entry_own == old_cont.entry_own);
206        assert(modified_cont.idx == old_cont.idx);
207        assert(modified_cont.tree_level == old_cont.tree_level);
208        assert(modified_cont.path == old_cont.path);
209        assert(modified_cont.guard_perm == old_cont.guard_perm);
210        assert(modified_cont.children == old_cont.children.update(old_cont.idx as int, None));
211
212        assert(child.entry_own == child_node.value);
213        assert(child.tree_level == old_cont.tree_level + 1);
214        assert(child.idx == self.va.index[self.level - 2] as usize);
215        assert(child.children == child_node.children);
216        assert(child.guard_perm == guard_perm);
217
218        assert(new_owner.va.inv());
219
220        assert(1 <= new_owner.level <= NR_LEVELS);
221
222        assert(new_owner.guard_level <= NR_LEVELS);
223
224        assert(!new_owner.popped_too_high ==> new_owner.level < new_owner.guard_level || new_owner.above_locked_range()) by {
225            if self.popped_too_high {
226                admit();
227            }
228        };
229
230        assert(new_owner.prefix.inv());
231
232        assert(new_owner.continuations[new_owner.level - 1].all_some()) by { admit() };
233
234        assert(modified_cont.all_but_index_some()) by {
235            assert(modified_cont.children[modified_cont.idx as int] is None);
236            assert forall |i: int| 0 <= i < modified_cont.idx implies
237                modified_cont.children[i] is Some by {
238                assert(modified_cont.children[i] == old_cont.children[i]);
239            };
240            assert forall |i: int| modified_cont.idx < i < NR_ENTRIES implies
241                modified_cont.children[i] is Some by {
242                assert(modified_cont.children[i] == old_cont.children[i]);
243            };
244        };
245
246        assert(forall|i: int| new_owner.level <= i < NR_LEVELS ==> {
247            (#[trigger] new_owner.continuations[i]).all_but_index_some()
248        }) by {
249            assert forall |i: int| new_owner.level <= i < NR_LEVELS implies
250                (#[trigger] new_owner.continuations[i]).all_but_index_some() by {
251                if i == self.level - 1 {
252                    assert(new_owner.continuations[i] == modified_cont);
253                } else {
254                    // i >= self.level, unchanged from old state
255                    assert(new_owner.continuations[i] == self.continuations[i]);
256                }
257            };
258        };
259
260        assert(modified_cont.inv()) by {
261            assert(modified_cont.children.len() == NR_ENTRIES);
262            assert(0 <= modified_cont.idx < NR_ENTRIES);
263            assert(modified_cont.inv_children()) by {
264                assert forall |i: int| 0 <= i < modified_cont.children.len() && #[trigger] modified_cont.children[i] is Some
265                    implies modified_cont.children[i].unwrap().inv() by {
266                    assert(i != modified_cont.idx);
267                    assert(modified_cont.children[i] == old_cont.children[i]);
268                    old_cont.inv_children_unroll(i);
269                };
270            };
271            assert(modified_cont.inv_children_rel()) by {
272                assert forall |i: int| 0 <= i < NR_ENTRIES && #[trigger] modified_cont.children[i] is Some
273                    implies {
274                        &&& modified_cont.children[i].unwrap().value.parent_level == modified_cont.level()
275                        &&& modified_cont.children[i].unwrap().level == modified_cont.tree_level + 1
276                        &&& !modified_cont.children[i].unwrap().value.in_scope
277                        &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
278                            modified_cont.entry_own, i, Some(modified_cont.children[i].unwrap().value))
279                        &&& modified_cont.children[i].unwrap().value.path == modified_cont.path().push_tail(i as usize)
280                    } by {
281                    assert(i != modified_cont.idx);
282                    assert(modified_cont.children[i] == old_cont.children[i]);
283                    assert(old_cont.inv_children_rel());
284                };
285            };
286            assert(modified_cont.entry_own.is_node());
287            assert(modified_cont.entry_own.inv());
288            assert(modified_cont.entry_own.node.unwrap().relate_guard_perm(modified_cont.guard_perm));
289            assert(modified_cont.tree_level == INC_LEVELS - modified_cont.level() - 1);
290            assert(modified_cont.tree_level < INC_LEVELS - 1);
291            assert(modified_cont.path().len() == modified_cont.tree_level);
292        };
293
294        assert(new_owner.level <= 4 ==> {
295            &&& new_owner.continuations.contains_key(3)
296            &&& new_owner.continuations[3].inv()
297            &&& new_owner.continuations[3].level() == 4
298            &&& new_owner.continuations[3].entry_own.parent_level == 5
299            &&& new_owner.va.index[3] == new_owner.continuations[3].idx
300        }) by {
301            if new_owner.level <= 4 {
302                if self.level == 4 {
303                    assert(new_owner.continuations[3] == modified_cont);
304                } else {
305                    assert(new_owner.continuations[3] == self.continuations[3]);
306                }
307            }
308        };
309
310        // Level 3 condition: new_level <= 3 ==> continuations[2] ...
311        assert(new_owner.level <= 3 ==> {
312            &&& new_owner.continuations.contains_key(2)
313            &&& new_owner.continuations[2].inv()
314            &&& new_owner.continuations[2].level() == 3
315            &&& new_owner.continuations[2].entry_own.parent_level == 4
316            &&& new_owner.va.index[2] == new_owner.continuations[2].idx
317            &&& new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr() !=
318                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
319        }) by {
320            if new_owner.level <= 3 {
321                if self.level == 4 {
322                    assert(self.va.index.contains_key(2));
323                    // guard_perm distinctness: requires new guard_perm addr != old guard_perm addr
324                    assert(new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr() !=
325                           new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()) by {
326                        assert(new_owner.continuations[2].guard_perm == guard_perm);
327                        assert(new_owner.continuations[3] == modified_cont);
328                        assert(self.continuations[3].guard_perm.addr() != guard_perm.addr());
329                    };
330                }
331            }
332        };
333
334        // Level 2 condition: new_level <= 2 ==> continuations[1] ...
335        assert(new_owner.level <= 2 ==> {
336            &&& new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
337                new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
338            &&& new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
339                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
340        }) by {
341            if new_owner.level <= 2 {
342                if self.level == 3 {
343                    // Trigger va.inv() quantifier for index 1
344                    assert(self.va.index.contains_key(1));
345                    assert(new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
346                           new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr()) by {
347                        admit();
348                    };
349                    assert(new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
350                           new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()) by {
351                        admit();
352                    };
353                }
354            }
355        };
356
357        // Level 1 condition: new_level == 1 ==> continuations[0] exists and is valid
358        assert(new_owner.level == 1 ==> {
359            &&& new_owner.continuations.contains_key(0)
360            &&& new_owner.continuations[0].inv()
361            &&& new_owner.continuations[0].level() == 1
362            &&& new_owner.continuations[0].entry_own.parent_level == 2
363            &&& new_owner.va.index[0] == new_owner.continuations[0].idx
364            &&& new_owner.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
365                new_owner.continuations[1].guard_perm.value().inner.inner@.ptr.addr()
366            &&& new_owner.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
367                new_owner.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
368            &&& new_owner.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
369                new_owner.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
370        }) by { admit() };
371    }
372
373    pub proof fn push_level_owner_preserves_invs(self, guard_perm: GuardPerm<'rcu, C>, regions: MetaRegionOwners, guards: Guards<'rcu, C>)
374        requires
375            self.inv(),
376            self.level > 1,
377            self.only_current_locked(guards),
378            self.nodes_locked(guards),
379            self.relate_region(regions),
380            // The new guard_perm must be locked in guards
381            guards.lock_held(guard_perm.value().inner.inner@.ptr.addr()),
382        ensures
383            self.push_level_owner_spec(guard_perm).inv(),
384            self.push_level_owner_spec(guard_perm).children_not_locked(guards),
385            self.push_level_owner_spec(guard_perm).nodes_locked(guards),
386            self.push_level_owner_spec(guard_perm).relate_region(regions),
387    {
388        reveal(CursorContinuation::inv_children);
389        let new_owner = self.push_level_owner_spec(guard_perm);
390        let new_level = (self.level - 1) as u8;
391
392        let old_cont = self.continuations[self.level - 1];
393
394        old_cont.inv_children_unroll_all();
395
396        let (child_cont, modified_cont) = old_cont.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm);
397        assert(forall |i: int|
398            #![trigger self.continuations[i]]
399            self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].guard_perm.addr() != guard_perm.addr()) by { admit() };
400        self.push_level_owner_preserves_inv(guard_perm);
401
402        let cur_entry = self.cur_entry_owner();
403        let cur_entry_addr = cur_entry.node.unwrap().meta_perm.addr();
404        let cur_entry_path = old_cont.path().push_tail(old_cont.idx as usize);
405
406        assert(cur_entry.relate_region(regions));
407
408        assert(new_owner.children_not_locked(guards)) by {
409            assert forall |i: int|
410                #![trigger new_owner.continuations[i]]
411                new_owner.level - 1 <= i < NR_LEVELS implies
412                new_owner.continuations[i].map_children(CursorOwner::<'rcu, C>::node_unlocked(guards)) by {
413
414                if i == self.level - 2 {
415                    assert(new_owner.continuations[i] == child_cont);
416                    admit();
417                } else if i == self.level - 1 {
418                    assert(new_owner.continuations[i] == modified_cont);
419                    assert(modified_cont.path() == old_cont.path());
420
421                    assert forall |j: int|
422                        #![trigger modified_cont.children[j]]
423                        0 <= j < modified_cont.children.len() && modified_cont.children[j] is Some implies
424                        modified_cont.children[j].unwrap().tree_predicate_map(
425                            modified_cont.path().push_tail(j as usize),
426                            CursorOwner::<'rcu, C>::node_unlocked(guards)) by {
427                        assert(j != old_cont.idx as int);
428                        assert(modified_cont.children[j] == old_cont.children[j]);
429                        let sibling_root_path = old_cont.path().push_tail(j as usize);
430                        assume(old_cont.path().inv());
431
432                        push_tail_different_indices_different_paths(old_cont.path(), j as usize, old_cont.idx);
433                        assert(sibling_root_path != cur_entry_path);
434
435                        admit();
436                    };
437                } else {
438                    assert(new_owner.continuations[i] == self.continuations[i]);
439                    admit();
440                }
441            };
442        };
443        assert(new_owner.nodes_locked(guards)) by {
444            assert forall |i: int|
445                #![trigger new_owner.continuations[i]]
446                new_owner.level - 1 <= i < NR_LEVELS implies
447                new_owner.continuations[i].node_locked(guards) by {
448
449                if i == self.level - 2 {
450                    assert(new_owner.continuations[i] == child_cont);
451                    assert(child_cont.guard_perm == guard_perm);
452                } else {
453                    assert(i >= self.level - 1);
454                    if i == self.level - 1 {
455                        assert(new_owner.continuations[i] == modified_cont);
456                        assert(modified_cont.guard_perm == old_cont.guard_perm);
457                    } else {
458                        assert(new_owner.continuations[i] == self.continuations[i]);
459                    }
460                }
461            };
462        };
463
464        assert(new_owner.relate_region(regions)) by {
465            let f = PageTableOwner::<C>::relate_region_pred(regions);
466            let g = PageTableOwner::<C>::path_tracked_pred(regions);
467            let child_subtree = child_cont.as_subtree();
468            self.cont_entries_relate_region(regions);
469
470            assert forall |i: int| #![auto]
471                new_owner.level - 1 <= i < NR_LEVELS implies {
472                    &&& f(new_owner.continuations[i].entry_own, new_owner.continuations[i].path())
473                    &&& new_owner.continuations[i].map_children(f)
474                    &&& g(new_owner.continuations[i].entry_own, new_owner.continuations[i].path())
475                    &&& new_owner.continuations[i].map_children(g)
476                } by {
477                if i == self.level - 2 {
478                    assert(new_owner.continuations[i] == child_cont);
479                    assert(f(new_owner.continuations[i].entry_own, new_owner.continuations[i].path()));
480                    assert(g(new_owner.continuations[i].entry_own, new_owner.continuations[i].path()));
481                    assert(child_subtree.inv()) by {
482                        assert(child_subtree.value.inv());
483                        assert(child_subtree.level < INC_LEVELS);
484                        assert(child_subtree.children.len() == NR_ENTRIES);
485                        assert(child_cont.entry_own.is_node());
486                        assert(child_cont.tree_level < INC_LEVELS - 1);
487                        assert(child_subtree.inv_node());
488                        assert(child_subtree.inv_children()) by {
489                            assert(child_subtree.level < INC_LEVELS - 1);
490                            assert forall |j: int| 0 <= j < NR_ENTRIES implies
491                                match #[trigger] child_subtree.children[j] {
492                                    Some(ch) => {
493                                        &&& ch.level == child_subtree.level + 1
494                                        &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, j, Some(ch.value))
495                                    },
496                                    None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, j, None),
497                                }
498                            by {
499                                assert(child_cont.children[j] is Some);
500                                let ch = child_cont.children[j].unwrap();
501                                assert(ch.level == child_cont.tree_level + 1);
502                                assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
503                                    child_cont.entry_own, j, Some(ch.value)));
504                            };
505                        };
506                        assert forall |j: int| 0 <= j < NR_ENTRIES implies
507                            match #[trigger] child_subtree.children[j] {
508                                Some(ch) => ch.inv(),
509                                None => true,
510                            }
511                        by {
512                            child_cont.inv_children_unroll(j);
513                            assert(child_cont.children[j] is Some);
514                            assert(child_cont.children[j].unwrap().inv());
515                        };
516                    };
517                    assert(child_subtree.tree_predicate_map(child_cont.path(), f)) by {
518                        assert(f(child_subtree.value, child_cont.path()));
519                        assert forall |j: int| 0 <= j < child_subtree.children.len() implies
520                            match #[trigger] child_subtree.children[j] {
521                                Some(ch) => ch.tree_predicate_map(child_cont.path().push_tail(j as usize), f),
522                                None => true,
523                            }
524                        by {
525                            child_subtree.map_unroll_once(child_cont.path(), f, j);
526                        };
527                    };
528                    assert(child_subtree.tree_predicate_map(child_cont.path(), g)) by {
529                        assert(g(child_subtree.value, child_cont.path()));
530                        assert forall |j: int| 0 <= j < child_subtree.children.len() implies
531                            match #[trigger] child_subtree.children[j] {
532                                Some(ch) => ch.tree_predicate_map(child_cont.path().push_tail(j as usize), g),
533                                None => true,
534                            }
535                        by {
536                            child_subtree.map_unroll_once(child_cont.path(), g, j);
537                        };
538                    };
539                    assert(new_owner.continuations[i].map_children(f));
540                    assert(new_owner.continuations[i].map_children(g));
541                } else if i == self.level - 1 {
542                    assert(new_owner.continuations[i] == modified_cont);
543                    assert(modified_cont.entry_own == old_cont.entry_own);
544                    assert(modified_cont.path() == old_cont.path());
545                    assert(f(modified_cont.entry_own, modified_cont.path()));
546                    assert(g(modified_cont.entry_own, modified_cont.path()));
547                    assert(modified_cont.map_children(f)) by {
548                        assert forall |j: int|
549                            0 <= j < modified_cont.children.len() && #[trigger] modified_cont.children[j] is Some implies
550                            modified_cont.children[j].unwrap().tree_predicate_map(modified_cont.path().push_tail(j as usize), f) by {
551                            assert(j != old_cont.idx as int);
552                            assert(modified_cont.children[j] == old_cont.children[j]);
553                        };
554                    };
555                    assert(modified_cont.map_children(g)) by {
556                        assert forall |j: int|
557                            0 <= j < modified_cont.children.len() && #[trigger] modified_cont.children[j] is Some implies
558                            modified_cont.children[j].unwrap().tree_predicate_map(modified_cont.path().push_tail(j as usize), g) by {
559                            assert(j != old_cont.idx as int);
560                            assert(modified_cont.children[j] == old_cont.children[j]);
561                        };
562                    };
563                } else {
564                    assert(new_owner.continuations[i] == self.continuations[i]);
565                    assert(f(new_owner.continuations[i].entry_own, new_owner.continuations[i].path()));
566                    assert(new_owner.continuations[i].map_children(f));
567                    assert(g(new_owner.continuations[i].entry_own, new_owner.continuations[i].path()));
568                    assert(new_owner.continuations[i].map_children(g));
569                }
570            };
571        };
572    }
573
574    #[verifier::returns(proof)]
575    pub proof fn push_level_owner(tracked &mut self, tracked guard_perm: Tracked<GuardPerm<'rcu, C>>)
576        requires
577            old(self).inv(),
578            old(self).level > 1,
579        ensures
580            *self == old(self).push_level_owner_spec(guard_perm@),
581    {
582        assert(self.va.index.contains_key(self.level - 2));
583
584        let ghost self0 = *self;
585        let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
586        let ghost cont0 = cont;
587        let tracked child = cont.make_cont(self.va.index[self.level - 2] as usize, guard_perm);
588
589        assert((child, cont) == cont0.make_cont_spec(self.va.index[self.level - 2] as usize, guard_perm@));
590
591        self.continuations.tracked_insert(self.level - 1, cont);
592        self.continuations.tracked_insert(self.level - 2, child);
593
594        assert(self.continuations == self0.continuations.insert(self.level - 1, cont).insert(self.level - 2, child));
595
596        self.popped_too_high = false;
597
598        self.level = (self.level - 1) as u8;
599    }
600
601    pub open spec fn pop_level_owner_spec(self) -> (Self, GuardPerm<'rcu, C>)
602    {
603        let child = self.continuations[self.level - 1];
604        let cont = self.continuations[self.level as int];
605        let (new_cont, guard_perm) = cont.restore_spec(child);
606        let new_continuations = self.continuations.insert(self.level as int, new_cont);
607        let new_continuations = new_continuations.remove(self.level - 1);
608        let new_level = (self.level + 1) as u8;
609        let popped_too_high = if new_level >= self.guard_level { true } else { false };
610        (Self {
611            continuations: new_continuations,
612            level: new_level,
613            popped_too_high: popped_too_high,
614            ..self
615        }, guard_perm)
616    }
617
618    pub proof fn pop_level_owner_preserves_inv(self)
619        requires
620            self.inv(),
621            self.level < NR_LEVELS,
622        ensures
623            self.pop_level_owner_spec().0.inv(),
624    {
625        reveal(CursorContinuation::inv_children);
626        let child = self.continuations[self.level - 1];
627        assert(child.inv());
628
629        let cont = self.continuations[self.level as int];
630        assert(cont.inv());
631        let (new_cont, _) = cont.restore_spec(child);
632
633        let child_node = OwnerSubtree {
634            value: child.entry_own,
635            level: child.tree_level,
636            children: child.children,
637        };
638
639        assert(new_cont.children[new_cont.idx as int].unwrap() == child_node);
640        admit();
641    }
642
643    pub proof fn pop_level_owner_preserves_invs(self, guards: Guards<'rcu, C>, regions: MetaRegionOwners)
644        requires
645            self.inv(),
646            self.level < NR_LEVELS,
647            self.children_not_locked(guards),
648            self.nodes_locked(guards),
649            self.relate_region(regions),
650        ensures
651            self.pop_level_owner_spec().0.inv(),
652            self.pop_level_owner_spec().0.only_current_locked(guards),
653            self.pop_level_owner_spec().0.nodes_locked(guards),
654            self.pop_level_owner_spec().0.relate_region(regions),
655    {
656        let new_owner = self.pop_level_owner_spec().0;
657        let child = self.continuations[self.level - 1];
658        let cont = self.continuations[self.level as int];
659        let (new_cont, _guard_perm) = cont.restore_spec(child);
660        let child_node = OwnerSubtree {
661            value: child.entry_own,
662            level: child.tree_level,
663            children: child.children,
664        };
665
666        self.pop_level_owner_preserves_inv();
667
668        // in_locked_range: va, prefix, guard_level unchanged by pop (..self)
669        assert(new_owner.va == self.va);
670        assert(new_owner.prefix == self.prefix);
671        assert(new_owner.guard_level == self.guard_level);
672
673        // nodes_locked: range shrinks from [self.level-1, NR_LEVELS) to [self.level, NR_LEVELS)
674        // new_cont.guard_perm = cont.guard_perm (restore only changes children)
675        assert(new_owner.nodes_locked(guards)) by {
676            assert forall |i: int|
677                #![trigger new_owner.continuations[i]]
678                new_owner.level - 1 <= i < NR_LEVELS implies
679                new_owner.continuations[i].node_locked(guards) by {
680                    if i == self.level as int {
681                        assert(new_owner.continuations[i] == new_cont);
682                        assert(new_cont.guard_perm == cont.guard_perm);
683                    } else {
684                        assert(new_owner.continuations[i] == self.continuations[i]);
685                    }
686                };
687        };
688
689        // only_current_locked: excepted address is child.entry_own.node.meta_perm.addr()
690        // After pop, cur_entry_owner = child.entry_own (restored as child_node at cont.idx)
691        let child_addr = child.entry_own.node.unwrap().meta_perm.addr();
692
693        // node_unlocked implies node_unlocked_except for any address
694        assert(OwnerSubtree::<C>::implies(
695            CursorOwner::<'rcu, C>::node_unlocked(guards),
696            CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
697        ));
698
699        // Lift: all old continuations satisfy node_unlocked_except
700        self.map_children_implies(
701            CursorOwner::<'rcu, C>::node_unlocked(guards),
702            CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
703        );
704
705        // For levels > self.level: new continuations == old continuations, already covered
706        // For level == self.level: new_cont has child restored at cont.idx
707        assert(new_owner.only_current_locked(guards)) by {
708            assert forall |i: int|
709                #![trigger new_owner.continuations[i]]
710                new_owner.level - 1 <= i < NR_LEVELS implies
711                new_owner.continuations[i].map_children(
712                    CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr)) by {
713                if i > self.level as int {
714                    assert(new_owner.continuations[i] == self.continuations[i]);
715                    // Already have node_unlocked_except from map_children_implies above
716                } else {
717                    // i == self.level
718                    assert(new_owner.continuations[i] == new_cont);
719                    // new_cont = cont with children[cont.idx] = Some(child_node)
720                    // For j != cont.idx: same as cont, node_unlocked_except from above
721                    // For j == cont.idx: child_node.value == child.entry_own,
722                    //   child_addr == child.entry_own addr, so node_unlocked_except is vacuous
723                    //   Children from child.map_children(node_unlocked) -> node_unlocked_except
724                    let child_subtree = child.as_subtree();
725                    assert(child_subtree.inv()) by {
726                        assert(child_subtree.value.inv());
727                        assert(child_subtree.level < INC_LEVELS);
728                        assert(child_subtree.children.len() == NR_ENTRIES);
729                        assert forall |j: int| 0 <= j < NR_ENTRIES implies
730                            match #[trigger] child_subtree.children[j] {
731                                Some(ch) => ch.inv(),
732                                None => true,
733                            }
734                        by {
735                            child.inv_children_unroll(j);
736                        };
737                    };
738                    new_cont.map_children_lift_skip_idx(
739                        cont,
740                        cont.idx as int,
741                        CursorOwner::<'rcu, C>::node_unlocked(guards),
742                        CursorOwner::<'rcu, C>::node_unlocked_except(guards, child_addr),
743                    );
744                }
745            };
746        };
747
748        // relate_region: child.entry_own.relate_region(regions) is not directly tracked by
749        // map_full_tree (which only checks map_children, not entry_own of continuations).
750        // This property was established when push extracted the child from the parent's subtree,
751        // and is invariant since no operations modify higher-level entry_owns.
752        assert(new_owner.relate_region(regions)) by {
753            let f = PageTableOwner::<C>::relate_region_pred(regions);
754            let g = PageTableOwner::<C>::path_tracked_pred(regions);
755            let child_subtree = child.as_subtree();
756            self.cont_entries_relate_region(regions);
757
758            assert forall |i: int| #![auto]
759                new_owner.level - 1 <= i < NR_LEVELS implies {
760                    &&& new_owner.continuations[i].map_children(f)
761                    &&& new_owner.continuations[i].map_children(g)
762                } by {
763                if i > self.level as int {
764                } else {
765                    assert(child_subtree.inv()) by {
766                        assert forall |j: int| 0 <= j < NR_ENTRIES implies
767                            match #[trigger] child_subtree.children[j] {
768                                Some(ch) => ch.inv(),
769                                None => true,
770                            }
771                        by {
772                            child.inv_children_unroll(j);
773                        };
774                    };
775                    new_cont.map_children_lift_skip_idx(cont, cont.idx as int, f, f);
776                    new_cont.map_children_lift_skip_idx(cont, cont.idx as int, g, g);
777                }
778            };
779        };
780    }
781
782    /// Update va to a new value that shares the same indices at levels >= self.level.
783    /// This preserves invariants because:
784    /// 1. The new va satisfies va.inv()
785    /// 2. The indices at levels >= level match the continuation indices
786    /// 3. in_locked_range/above_locked_range depend on va but the preconditions ensure consistency
787    pub proof fn set_va_preserves_inv(self, new_va: AbstractVaddr)
788        requires
789            self.inv(),
790            new_va.inv(),
791            forall |i: int| #![auto] self.level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.va.index[i],
792            forall |i: int| #![auto] self.guard_level - 1 <= i < NR_LEVELS ==> new_va.index[i] == self.prefix.index[i],
793        ensures
794            self.set_va_spec(new_va).inv(),
795    {
796        admit()
797    }
798
799    #[verifier::returns(proof)]
800    pub proof fn pop_level_owner(tracked &mut self) -> (tracked guard_perm: GuardPerm<'rcu, C>)
801        requires
802            old(self).inv(),
803            old(self).level < NR_LEVELS,
804        ensures
805            *self == old(self).pop_level_owner_spec().0,
806            guard_perm == old(self).pop_level_owner_spec().1,
807    {
808        let ghost self0 = *self;
809        let tracked mut parent = self.continuations.tracked_remove(self.level as int);
810        let tracked child = self.continuations.tracked_remove(self.level - 1);
811
812        let tracked guard_perm = parent.restore(child);
813
814        self.continuations.tracked_insert(self.level as int, parent);
815
816        assert(self.continuations == self0.continuations.insert(self.level as int, parent).remove(self.level - 1));
817
818        self.level = (self.level + 1) as u8;
819
820        if self.level >= self.guard_level {
821            self.popped_too_high = true;
822        }
823
824        guard_perm
825    }
826
827    pub open spec fn move_forward_owner_spec(self) -> Self
828        recommends
829            self.inv(),
830            self.level < NR_LEVELS,
831            self.in_locked_range(),
832        decreases NR_LEVELS - self.level when self.level <= NR_LEVELS
833    {
834        if self.index() + 1 < NR_ENTRIES {
835            self.inc_index().zero_below_level()
836        } else if self.level < NR_LEVELS {
837            self.pop_level_owner_spec().0.move_forward_owner_spec()
838        } else {
839            // Should never happen
840            Self {
841                popped_too_high: false,
842                ..self
843            }
844        }
845    }
846
847    pub proof fn move_forward_increases_va(self)
848        requires
849            self.inv(),
850            self.level <= NR_LEVELS,
851            self.in_locked_range(),
852        ensures
853            self.move_forward_owner_spec().va.to_vaddr() > self.va.to_vaddr(),
854        decreases NR_LEVELS - self.level
855    {
856        if self.index() + 1 < NR_ENTRIES {
857            self.inc_and_zero_increases_va();
858        } else if self.level < NR_LEVELS {
859            self.pop_level_owner_preserves_inv();
860            self.pop_level_owner_spec().0.move_forward_increases_va();
861        } else {
862            admit();
863        }
864    }
865
866    pub proof fn move_forward_not_popped_too_high(self)
867        requires
868            self.inv(),
869            self.level <= NR_LEVELS,
870            self.in_locked_range(),
871        ensures
872            !self.move_forward_owner_spec().popped_too_high,
873       decreases NR_LEVELS - self.level,
874    {
875        if self.index() + 1 < NR_ENTRIES {
876            self.inc_index().zero_preserves_all_but_va();
877        } else if self.level < NR_LEVELS {
878            self.pop_level_owner_preserves_inv();
879            self.pop_level_owner_spec().0.move_forward_not_popped_too_high();
880        }
881    }
882
883    pub proof fn move_forward_owner_decreases_steps(self)
884        requires
885            self.inv(),
886            self.level <= NR_LEVELS,
887        ensures
888            self.move_forward_owner_spec().max_steps() < self.max_steps()
889    { admit() }
890
891    pub proof fn move_forward_va_is_align_up(self)
892        requires
893            self.inv(),
894            self.level <= NR_LEVELS,
895        ensures
896            self.move_forward_owner_spec().va == self.va.align_up(self.level as int),
897        decreases NR_LEVELS - self.level
898    {
899        admit()
900    }
901
902    /// After popping a level, the total view_mappings is preserved.
903    /// The restored parent at index self.level absorbs the child's mappings,
904    /// and both are within the view_mappings range [self.level, NR_LEVELS).
905    pub proof fn pop_level_owner_preserves_mappings(self)
906        requires
907            self.inv(),
908            self.level < NR_LEVELS,
909            self.in_locked_range(),
910        ensures
911            self.pop_level_owner_spec().0@.mappings == self@.mappings,
912    {
913        let child = self.continuations[self.level - 1];
914        let parent = self.continuations[self.level as int];
915        let (restored_parent, _) = parent.restore_spec(child);
916        let popped = self.pop_level_owner_spec().0;
917        let child_subtree = child.as_subtree();
918
919        // From cursor invariant
920        assert(child.inv());
921        assert(child.all_some());
922        assert(parent.inv());
923        assert(parent.all_but_index_some());
924
925        // Path relationship follows from CursorOwner::inv() path consistency conditions
926        assert(child.path() == parent.path().push_tail(parent.idx as usize));
927
928        // child.as_subtree().inv() follows from child.inv() + child.all_some()
929        assert(child_subtree.inv()) by {
930            // inv_node: value.inv(), la_inv(level), level < L, children.len() == N
931            assert(child_subtree.value.inv());
932            assert(child_subtree.level < INC_LEVELS);
933            assert(child_subtree.children.len() == NR_ENTRIES);
934            // la_inv: is_node() ==> tree_level < INC_LEVELS - 1
935            assert(child.entry_own.is_node());
936            assert(child.tree_level < INC_LEVELS - 1);
937            assert(child_subtree.inv_node());
938
939            // inv_children: for each i, child.level == tree_level + 1, rel_children holds
940            assert(child_subtree.inv_children()) by {
941                assert(child_subtree.level < INC_LEVELS - 1);
942                assert forall |i: int| 0 <= i < NR_ENTRIES implies
943                    match #[trigger] child_subtree.children[i] {
944                        Some(ch) => {
945                            &&& ch.level == child_subtree.level + 1
946                            &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, i, Some(ch.value))
947                        },
948                        None => <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(child_subtree.value, i, None),
949                    }
950                by {
951                    assert(child.children[i] is Some);
952                    let ch = child.children[i].unwrap();
953                    assert(ch.level == child.tree_level + 1);
954                    // rel_children body is identical for TreeNodeValue<NR_LEVELS> and <INC_LEVELS>
955                    assert(<EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(
956                        child.entry_own, i, Some(ch.value)));
957                };
958            };
959
960            // Recursive child invariants
961            assert forall |i: int| 0 <= i < NR_ENTRIES implies
962                match #[trigger] child_subtree.children[i] {
963                    Some(ch) => ch.inv(),
964                    None => true,
965                }
966            by {
967                child.inv_children_unroll(i);
968                assert(child.children[i] is Some);
969                assert(child.children[i].unwrap().inv());
970            };
971        };
972
973        // Connect restore_spec to put_child_spec via as_subtree_restore
974        parent.as_subtree_restore(child);
975        // restored_parent.as_subtree() == parent.put_child_spec(child_subtree).as_subtree()
976
977        // Since view_mappings depends only on children and path() (= entry_own.path),
978        // and as_subtree() captures both, equal subtrees give equal view_mappings.
979        assert(restored_parent.view_mappings() =~=
980            parent.put_child_spec(child_subtree).view_mappings()) by {
981            let r = restored_parent;
982            let p = parent.put_child_spec(child_subtree);
983            assert(r.children =~= p.children) by {
984                assert forall |j: int| 0 <= j < r.children.len()
985                    implies r.children[j] == p.children[j] by {
986                    if j == parent.idx as int {
987                        assert(r.children[j] == Some(child_subtree));
988                    } else {
989                        assert(r.children[j] == parent.children[j]);
990                    }
991                };
992            };
993            assert(r.path() == p.path());
994            // With same children and path, view_mappings are the same
995            assert forall |m: Mapping| r.view_mappings().contains(m)
996                implies p.view_mappings().contains(m) by {
997                let j = choose |j: int| #![auto]
998                    0 <= j < r.children.len()
999                    && r.children[j] is Some
1000                    && PageTableOwner(r.children[j].unwrap()).view_rec(
1001                        r.path().push_tail(j as usize)).contains(m);
1002                assert(p.children[j] is Some);
1003                assert(PageTableOwner(p.children[j].unwrap()).view_rec(
1004                    p.path().push_tail(j as usize)).contains(m));
1005            };
1006            assert forall |m: Mapping| p.view_mappings().contains(m)
1007                implies r.view_mappings().contains(m) by {
1008                let j = choose |j: int| #![auto]
1009                    0 <= j < p.children.len()
1010                    && p.children[j] is Some
1011                    && PageTableOwner(p.children[j].unwrap()).view_rec(
1012                        p.path().push_tail(j as usize)).contains(m);
1013                assert(r.children[j] is Some);
1014                assert(PageTableOwner(r.children[j].unwrap()).view_rec(
1015                    r.path().push_tail(j as usize)).contains(m));
1016            };
1017        };
1018
1019        // view_mappings_put_child: parent.put_child_spec(child_subtree).view_mappings()
1020        //   == parent.view_mappings() + PTO(child_subtree).view_rec(parent.path().push_tail(parent.idx))
1021        parent.view_mappings_put_child(child_subtree);
1022
1023        // as_page_table_owner_preserves_view_mappings:
1024        //   PTO(child.as_subtree()).view_rec(child.path()) == child.view_mappings()
1025        child.as_page_table_owner_preserves_view_mappings();
1026
1027        // Combined with path relationship:
1028        //   PTO(child_subtree).view_rec(parent.path().push_tail(parent.idx)) == child.view_mappings()
1029        // Therefore:
1030        //   restored_parent.view_mappings() == parent.view_mappings() + child.view_mappings()
1031
1032        // Now show popped.view_mappings() == self.view_mappings()
1033        // popped has level = self.level + 1, continuations[self.level] = restored_parent
1034        // self has level, continuations[self.level - 1] = child, continuations[self.level] = parent
1035        assert(popped.level == (self.level + 1) as u8);
1036        assert(popped.continuations[self.level as int] == restored_parent);
1037
1038        // The restored parent at index self.level is within the
1039        // view_mappings range [self.level, NR_LEVELS).
1040        assert(popped.view_mappings() =~= self.view_mappings()) by {
1041            // Forward: self.view_mappings() ⊆ popped.view_mappings()
1042            assert forall |m: Mapping| self.view_mappings().contains(m)
1043                implies popped.view_mappings().contains(m) by {
1044                let i = choose |i: int|
1045                    self.level - 1 <= i < NR_LEVELS
1046                    && (#[trigger] self.continuations[i]).view_mappings().contains(m);
1047                if i == self.level - 1 {
1048                    // m in child.view_mappings() ⊆ restored_parent.view_mappings()
1049                    assert(child.view_mappings().contains(m));
1050                    assert(restored_parent.view_mappings().contains(m));
1051                    assert(popped.continuations[self.level as int].view_mappings().contains(m));
1052                } else if i == self.level as int {
1053                    // m in parent.view_mappings() ⊆ restored_parent.view_mappings()
1054                    assert(parent.view_mappings().contains(m));
1055                    assert(restored_parent.view_mappings().contains(m));
1056                    assert(popped.continuations[self.level as int].view_mappings().contains(m));
1057                } else {
1058                    // i > self.level, unchanged
1059                    assert(popped.continuations[i] == self.continuations[i]);
1060                }
1061            };
1062            // Backward: popped.view_mappings() ⊆ self.view_mappings()
1063            assert forall |m: Mapping| popped.view_mappings().contains(m)
1064                implies self.view_mappings().contains(m) by {
1065                let i = choose |i: int|
1066                    popped.level - 1 <= i < NR_LEVELS
1067                    && (#[trigger] popped.continuations[i]).view_mappings().contains(m);
1068                if i == self.level as int {
1069                    // m in restored_parent.view_mappings()
1070                    //   = parent.view_mappings() ∪ child.view_mappings()
1071                    assert(restored_parent.view_mappings().contains(m));
1072                    if child.view_mappings().contains(m) {
1073                        assert(self.continuations[self.level - 1].view_mappings().contains(m));
1074                    } else {
1075                        assert(parent.view_mappings().contains(m));
1076                        assert(self.continuations[self.level as int].view_mappings().contains(m));
1077                    }
1078                } else {
1079                    assert(self.continuations[i] == popped.continuations[i]);
1080                }
1081            };
1082        };
1083    }
1084
1085    pub proof fn move_forward_owner_preserves_mappings(self)
1086    requires
1087        self.inv(),
1088        self.in_locked_range(),
1089    ensures
1090        self.move_forward_owner_spec()@.mappings == self@.mappings,
1091    decreases NR_LEVELS - self.level,
1092    {
1093        if self.index() + 1 < NR_ENTRIES {
1094            // Case 1: result = self.inc_index().zero_below_level()
1095            let inc = self.inc_index();
1096            let result = inc.zero_below_level();
1097
1098            // zero_below_level preserves continuations and level
1099            inc.zero_preserves_all_but_va();
1100            assert(result.continuations =~= inc.continuations);
1101            assert(result.level == inc.level);
1102
1103            // inc_index only changes idx at level-1; children and entry_own unchanged
1104            let old_cont = self.continuations[self.level - 1];
1105            let new_cont = old_cont.inc_index();
1106            assert(new_cont.children =~= old_cont.children);
1107            assert(new_cont.entry_own == old_cont.entry_own);
1108            assert(new_cont.path() == old_cont.path());
1109
1110            // CursorContinuation::view_mappings depends on children and path(), not idx
1111            assert(new_cont.view_mappings() =~= old_cont.view_mappings()) by {
1112                assert forall |m: Mapping| old_cont.view_mappings().contains(m)
1113                    implies new_cont.view_mappings().contains(m) by {
1114                    let i = choose |i: int| #![auto]
1115                        0 <= i < old_cont.children.len()
1116                        && old_cont.children[i] is Some
1117                        && PageTableOwner(old_cont.children[i].unwrap()).view_rec(
1118                            old_cont.path().push_tail(i as usize)).contains(m);
1119                    assert(new_cont.children[i] is Some);
1120                    assert(PageTableOwner(new_cont.children[i].unwrap()).view_rec(
1121                        new_cont.path().push_tail(i as usize)).contains(m));
1122                };
1123                assert forall |m: Mapping| new_cont.view_mappings().contains(m)
1124                    implies old_cont.view_mappings().contains(m) by {
1125                    let i = choose |i: int| #![auto]
1126                        0 <= i < new_cont.children.len()
1127                        && new_cont.children[i] is Some
1128                        && PageTableOwner(new_cont.children[i].unwrap()).view_rec(
1129                            new_cont.path().push_tail(i as usize)).contains(m);
1130                    assert(old_cont.children[i] is Some);
1131                    assert(PageTableOwner(old_cont.children[i].unwrap()).view_rec(
1132                        old_cont.path().push_tail(i as usize)).contains(m));
1133                };
1134            };
1135
1136            // Now result.view_mappings() == self.view_mappings()
1137            assert(result.view_mappings() =~= self.view_mappings()) by {
1138                assert forall |m: Mapping| self.view_mappings().contains(m)
1139                    implies result.view_mappings().contains(m) by {
1140                    let i = choose |i: int|
1141                        self.level - 1 <= i < NR_LEVELS
1142                        && (#[trigger] self.continuations[i]).view_mappings().contains(m);
1143                    if i == self.level - 1 {
1144                        assert(result.continuations[i].view_mappings().contains(m));
1145                    } else {
1146                        assert(result.continuations[i] == self.continuations[i]);
1147                    }
1148                };
1149                assert forall |m: Mapping| result.view_mappings().contains(m)
1150                    implies self.view_mappings().contains(m) by {
1151                    let i = choose |i: int|
1152                        result.level - 1 <= i < NR_LEVELS
1153                        && (#[trigger] result.continuations[i]).view_mappings().contains(m);
1154                    if i == self.level - 1 {
1155                        assert(self.continuations[i].view_mappings().contains(m));
1156                    } else {
1157                        assert(self.continuations[i] == result.continuations[i]);
1158                    }
1159                };
1160            };
1161        } else if self.level < NR_LEVELS {
1162            // Case 2: result = self.pop_level_owner_spec().0.move_forward_owner_spec()
1163            let popped = self.pop_level_owner_spec().0;
1164
1165            // Pop preserves inv and in_locked_range
1166            self.pop_level_owner_preserves_inv();
1167            assert(popped.in_locked_range()) by {
1168                assert(popped.va == self.va);
1169                assert(popped.prefix == self.prefix);
1170                assert(popped.guard_level == self.guard_level);
1171            };
1172
1173            // Pop preserves mappings (restored parent within view_mappings range)
1174            self.pop_level_owner_preserves_mappings();
1175            // Inductive step
1176            popped.move_forward_owner_preserves_mappings();
1177        } else {
1178            // Case 3: level >= NR_LEVELS, only popped_too_high changes
1179            // continuations and level unchanged, view_mappings trivially preserved
1180        }
1181    }
1182
1183    /// After `move_forward_owner_spec`, the cursor remains within the locked range.
1184    pub proof fn move_forward_owner_preserves_in_locked_range(self)
1185        requires
1186            self.inv(),
1187            self.level <= NR_LEVELS,
1188            self.in_locked_range(),
1189        ensures
1190            self.move_forward_owner_spec().in_locked_range(),
1191        decreases NR_LEVELS - self.level,
1192    {
1193        if self.index() + 1 < NR_ENTRIES {
1194            // inc_index + zero_below_level: VA advances within the current node.
1195            // The node fits within the locked range, so the new VA is still in range.
1196            admit();
1197        } else if self.level < NR_LEVELS {
1198            // Pop + recurse: pop preserves VA (and thus in_locked_range),
1199            // then the recursive call preserves it.
1200            self.pop_level_owner_preserves_inv();
1201            let popped = self.pop_level_owner_spec().0;
1202            // pop preserves va, prefix, guard_level, so in_locked_range is preserved.
1203            assert(popped.in_locked_range());
1204            popped.move_forward_owner_preserves_in_locked_range();
1205        } else {
1206            // level == NR_LEVELS: unreachable (in_locked_range + inv ==> level < guard_level <= NR_LEVELS,
1207            // but level <= NR_LEVELS, so level == NR_LEVELS means guard_level == NR_LEVELS too)
1208        }
1209    }
1210
1211    /// After the pop loop in `move_forward`, the cursor level is strictly below guard_level.
1212    ///
1213    /// The loop exits when `level >= guard_level` OR `pte_index != 0`. The `level >= guard_level`
1214    /// case is impossible: reaching guard_level via pop would set `popped_too_high = true`, but
1215    /// the loop invariant `owner.move_forward_owner_spec() == owner0.move_forward_owner_spec()`
1216    /// combined with `move_forward_not_popped_too_high` gives
1217    /// `!owner.move_forward_owner_spec().popped_too_high`, and `move_forward_owner_spec()`
1218    /// on a `popped_too_high` state gives a different result — a contradiction.
1219    pub proof fn move_forward_pop_loop_level_lt_guard(self, owner0: Self)
1220        requires
1221            self.inv(),
1222            self.in_locked_range(),
1223            self.level <= self.guard_level,
1224            owner0.inv(),
1225            owner0.in_locked_range(),
1226            self.move_forward_owner_spec() == owner0.move_forward_owner_spec(),
1227            !owner0.move_forward_owner_spec().popped_too_high,
1228        ensures
1229            self.level < self.guard_level,
1230    {
1231        // From inv: !popped_too_high ==> level < guard_level || above_locked_range.
1232        // in_locked_range ==> !above_locked_range.
1233        // So !popped_too_high ==> level < guard_level.
1234        if !self.popped_too_high {
1235            assert(self.in_locked_range() ==> !self.above_locked_range());
1236        } else {
1237            // popped_too_high: from inv, level >= guard_level.
1238            // With level <= guard_level: level == guard_level.
1239            // Need contradiction from move_forward_owner_spec preconditions.
1240            // popped_too_high at guard_level + in_locked_range is a valid state,
1241            // but move_forward_owner_spec on such a state advances past the locked
1242            // range, setting popped_too_high = false but above_locked_range.
1243            // owner0 starts in_locked_range with !popped_too_high (from its own inv),
1244            // so owner0.move_forward_owner_spec() != self.move_forward_owner_spec()
1245            // in this case — contradicting the precondition.
1246            admit();
1247        }
1248    }
1249}
1250
1251}