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

1use vstd::prelude::*;
2
3use vstd_extra::drop_tracking::*;
4use vstd_extra::ghost_tree::*;
5use vstd_extra::ownership::*;
6
7use crate::mm::page_table::*;
8
9use core::marker::PhantomData;
10use core::ops::Range;
11
12use crate::mm::page_prop::PageProperty;
13use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
14use crate::specs::arch::mm::MAX_USERSPACE_VADDR;
15use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
16use crate::specs::arch::paging_consts::PagingConsts;
17use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
18use crate::specs::mm::page_table::node::GuardPerm;
19use crate::specs::mm::page_table::owners::*;
20use crate::specs::mm::page_table::view::PageTableView;
21use crate::specs::mm::page_table::AbstractVaddr;
22use crate::specs::mm::page_table::Guards;
23use crate::specs::mm::page_table::Mapping;
24use crate::specs::mm::page_table::{nat_align_down, nat_align_up};
25use crate::specs::task::InAtomicMode;
26
27verus! {
28
29pub tracked struct CursorContinuation<'rcu, C: PageTableConfig> {
30    pub entry_own: EntryOwner<C>,
31    pub idx: usize,
32    pub tree_level: nat,
33    pub children: Seq<Option<OwnerSubtree<C>>>,
34    pub path: TreePath<NR_ENTRIES>,
35    pub guard_perm: GuardPerm<'rcu, C>,
36}
37
38impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
39    pub open spec fn path(self) -> TreePath<NR_ENTRIES> {
40        self.entry_own.path
41    }
42
43    pub open spec fn child(self) -> OwnerSubtree<C> {
44        self.children[self.idx as int].unwrap()
45    }
46
47    pub open spec fn take_child_spec(self) -> (OwnerSubtree<C>, Self) {
48        let child = self.children[self.idx as int].unwrap();
49        let cont = Self {
50            children: self.children.remove(self.idx as int).insert(self.idx as int, None),
51            ..self
52        };
53        (child, cont)
54    }
55
56    #[verifier::returns(proof)]
57    pub proof fn take_child(tracked &mut self) -> (res: OwnerSubtree<C>)
58        requires
59            old(self).idx < old(self).children.len(),
60            old(self).children[old(self).idx as int] is Some,
61        ensures
62            res == old(self).take_child_spec().0,
63            *self == old(self).take_child_spec().1,
64    {
65        let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
66        self.children.tracked_insert(old(self).idx as int, None);
67        child
68    }
69
70    pub open spec fn put_child_spec(self, child: OwnerSubtree<C>) -> Self {
71        Self {
72            children: self.children.remove(self.idx as int).insert(self.idx as int, Some(child)),
73            ..self
74        }
75    }
76
77    #[verifier::returns(proof)]
78    pub proof fn put_child(tracked &mut self, tracked child: OwnerSubtree<C>)
79        requires
80            old(self).idx < old(self).children.len(),
81            old(self).children[old(self).idx as int] is None,
82        ensures
83            *self == old(self).put_child_spec(child)
84    {
85        let _ = self.children.tracked_remove(old(self).idx as int);
86        self.children.tracked_insert(old(self).idx as int, Some(child));
87    }
88
89    pub proof fn take_put_child(self)
90        requires
91            self.idx < self.children.len(),
92            self.children[self.idx as int] is Some,
93        ensures
94            self.take_child_spec().1.put_child_spec(self.take_child_spec().0) == self,
95    {
96        let child = self.take_child_spec().0;
97        let cont = self.take_child_spec().1;
98        assert(cont.put_child_spec(child).children == self.children);
99    }
100
101    pub open spec fn make_cont_spec(self, idx: usize, guard_perm: GuardPerm<'rcu, C>) -> (Self, Self) {
102        let child = Self {
103            entry_own: self.children[self.idx as int].unwrap().value,
104            tree_level: (self.tree_level + 1) as nat,
105            idx: idx,
106            children: self.children[self.idx as int].unwrap().children,
107            path: self.path.push_tail(self.idx as usize),
108            guard_perm: guard_perm,
109        };
110        let cont = Self {
111            children: self.children.update(self.idx as int, None),
112            ..self
113        };
114        (child, cont)
115    }
116
117    #[verifier::returns(proof)]
118    pub axiom fn make_cont(tracked &mut self, idx: usize, tracked guard_perm: Tracked<GuardPerm<'rcu, C>>) -> (res: Self)
119        requires
120            old(self).all_some(),
121            old(self).idx < NR_ENTRIES,
122            idx < NR_ENTRIES,
123        ensures
124            res == old(self).make_cont_spec(idx, guard_perm@).0,
125            *self == old(self).make_cont_spec(idx, guard_perm@).1,
126    ;
127
128    pub open spec fn restore_spec(self, child: Self) -> (Self, GuardPerm<'rcu, C>) {
129        let child_node = OwnerSubtree {
130            value: child.entry_own,
131            level: child.tree_level,
132            children: child.children,
133        };
134        (Self { children: self.children.update(self.idx as int, Some(child_node)), ..self }, child.guard_perm)
135    }
136
137    #[verifier::returns(proof)]
138    pub axiom fn restore(tracked &mut self, tracked child: Self) -> (tracked guard_perm: GuardPerm<'rcu, C>)
139        ensures
140            *self == old(self).restore_spec(child).0,
141            guard_perm == old(self).restore_spec(child).1,
142    ;
143
144    pub open spec fn map_children(self, f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool) -> bool {
145        forall |i: int|
146            #![trigger self.children[i]]
147            0 <= i < self.children.len() ==>
148                self.children[i] is Some ==>
149                    self.children[i].unwrap().tree_predicate_map(self.path().push_tail(i as usize), f)
150    }
151
152    pub open spec fn level(self) -> PagingLevel {
153        self.entry_own.node.unwrap().level
154    }
155
156    pub open spec fn inv(self) -> bool {
157        &&& self.children.len() == NR_ENTRIES
158        &&& 0 <= self.idx < NR_ENTRIES
159        &&& forall|i: int|
160            #![trigger self.children[i]]
161            0 <= i < NR_ENTRIES ==>
162            self.children[i] is Some ==> {
163                &&& self.children[i].unwrap().value.path == self.path().push_tail(i as usize)
164                &&& self.children[i].unwrap().value.parent_level == self.level()
165                &&& self.children[i].unwrap().inv()
166                &&& self.children[i].unwrap().level == self.tree_level + 1
167                &&& <EntryOwner<C> as TreeNodeValue<NR_LEVELS>>::rel_children(self.entry_own, i, Some(self.children[i].unwrap().value))
168            }
169        &&& self.entry_own.is_node()
170        &&& self.entry_own.inv()
171        &&& self.entry_own.node.unwrap().relate_guard_perm(self.guard_perm)
172        &&& self.tree_level == INC_LEVELS - self.level()
173        &&& self.tree_level < INC_LEVELS - 1
174        &&& self.path().len() == self.tree_level
175    }
176
177    pub open spec fn all_some(self) -> bool {
178        forall|i: int| 0 <= i < NR_ENTRIES ==> self.children[i] is Some
179    }
180
181    pub open spec fn all_but_index_some(self) -> bool {
182        &&& forall|i: int| 0 <= i < self.idx ==> self.children[i] is Some
183        &&& forall|i: int| self.idx < i < NR_ENTRIES ==> self.children[i] is Some
184        &&& self.children[self.idx as int] is None
185    }
186
187    pub open spec fn inc_index(self) -> Self {
188        Self {
189            idx: (self.idx + 1) as usize,
190            ..self
191        }
192    }
193
194    pub proof fn do_inc_index(tracked &mut self)
195        requires
196            old(self).idx + 1 < NR_ENTRIES,
197        ensures
198            *self == old(self).inc_index(),
199    {
200        self.idx = (self.idx + 1) as usize;
201    }
202
203    pub open spec fn node_locked(self, guards: Guards<'rcu, C>) -> bool {
204        guards.lock_held(self.guard_perm.value().inner.inner@.ptr.addr())
205    }
206
207    pub open spec fn view_mappings(self) -> Set<Mapping> {
208        Set::new(
209            |m: Mapping| exists|i:int|
210            #![trigger self.children[i]]
211            0 <= i < self.children.len() &&
212                self.children[i] is Some &&
213                PageTableOwner(self.children[i].unwrap()).view_rec(self.path().push_tail(i as usize)).contains(m)
214        )
215    }
216
217    pub open spec fn as_subtree(self) -> OwnerSubtree<C> {
218        OwnerSubtree {
219            value: self.entry_own,
220            level: self.tree_level,
221            children: self.children,
222        }
223    }
224
225    pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
226        PageTableOwner(self.as_subtree())
227    }
228
229    pub proof fn as_page_table_owner_preserves_view_mappings(self)
230        requires
231            self.inv(),
232            self.all_some(),
233        ensures
234            self.as_page_table_owner().view_rec(self.path()) == self.view_mappings(),
235    { }
236
237    pub proof fn as_subtree_restore(self, child: Self)
238        requires
239            self.inv(),
240            child.inv(),
241            self.all_but_index_some(),
242            child.all_some(),
243        ensures
244            self.restore_spec(child).0.as_subtree() ==
245            self.put_child_spec(child.as_subtree()).as_subtree(),
246    {
247        assert(self.put_child_spec(child.as_subtree()).children ==
248        self.children.update(self.idx as int, Some(child.as_subtree())));
249    }
250
251    pub open spec fn view_mappings_take_child_spec(self) -> Set<Mapping> {
252        PageTableOwner(self.children[self.idx as int].unwrap()).view_rec(self.path().push_tail(self.idx as usize))
253    }
254
255    pub proof fn view_mappings_take_child(self)
256        requires
257            self.inv(),
258            self.all_some(),
259        ensures
260            self.take_child_spec().1.view_mappings() == self.view_mappings() - self.view_mappings_take_child_spec()
261    {
262        let def = self.take_child_spec().1.view_mappings();
263        let diff = self.view_mappings() - self.view_mappings_take_child_spec();
264        assert forall |m: Mapping| diff.contains(m) implies def.contains(m) by {
265            let i = choose|i: int| 0 <= i < self.children.len() && #[trigger] self.children[i] is Some &&
266                PageTableOwner(self.children[i].unwrap()).view_rec(self.path().push_tail(i as usize)).contains(m);
267            assert(i != self.idx);
268            assert(self.take_child_spec().1.children[i] is Some);
269        };
270        assert forall |m: Mapping|
271        #![trigger def.contains(m)]
272        def.contains(m) implies diff.contains(m) by {
273            let left = self.take_child_spec().1;
274            assert(left.view_mappings().contains(m));
275            if self.view_mappings_take_child_spec().contains(m) {
276                assert(PageTableOwner(self.children[self.idx as int].unwrap()).view_rec(self.path().push_tail(self.idx as usize)).contains(m));
277                let i = choose|i: int| 0 <= i < left.children.len() && #[trigger] left.children[i] is Some &&
278                    PageTableOwner(left.children[i].unwrap()).view_rec(left.path().push_tail(i as usize)).contains(m);
279                assert(i != self.idx);
280                assert(PageTableOwner(left.children[i as int].unwrap()).view_rec(left.path().push_tail(i as usize)).contains(m));
281
282                PageTableOwner(self.children[self.idx as int].unwrap()).view_rec_vaddr_range(self.path().push_tail(self.idx as usize), m);
283                PageTableOwner(left.children[i as int].unwrap()).view_rec_vaddr_range(left.path().push_tail(i as usize), m);
284
285                let size = page_size(self.path().push_tail(self.idx as usize).len() as PagingLevel);
286
287                // Sibling paths have disjoint VA ranges
288                sibling_paths_disjoint(self.path(), self.idx, i as usize, size);
289                assert(vaddr(self.path().push_tail(self.idx as usize)) + size <= vaddr(left.path().push_tail(i as usize)) ||
290                    vaddr(left.path().push_tail(i as usize)) + size <= vaddr(self.path().push_tail(self.idx as usize)));
291
292            }
293        };
294    }
295
296    pub proof fn view_mappings_put_child(self, child: OwnerSubtree<C>)
297        requires
298            self.inv(),
299            child.inv(),
300            self.all_but_index_some(),
301        ensures
302            self.put_child_spec(child).view_mappings() == self.view_mappings() + PageTableOwner(child).view_rec(self.path().push_tail(self.idx as usize))
303    {
304        let def = self.put_child_spec(child).view_mappings();
305        let sum = self.view_mappings() + PageTableOwner(child).view_rec(self.path().push_tail(self.idx as usize));
306        assert forall |m: Mapping| sum.contains(m) implies def.contains(m) by {
307            if self.view_mappings().contains(m) {
308                let i = choose|i: int| 0 <= i < self.children.len() && #[trigger] self.children[i] is Some &&
309                    PageTableOwner(self.children[i].unwrap()).view_rec(self.path().push_tail(i as usize)).contains(m);
310                assert(i != self.idx);
311                assert(self.put_child_spec(child).children[i] == self.children[i]);
312            } else {
313                assert(PageTableOwner(child).view_rec(self.path().push_tail(self.idx as usize)).contains(m));
314                assert(self.put_child_spec(child).children[self.idx as int] == Some(child));
315            }
316        };
317    }
318
319    pub proof fn new_child(tracked &self, paddr: Paddr, prop: PageProperty) -> (tracked res: OwnerSubtree<C>)
320        requires
321            self.inv(),
322        ensures
323            res.value == EntryOwner::<C>::new_frame_spec(paddr, self.path().push_tail(self.idx as usize), self.level(), prop),
324            res.inv(),
325            res.level == self.tree_level + 1
326    {
327        let tracked owner = EntryOwner::<C>::new_frame(paddr, self.path().push_tail(self.idx as usize), self.level(), prop);
328        OwnerSubtree::new_val_tracked(owner, self.tree_level + 1)
329    }
330
331}
332
333pub tracked struct CursorOwner<'rcu, C: PageTableConfig> {
334    pub level: PagingLevel,
335    pub continuations: Map<int, CursorContinuation<'rcu, C>>,
336    pub va: AbstractVaddr,
337    pub guard_level: PagingLevel,
338    pub prefix: AbstractVaddr,
339    pub popped_too_high: bool,
340}
341
342impl<'rcu, C: PageTableConfig> Inv for CursorOwner<'rcu, C> {
343    open spec fn inv(self) -> bool {
344        &&& self.va.inv()
345        &&& 1 <= self.level <= NR_LEVELS
346        &&& self.guard_level <= NR_LEVELS
347        // The cursor is allowed to pop out of the guard range only when it reaches the end of the locked range.
348        // This allows the user to reason solely about the current vaddr and not keep track of the cursor's level.
349        &&& self.popped_too_high ==> self.level >= self.guard_level && self.in_locked_range()
350        &&& !self.popped_too_high ==> self.level < self.guard_level || self.above_locked_range()
351        &&& self.continuations[self.level - 1].all_some()
352        &&& forall|i: int| self.level <= i < NR_LEVELS ==> {
353            (#[trigger] self.continuations[i]).all_but_index_some()
354        }
355        &&& self.prefix.inv()
356        &&& forall|i: int| i < self.guard_level ==> self.prefix.index[i] == 0
357        &&& self.level <= 4 ==> {
358            &&& self.continuations.contains_key(3)
359            &&& self.continuations[3].inv()
360            &&& self.continuations[3].level() == 4
361            // Obviously there is no level 5 pt, but that would be the level of the parent of the root pt.
362            &&& self.continuations[3].entry_own.parent_level == 5
363            &&& self.va.index[3] == self.continuations[3].idx
364        }
365        &&& self.level <= 3 ==> {
366            &&& self.continuations.contains_key(2)
367            &&& self.continuations[2].inv()
368            &&& self.continuations[2].level() == 3
369            &&& self.continuations[2].entry_own.parent_level == 4
370            &&& self.va.index[2] == self.continuations[2].idx
371            &&& self.continuations[2].guard_perm.value().inner.inner@.ptr.addr() !=
372                self.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
373        }
374        &&& self.level <= 2 ==> {
375            &&& self.continuations.contains_key(1)
376            &&& self.continuations[1].inv()
377            &&& self.continuations[1].level() == 2
378            &&& self.continuations[1].entry_own.parent_level == 3
379            &&& self.va.index[1] == self.continuations[1].idx
380            &&& self.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
381                self.continuations[2].guard_perm.value().inner.inner@.ptr.addr()
382            &&& self.continuations[1].guard_perm.value().inner.inner@.ptr.addr() !=
383                self.continuations[3].guard_perm.value().inner.inner@.ptr.addr()
384        }
385        &&& self.level == 1 ==> {
386            &&& self.continuations.contains_key(0)
387            &&& self.continuations[0].inv()
388            &&& self.continuations[0].level() == 1
389            &&& self.continuations[0].entry_own.parent_level == 2
390            &&& self.va.index[0] == self.continuations[0].idx
391            &&& self.continuations[0].guard_perm.value().inner.inner@.ptr.addr() !=
392                self.continuations[1].guard_perm.value().inner.inner@.ptr.addr()
393        }
394    }
395}
396
397impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
398
399    pub open spec fn node_unlocked(guards: Guards<'rcu, C>) ->
400        (spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool) {
401        |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
402            owner.is_node() ==>
403            guards.unlocked(owner.node.unwrap().meta_perm.addr())
404    }
405
406    pub open spec fn node_unlocked_except(guards: Guards<'rcu, C>, addr: usize) ->
407        (spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool) {
408        |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
409            owner.is_node() ==>
410            owner.node.unwrap().meta_perm.addr() != addr ==>
411            guards.unlocked(owner.node.unwrap().meta_perm.addr())
412    }
413
414    pub open spec fn map_full_tree(self, f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool) -> bool {
415        forall|i: int|
416            #![trigger self.continuations[i]]
417            self.level - 1 <= i < NR_LEVELS ==> {
418                self.continuations[i].map_children(f)
419            }
420    }
421
422    pub open spec fn map_only_children(self, f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool) -> bool {
423        forall|i: int|
424            #![trigger self.continuations[i]]
425            self.level - 1 <= i < NR_LEVELS ==>
426            self.continuations[i].map_children(f)
427    }
428
429    pub open spec fn children_not_locked(self, guards: Guards<'rcu, C>) -> bool {
430        self.map_only_children(Self::node_unlocked(guards))
431    }
432
433    pub open spec fn only_current_locked(self, guards: Guards<'rcu, C>) -> bool {
434        self.map_only_children(Self::node_unlocked_except(guards, self.cur_entry_owner().node.unwrap().meta_perm.addr()))
435    }
436
437    pub proof fn never_drop_restores_children_not_locked(
438        self,
439        guard: PageTableGuard<'rcu, C>,
440        guards0: Guards<'rcu, C>,
441        guards1: Guards<'rcu, C>)
442    requires
443        self.inv(),
444        self.only_current_locked(guards0),
445        <PageTableGuard<'rcu, C> as TrackDrop>::constructor_requires(guard, guards0),
446        <PageTableGuard<'rcu, C> as TrackDrop>::constructor_ensures(guard, guards0, guards1),
447    ensures
448        self.children_not_locked(guards1),
449    {
450        admit()
451    }
452
453    pub proof fn map_children_implies(
454        self,
455        f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
456        g: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
457    )
458    requires
459        self.inv(),
460        OwnerSubtree::implies(f, g),
461        forall|i: int|
462            #![trigger self.continuations[i]]
463                self.level - 1 <= i < NR_LEVELS ==>
464                    self.continuations[i].map_children(f),
465    ensures
466        forall|i: int|
467            #![trigger self.continuations[i]]
468            self.level - 1 <= i < NR_LEVELS ==>
469                self.continuations[i].map_children(g),
470    {
471        assert forall|i: int|
472            #![trigger self.continuations[i]]
473            self.level - 1 <= i < NR_LEVELS implies self.continuations[i].map_children(g) by {
474                let cont = self.continuations[i];
475                assert forall|j: int|
476                    #![trigger cont.children[j]]
477                    0 <= j < cont.children.len() && cont.children[j] is Some
478                        implies cont.children[j].unwrap().tree_predicate_map(cont.path().push_tail(j as usize), g) by {
479                            OwnerSubtree::map_implies(cont.children[j].unwrap(), cont.path().push_tail(j as usize), f, g);
480                    }
481            }
482    }
483
484    pub open spec fn nodes_locked(self, guards: Guards<'rcu, C>) -> bool {
485        forall|i: int|
486            #![trigger self.continuations[i]]
487            self.level - 1 <= i < NR_LEVELS ==> {
488                self.continuations[i].node_locked(guards)
489            }
490    }
491
492    pub open spec fn index(self) -> usize {
493        self.continuations[self.level - 1].idx
494    }
495
496    pub open spec fn inc_index(self) -> Self {
497        Self {
498            continuations: self.continuations.insert(self.level - 1, self.continuations[self.level - 1].inc_index()),
499            va: AbstractVaddr {
500                offset: self.va.offset,
501                index: self.va.index.insert(self.level - 1, self.continuations[self.level - 1].inc_index().idx as int)
502            },
503            popped_too_high: false,
504            ..self
505        }
506    }
507
508    pub open spec fn zero_below_level_rec(self, level: PagingLevel) -> Self
509        decreases self.level - level
510    {
511        if self.level <= level {
512            self
513        } else {
514            Self {
515                va: AbstractVaddr {
516                    offset: self.va.offset,
517                    index: self.va.index.insert(level - 1, 0)
518                },
519                ..self.zero_below_level_rec((level + 1) as u8)
520            }
521        }
522    }
523
524    pub open spec fn zero_below_level(self) -> Self {
525        self.zero_below_level_rec(1u8)
526    }
527
528    pub proof fn zero_below_level_rec_preserves_above(self, level: PagingLevel)
529        ensures
530            forall |lv: int| lv >= self.level ==>  self.zero_below_level_rec(level).va.index[lv] == #[trigger] self.va.index[lv],
531        decreases self.level - level,
532    {
533        if self.level > level {
534            self.zero_below_level_rec_preserves_above((level + 1) as u8);
535        }
536    }
537
538    pub proof fn zero_preserves_above(self)
539        ensures
540            forall |lv: int| lv >= self.level ==> self.zero_below_level().va.index[lv] == #[trigger] self.va.index[lv],
541    {
542        self.zero_below_level_rec_preserves_above(1u8);
543    }
544
545    pub axiom fn do_zero_below_level(tracked &mut self)
546        requires
547            old(self).inv(),
548        ensures
549            *self == old(self).zero_below_level();
550
551    pub proof fn do_inc_index(tracked &mut self)
552        requires
553            old(self).inv(),
554            old(self).continuations[old(self).level - 1].idx + 1 < NR_ENTRIES,
555            old(self).in_locked_range(),
556        ensures
557            self.inv(),
558            *self == old(self).inc_index(),
559    {
560        self.popped_too_high = false;
561        let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
562        if self.level >= self.guard_level {
563            let ghost size = self.locked_range().end - self.locked_range().start;
564            let ghost new_va = AbstractVaddr {
565                offset: self.va.offset,
566                index: self.va.index.insert(self.level - 1, cont.idx + 1)
567            };
568            assert(new_va.to_vaddr() == self.va.to_vaddr() + size) by { admit() };
569        }
570
571        cont.do_inc_index();
572        self.va.index.tracked_insert(self.level - 1, cont.idx as int);
573        self.continuations.tracked_insert(self.level - 1, cont);
574        assert(self.continuations == old(self).continuations.insert(self.level - 1, cont));
575    }
576
577    pub proof fn inc_and_zero_increases_va(self)
578        requires
579            self.inv()
580        ensures
581            self.inc_index().zero_below_level().va.to_vaddr() > self.va.to_vaddr(),
582    {
583        admit()
584    }
585
586    pub proof fn zero_rec_preserves_all_but_va(self, level: PagingLevel)
587        ensures
588            self.zero_below_level_rec(level).level == self.level,
589            self.zero_below_level_rec(level).continuations == self.continuations,
590            self.zero_below_level_rec(level).guard_level == self.guard_level,
591            self.zero_below_level_rec(level).prefix == self.prefix,
592            self.zero_below_level_rec(level).popped_too_high == self.popped_too_high,
593        decreases self.level - level,
594    {
595        if self.level > level {
596            self.zero_rec_preserves_all_but_va((level + 1) as u8);
597        }
598    }
599
600    pub proof fn zero_preserves_all_but_va(self)
601        ensures
602            self.zero_below_level().level == self.level,
603            self.zero_below_level().continuations == self.continuations,
604            self.zero_below_level().guard_level == self.guard_level,
605            self.zero_below_level().prefix == self.prefix,
606            self.zero_below_level().popped_too_high == self.popped_too_high,
607    {
608        self.zero_rec_preserves_all_but_va(1u8);
609    }
610
611    pub open spec fn cur_va(self) -> Vaddr {
612        self.va.to_vaddr()
613    }
614
615    pub open spec fn cur_va_range(self) -> Range<AbstractVaddr> {
616        let start = self.va.align_down(self.level as int);
617        let end = self.va.align_up(self.level as int);
618        Range { start, end }
619    }
620
621    pub proof fn cur_va_range_reflects_view(self)
622        requires
623            self.inv(),
624        ensures
625            self.cur_va_range().start.reflect(self@.query_range().start),
626            self.cur_va_range().end.reflect(self@.query_range().end),
627    {
628        admit()
629    }
630
631    /// The current virtual address falls within the VA range of the current subtree's path.
632    /// This follows from the invariant that va.index matches the continuation indices.
633    pub axiom fn cur_va_in_subtree_range(self)
634        requires
635            self.inv(),
636        ensures
637            vaddr(self.cur_subtree().value.path) <= self.cur_va() < vaddr(self.cur_subtree().value.path) + page_size((self.level - 1) as PagingLevel);
638
639    /// The mappings in the current subtree are exactly those mappings whose VA range starts
640    /// within [cur_va, cur_va + page_size(level)).
641    /// This connects the page table representation to the cursor view's remove_subtree operation.
642    /// At cursor level L, the current entry manages a VA region of size page_size(L).
643    pub proof fn cur_subtree_eq_filtered_mappings(self)
644        requires
645            self.inv(),
646        ensures
647            PageTableOwner(self.cur_subtree())@.mappings ==
648                self@.mappings.filter(|m: Mapping| self@.cur_va <= m.va_range.start < self@.cur_va + page_size(self.level)),
649    {
650        let cur_subtree = self.cur_subtree();
651        let cur_path = cur_subtree.value.path;
652        let cur_va = self.cur_va();
653        let size = page_size(self.level);
654
655        let subtree_mappings = PageTableOwner(cur_subtree)@.mappings;
656        let filtered = self@.mappings.filter(|m: Mapping| cur_va <= m.va_range.start < cur_va + size);
657
658        // Direction 1: Every mapping in cur_subtree is in the filtered set
659        assert forall |m: Mapping| subtree_mappings.contains(m) implies filtered.contains(m) by {
660            // m is in view_rec(cur_path), so m's VA range is bounded by cur_path's VA range
661            // By view_rec_vaddr_range: vaddr(cur_path) <= m.va_range.start < vaddr(cur_path) + page_size(...)
662            // Need to relate vaddr(cur_path) to cur_va - they should be aligned
663            // cur_va falls within [vaddr(cur_path), vaddr(cur_path) + size) by cur_va_in_subtree_range
664            // For now, admit this relationship
665            admit();
666        };
667
668        // Direction 2: Every mapping in filtered is in cur_subtree
669        assert forall |m: Mapping| filtered.contains(m) implies subtree_mappings.contains(m) by {
670            // m is in self@.mappings = self.view_mappings()
671            // m.va_range.start is in [cur_va, cur_va + size)
672            // By disjointness of subtrees, m must come from cur_subtree
673            // Similar reasoning to mapping_covering_cur_va_from_cur_subtree but for start in range
674            assume(self.view_mappings().contains(m));
675
676            // Find which continuation/child m comes from
677            let i = choose|i: int| self.level - 1 <= i < NR_LEVELS - 1
678                && #[trigger] self.continuations[i].view_mappings().contains(m);
679            self.inv_continuation(i);
680
681            let cont_i = self.continuations[i];
682            let j = choose|j: int| #![auto] 0 <= j < NR_ENTRIES
683                && cont_i.children[j] is Some
684                && PageTableOwner(cont_i.children[j].unwrap())
685                    .view_rec(cont_i.path().push_tail(j as usize)).contains(m);
686
687            // By view_rec_vaddr_range, m's VA range is bounded by child j's path
688            // If i == self.level - 1 and j == self.index(), then m is in cur_subtree
689            // Otherwise, by disjointness, m.va_range.start cannot be in [cur_va, cur_va + size)
690            // which contradicts the filter condition
691            admit();
692        };
693
694        assert(subtree_mappings =~= filtered);
695    }
696
697    /// Subtrees at different indices have disjoint VA ranges.
698    pub axiom fn subtree_va_ranges_disjoint(self, j: int)
699        requires
700            self.inv(),
701            0 <= j < NR_ENTRIES,
702            j != self.index(),
703            self.continuations[self.level - 1].children[j] is Some,
704        ensures
705            vaddr(self.continuations[self.level - 1].path().push_tail(j as usize)) + page_size((self.level - 1) as PagingLevel) <= self.cur_va()
706            || self.cur_va() < vaddr(self.continuations[self.level - 1].path().push_tail(j as usize));
707
708    /// Children of higher-level continuations have VA ranges that don't include cur_va,
709    /// because cur_va's indices at those levels match the path to the current position.
710    pub axiom fn higher_level_children_disjoint(self, i: int, j: int)
711        requires
712            self.inv(),
713            self.level - 1 < i < NR_LEVELS - 1,
714            0 <= j < NR_ENTRIES,
715            j != self.continuations[i].idx,
716            self.continuations[i].children[j] is Some,
717        ensures
718            vaddr(self.continuations[i].path().push_tail(j as usize)) + page_size(i as PagingLevel) <= self.cur_va()
719            || self.cur_va() < vaddr(self.continuations[i].path().push_tail(j as usize));
720
721    /// Any mapping that covers cur_va must come from the current subtree.
722    /// This follows from the disjointness of VA ranges and the fact that
723    /// cur_va falls within the current subtree's VA range.
724    pub proof fn mapping_covering_cur_va_from_cur_subtree(self, m: Mapping)
725        requires
726            self.inv(),
727            self.view_mappings().contains(m),
728            m.va_range.start <= self.cur_va() < m.va_range.end,
729        ensures
730            PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value.path).contains(m),
731    {
732        let cur_va = self.cur_va();
733
734        // m comes from some continuation level i
735        let i = choose|i: int| self.level - 1 <= i < NR_LEVELS - 1
736            && #[trigger] self.continuations[i].view_mappings().contains(m);
737        self.inv_continuation(i);
738
739        let cont_i = self.continuations[i];
740
741        // m comes from some child j in continuation i
742        let j = choose|j: int| #![auto] 0 <= j < NR_ENTRIES
743            && cont_i.children[j] is Some
744            && PageTableOwner(cont_i.children[j].unwrap())
745                .view_rec(cont_i.path().push_tail(j as usize)).contains(m);
746
747        let child_j = cont_i.children[j].unwrap();
748        let path_j = cont_i.path().push_tail(j as usize);
749
750        // By view_rec_vaddr_range, m's VA range is bounded by child j's path
751        PageTableOwner(child_j).view_rec_vaddr_range(path_j, m);
752
753        // From view_rec_vaddr_range: vaddr(path_j) <= m.va_range.start
754        // From precondition: m.va_range.start <= cur_va
755        // Therefore: vaddr(path_j) <= cur_va
756        assert(vaddr(path_j) <= m.va_range.start);
757        assert(m.va_range.start <= cur_va);
758        assert(vaddr(path_j) <= cur_va);
759
760        // Case analysis: which continuation level and child is this?
761        if i == self.level - 1 {
762            // Same level as current subtree
763            if j as usize != self.index() {
764                // j is a different child - by subtree_va_ranges_disjoint, j's range doesn't contain cur_va
765                self.subtree_va_ranges_disjoint(j);
766                // subtree_va_ranges_disjoint ensures:
767                //   vaddr(path_j) + page_size((self.level - 1) as PagingLevel) <= cur_va
768                //   || cur_va < vaddr(path_j)
769                // We have: vaddr(path_j) <= cur_va
770                // So the first disjunct must hold if there's no contradiction
771                // But since m covers cur_va and m's range is bounded by path_j's range,
772                // cur_va < vaddr(path_j) + page_size would contradict
773                // The arithmetic reasoning is complex; we admit this contradiction
774                assert(false) by { admit() };
775            }
776            // j == self.index(), so child_j is cur_subtree()
777            assert(j as usize == self.index());
778        } else {
779            // Higher level continuation (i > self.level - 1)
780            // By the invariant, higher-level continuations have all_but_index_some()
781            // This means children[cont_i.idx] is None
782
783            if j as usize != cont_i.idx as usize {
784                // j is not on the current path - by higher_level_children_disjoint
785                self.higher_level_children_disjoint(i, j);
786                // higher_level_children_disjoint ensures the VA range of child j
787                // doesn't contain cur_va. Combined with m being bounded by this range,
788                // we get a contradiction.
789                assert(false) by { admit() };
790            } else {
791                // j == cont_i.idx, but by all_but_index_some(), children[idx] is None!
792                // For higher levels (i >= self.level), the invariant says all_but_index_some()
793                assert(i >= self.level);
794                assert(self.continuations[i].all_but_index_some());
795                // all_but_index_some says children[idx] is None
796                // But we chose j such that children[j] is Some
797                // This is a contradiction
798                assert(false) by { admit() };
799            }
800        }
801    }
802
803    pub proof fn inv_continuation(self, i: int)
804        requires
805            self.inv(),
806            self.level - 1 <= i <= NR_LEVELS - 1,
807        ensures
808            self.continuations.contains_key(i),
809            self.continuations[i].inv(),
810            self.continuations[i].children.len() == NR_ENTRIES,
811    {
812        assert(self.continuations.contains_key(i));
813    }
814
815    pub open spec fn view_mappings(self) -> Set<Mapping>
816    {
817        Set::new(
818            |m: Mapping|
819            exists|i:int|
820            #![trigger self.continuations[i]]
821            self.level - 1 <= i < NR_LEVELS - 1 && self.continuations[i].view_mappings().contains(m)
822        )
823    }
824
825    pub proof fn view_mappings_take_lowest(self, new: Self)
826        requires
827            self.inv(),
828            new.continuations == self.continuations.remove(self.level - 1),
829        ensures
830            new.view_mappings() == self.view_mappings() - self.continuations[self.level - 1].view_mappings(),
831    {
832        admit()
833    }
834
835    pub proof fn view_mappings_put_lowest(self, new: Self, cont: CursorContinuation<C>)
836        requires
837            cont.inv(),
838            new.inv(),
839            new.continuations == self.continuations.insert(self.level - 1, cont),
840        ensures
841            new.view_mappings() == self.view_mappings() + cont.view_mappings(),
842    {
843        admit()
844    }
845
846    pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
847        if self.level == 1 {
848            let l1 = self.continuations[0];
849            let l2 = self.continuations[1].restore_spec(l1).0;
850            let l3 = self.continuations[2].restore_spec(l2).0;
851            let l4 = self.continuations[3].restore_spec(l3).0;
852            l4.as_page_table_owner()
853        } else if self.level == 2 {
854            let l2 = self.continuations[1];
855            let l3 = self.continuations[2].restore_spec(l2).0;
856            let l4 = self.continuations[3].restore_spec(l3).0;
857            l4.as_page_table_owner()
858        } else if self.level == 3 {
859            let l3 = self.continuations[2];
860            let l4 = self.continuations[3].restore_spec(l3).0;
861            l4.as_page_table_owner()
862        } else {
863            let l4 = self.continuations[3];
864            l4.as_page_table_owner()
865        }
866    }
867
868    pub proof fn as_page_table_owner_preserves_view_mappings(self)
869        requires
870            self.inv(),
871        ensures
872            self.as_page_table_owner().view_rec(self.continuations[3].path()) == self.view_mappings(),
873    {
874        admit()
875    }
876
877    pub open spec fn cur_entry_owner(self) -> EntryOwner<C> {
878        self.cur_subtree().value
879    }
880
881    pub open spec fn cur_subtree(self) -> OwnerSubtree<C> {
882        self.continuations[self.level - 1].children[self.index() as int].unwrap()
883    }
884
885    pub open spec fn locked_range(self) -> Range<Vaddr> {
886        let start = self.prefix.align_down(self.guard_level as int).to_vaddr();
887        let end = self.prefix.align_up(self.guard_level as int).to_vaddr();
888        Range { start, end }
889    }
890
891    pub open spec fn in_locked_range(self) -> bool {
892        self.locked_range().start <= self.va.to_vaddr() < self.locked_range().end
893    }
894
895    pub open spec fn above_locked_range(self) -> bool {
896        self.va.to_vaddr() >= self.locked_range().end
897    }
898
899    pub proof fn prefix_in_locked_range(self)
900        requires
901            forall|i:int| i >= self.guard_level ==> self.va.index[i] == self.prefix.index[i],
902        ensures
903            self.in_locked_range(),
904    { admit() }
905
906    /// When in_locked_range and !popped_too_high, level < guard_level (from inv), hence level < NR_LEVELS.
907    pub proof fn in_locked_range_level_lt_nr_levels(self)
908        requires
909            self.inv(),
910            self.in_locked_range(),
911            !self.popped_too_high,
912        ensures
913            self.level < NR_LEVELS,
914    {
915        assert(self.above_locked_range() ==> self.va.to_vaddr() >= self.locked_range().end);
916        assert(self.in_locked_range() ==> self.va.to_vaddr() < self.locked_range().end);
917        assert(self.in_locked_range() ==> !self.above_locked_range());
918        assert(!self.popped_too_high ==> self.level < self.guard_level || self.above_locked_range());
919        assert(self.level < self.guard_level);
920        assert(self.guard_level <= NR_LEVELS);
921    }
922
923    /// If in_locked_range() and level < guard_level, then:
924    /// - va.align_down(page_size(level+1)) >= locked_range().start
925    /// - va.align_down(page_size(level+1)) + page_size(level+1) <= locked_range().end
926    ///
927    /// This follows from the fact that locked_range().start is aligned to page_size(guard_level),
928    /// and page_size(guard_level) >= page_size(level+1) when guard_level > level.
929    /// Therefore locked_range().start is also aligned to page_size(level+1).
930    pub proof fn node_within_locked_range(self, level: PagingLevel)
931        requires
932            self.in_locked_range(),
933            1 <= level < self.guard_level,
934            self.va.inv(),
935        ensures
936            self.locked_range().start <= nat_align_down(self.va.to_vaddr() as nat, page_size((level + 1) as PagingLevel) as nat) as usize,
937            nat_align_down(self.va.to_vaddr() as nat, page_size((level + 1) as PagingLevel) as nat) as usize + page_size((level + 1) as PagingLevel) <= self.locked_range().end,
938    {
939        admit()
940    }
941
942    /// Proves that if the current entry is absent, then there is no mapping
943    /// at the current virtual address. This follows from the page table structure:
944    /// - cur_va falls within the VA range of cur_subtree()
945    /// - An absent entry contributes no mappings (view_rec returns empty set)
946    /// - Mappings from other subtrees have disjoint VA ranges
947    pub proof fn cur_entry_absent_not_present(self)
948        requires
949            self.inv(),
950            self.cur_entry_owner().is_absent(),
951        ensures
952            !self@.present(),
953    {
954        let cur_va = self.cur_va();
955        let cur_subtree = self.cur_subtree();
956        let cur_path = cur_subtree.value.path;
957
958        // cur_subtree.value is cur_entry_owner(), which is absent
959        // By view_rec_absent_empty, PageTableOwner(cur_subtree).view_rec(cur_path) is empty
960        PageTableOwner(cur_subtree).view_rec_absent_empty(cur_path);
961        assert(PageTableOwner(cur_subtree).view_rec(cur_path) =~= set![]);
962
963        // Prove that no mapping in view_mappings() covers cur_va
964        assert forall |m: Mapping| self.view_mappings().contains(m) implies
965            !(m.va_range.start <= cur_va < m.va_range.end) by {
966
967            if m.va_range.start <= cur_va < m.va_range.end {
968                self.mapping_covering_cur_va_from_cur_subtree(m);
969                assert(PageTableOwner(cur_subtree).view_rec(cur_path).contains(m));
970                assert(PageTableOwner(cur_subtree).view_rec(cur_path) =~= set![]);
971                assert(false);
972            }
973        };
974
975        // Now show that the filtered set is empty
976        let mappings = self@.mappings;
977        let filtered = mappings.filter(|m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end);
978
979        // Since no mapping covers cur_va, the filter produces an empty set
980        assert(filtered =~= set![]) by {
981            assert forall |m: Mapping| !filtered.contains(m) by {
982                if mappings.contains(m) && m.va_range.start <= self@.cur_va < m.va_range.end {
983                    assert(self.view_mappings().contains(m));
984                    assert(!(m.va_range.start <= cur_va < m.va_range.end));
985                }
986            };
987        };
988
989        // Empty set has length 0
990        assert(filtered.len() == 0);
991        assert(!self@.present());
992    }
993
994    pub proof fn cur_entry_frame_present(self)
995        requires
996            self.inv(),
997            self.cur_entry_owner().is_frame(),
998        ensures
999            self@.present(),
1000            self@.query(self.cur_entry_owner().frame.unwrap().mapped_pa,
1001                self.cur_entry_owner().frame.unwrap().size,
1002                self.cur_entry_owner().frame.unwrap().prop),
1003    {
1004        admit()
1005    }
1006
1007    pub open spec fn relate_region(self, regions: MetaRegionOwners) -> bool
1008    {
1009        &&& self.map_full_tree(|entry_owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1010            entry_owner.relate_region(regions))
1011        &&& self.map_full_tree(PageTableOwner::<C>::path_tracked_pred(regions))
1012    }
1013
1014    pub open spec fn not_in_tree(self, owner: EntryOwner<C>) -> bool {
1015        self.map_full_tree(|owner0: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1016            owner0.meta_slot_paddr_neq(owner))
1017    }
1018
1019    pub proof fn absent_not_in_tree(self, owner: EntryOwner<C>)
1020        requires
1021            self.inv(),
1022            owner.is_absent(),
1023        ensures
1024            self.not_in_tree(owner),
1025    {
1026        admit()
1027    }
1028
1029    pub proof fn relate_region_preserved(self, other: Self, regions0: MetaRegionOwners, regions1: MetaRegionOwners)
1030        requires
1031            self.inv(),
1032            self.relate_region(regions0),
1033            self.level == other.level,
1034            self.continuations =~= other.continuations,
1035            OwnerSubtree::implies(
1036                PageTableOwner::<C>::relate_region_pred(regions0),
1037                PageTableOwner::<C>::relate_region_pred(regions1)),
1038            OwnerSubtree::implies(
1039                PageTableOwner::<C>::path_tracked_pred(regions0),
1040                PageTableOwner::<C>::path_tracked_pred(regions1)),
1041        ensures
1042            other.relate_region(regions1),
1043    {
1044        let e = PageTableOwner::<C>::path_tracked_pred(regions0);
1045        let f = PageTableOwner::relate_region_pred(regions0);
1046        let g = PageTableOwner::relate_region_pred(regions1);
1047        let h = PageTableOwner::<C>::path_tracked_pred(regions1);
1048
1049        assert forall|i: int| #![auto] self.level - 1 <= i < NR_LEVELS implies {
1050            &&& other.continuations[i].map_children(g)
1051            &&& other.continuations[i].map_children(h)
1052        } by {
1053            let cont = self.continuations[i];
1054            assert(cont.inv());
1055            assert(cont.map_children(f));
1056            assert(cont.map_children(e));
1057            assert(cont == other.continuations[i]);
1058            assert forall |j: int| 0 <= j < NR_ENTRIES && #[trigger] cont.children[j] is Some implies
1059                cont.children[j].unwrap().tree_predicate_map(cont.path().push_tail(j as usize), g) by {
1060                    cont.children[j].unwrap().map_implies(cont.path().push_tail(j as usize), f, g);
1061            };
1062            assert forall |j: int| 0 <= j < NR_ENTRIES && #[trigger] cont.children[j] is Some implies
1063                cont.children[j].unwrap().tree_predicate_map(cont.path().push_tail(j as usize), h) by {
1064                    cont.children[j].unwrap().map_implies(cont.path().push_tail(j as usize), e, h);
1065            };
1066        };
1067    }
1068
1069    pub open spec fn set_va_spec(self, new_va: AbstractVaddr) -> Self {
1070        Self {
1071            va: new_va,
1072            ..self
1073        }
1074    }
1075
1076    pub axiom fn set_va(tracked &mut self, new_va: AbstractVaddr)
1077        requires
1078            forall |i: int| #![auto] old(self).level - 1 <= i < NR_LEVELS ==> new_va.index[i] == old(self).va.index[i],
1079            forall |i: int| #![auto] old(self).guard_level - 1 <= i < NR_LEVELS ==> new_va.index[i] == old(self).prefix.index[i],
1080        ensures
1081            *self == old(self).set_va_spec(new_va);
1082
1083}
1084
1085pub tracked struct CursorView<C: PageTableConfig> {
1086    pub cur_va: Vaddr,
1087    pub mappings: Set<Mapping>,
1088    pub phantom: PhantomData<C>,
1089}
1090
1091impl<'rcu, C: PageTableConfig> View for CursorOwner<'rcu, C> {
1092    type V = CursorView<C>;
1093
1094    open spec fn view(&self) -> Self::V {
1095        CursorView {
1096            cur_va: self.cur_va(),
1097            mappings: self.view_mappings(),
1098            phantom: PhantomData,
1099        }
1100    }
1101}
1102
1103impl<C: PageTableConfig> Inv for CursorView<C> {
1104    open spec fn inv(self) -> bool {
1105        &&& self.cur_va < MAX_USERSPACE_VADDR
1106        &&& forall|m: Mapping| #![auto] self.mappings.contains(m) ==> m.inv()
1107        &&& forall|m: Mapping, n: Mapping| #![auto]
1108            self.mappings.contains(m) ==>
1109            self.mappings.contains(n) ==>
1110            m != n ==>
1111            m.va_range.end <= n.va_range.start || n.va_range.end <= m.va_range.start
1112    }
1113}
1114
1115impl<'rcu, C: PageTableConfig> InvView for CursorOwner<'rcu, C> {
1116    proof fn view_preserves_inv(self) {
1117        assert(self@.inv()) by { admit() };
1118    }
1119}
1120
1121impl<'rcu, C: PageTableConfig, A: InAtomicMode> Inv for Cursor<'rcu, C, A> {
1122    open spec fn inv(self) -> bool {
1123        &&& 1 <= self.level <= NR_LEVELS
1124        &&& self.level <= self.guard_level <= NR_LEVELS
1125//        &&& forall|i: int| 0 <= i < self.guard_level - self.level ==> self.path[i] is Some
1126    }
1127}
1128
1129impl<'rcu, C: PageTableConfig, A: InAtomicMode> OwnerOf for Cursor<'rcu, C, A> {
1130    type Owner = CursorOwner<'rcu, C>;
1131
1132    open spec fn wf(self, owner: Self::Owner) -> bool {
1133        &&& owner.va.reflect(self.va)
1134        &&& self.level == owner.level
1135        &&& owner.guard_level == self.guard_level
1136//        &&& owner.index() == self.va % page_size(self.level)
1137        &&& self.level <= 4 ==> {
1138            &&& self.path[3] is Some
1139            &&& owner.continuations.contains_key(3)
1140            &&& owner.continuations[3].guard_perm.pptr() == self.path[3].unwrap()
1141        }
1142        &&& self.level <= 3 ==> {
1143            &&& self.path[2] is Some
1144            &&& owner.continuations.contains_key(2)
1145            &&& owner.continuations[2].guard_perm.pptr() == self.path[2].unwrap()
1146        }
1147        &&& self.level <= 2 ==> {
1148            &&& self.path[1] is Some
1149            &&& owner.continuations.contains_key(1)
1150            &&& owner.continuations[1].guard_perm.pptr() == self.path[1].unwrap()
1151        }
1152        &&& self.level == 1 ==> {
1153            &&& self.path[0] is Some
1154            &&& owner.continuations.contains_key(0)
1155            &&& owner.continuations[0].guard_perm.pptr() == self.path[0].unwrap()
1156        }
1157        &&& self.barrier_va.start == owner.locked_range().start
1158        &&& self.barrier_va.end == owner.locked_range().end
1159    }
1160}
1161
1162impl<'rcu, C: PageTableConfig, A: InAtomicMode> ModelOf for Cursor<'rcu, C, A> {
1163
1164}
1165
1166} // verus!