1use vstd::{
2 arithmetic::{
3 div_mod::{lemma_div_non_zero, lemma_fundamental_div_mod},
4 mul::lemma_mul_is_commutative,
5 power2::pow2,
6 },
7 bits::lemma_usize_shr_is_div,
8 prelude::*,
9 seq_lib::*,
10 set::lemma_set_contains_len,
11};
12use vstd_extra::{
13 drop_tracking::*,
14 ghost_tree::*,
15 ownership::*,
16 panic::may_panic,
17 prelude::*,
18 seq_extra::{forall_seq, lemma_forall_seq_index},
19};
20
21use crate::specs::{
22 arch::*,
23 mm::{
24 frame::{
25 mapping::{frame_to_index, index_to_meta},
26 meta_owners::MetaSlotStorage,
27 meta_region_owners::MetaRegionOwners,
28 },
29 page_table::{
30 Guards, Mapping, lemma_aligned_vaddr_slack, lemma_inc_slot_indices,
31 lemma_lower_indices_aligned, lemma_page_size_base, lemma_page_size_divides,
32 lemma_page_size_ge_base, lemma_page_size_is_pow2_pte_index_bit_offset,
33 lemma_page_size_next, lemma_pte_index_bound, lemma_vaddr_range_spec_kernel,
34 lemma_vaddr_range_spec_user, lemma_vaddr_upper_part_is_align_down, owners::*,
35 page_table_vaddr_bits_spec, pte_index_bit_offset_spec, pte_index_spec,
36 vaddr_range_spec, vaddr_replace_pte_index_spec, vaddr_upper_bits_spec,
37 vaddr_upper_part_spec,
38 },
39 },
40 task::InAtomicMode,
41};
42
43use crate::arch::mm::PagingConsts;
44use crate::mm::{
45 MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr,
46 frame::{
47 Frame,
48 meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
49 },
50 kspace::KernelPtConfig,
51 nr_subpage_per_huge,
52 page_prop::PageProperty,
53 page_size,
54 page_table::*,
55};
56use core::{marker::PhantomData, ops::Range};
57
58verus! {
59
60broadcast use group_ghost_tree_lemmas;
61
62pub tracked struct CursorContinuation<'rcu, C: PageTableConfig> {
63 pub entry_own: EntryOwner<C>,
64 pub ghost idx: usize,
65 pub ghost tree_level: nat,
66 pub children: Seq<Option<OwnerSubtree<C>>>,
67 pub ghost path: TreePath<NR_ENTRIES>,
68 pub ghost guard: PageTableGuard<'rcu, C>,
69}
70
71impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
72 pub open spec fn path(self) -> TreePath<NR_ENTRIES> {
73 self.entry_own.path
74 }
75
76 pub open spec fn child(self) -> OwnerSubtree<C> {
77 self.children[self.idx as int]->0
78 }
79
80 pub open spec fn take_child(self) -> (OwnerSubtree<C>, Self) {
81 let child = self.children[self.idx as int]->0;
82 let cont = Self {
83 children: self.children.remove(self.idx as int).insert(self.idx as int, None),
84 ..self
85 };
86 (child, cont)
87 }
88
89 pub proof fn tracked_take_child(tracked &mut self) -> (tracked res: OwnerSubtree<C>)
90 requires
91 old(self).inv(),
92 old(self).idx < old(self).children.len(),
93 old(self).children[old(self).idx as int] is Some,
94 ensures
95 res == old(self).take_child().0,
96 *final(self) == old(self).take_child().1,
97 res.inv(),
98 {
99 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
100 self.children.tracked_insert(old(self).idx as int, None);
101 child
102 }
103
104 pub open spec fn put_child(self, child: OwnerSubtree<C>) -> Self {
105 Self {
106 children: self.children.remove(self.idx as int).insert(self.idx as int, Some(child)),
107 ..self
108 }
109 }
110
111 pub proof fn tracked_put_child(tracked &mut self, tracked child: OwnerSubtree<C>)
112 requires
113 old(self).idx < old(self).children.len(),
114 old(self).children[old(self).idx as int] is None,
115 ensures
116 *final(self) == old(self).put_child(child),
117 {
118 let _ = self.children.tracked_remove(old(self).idx as int);
119 self.children.tracked_insert(old(self).idx as int, Some(child));
120 }
121
122 pub proof fn take_put_child(self)
123 requires
124 self.idx < self.children.len(),
125 self.children[self.idx as int] is Some,
126 ensures
127 self.take_child().1.put_child(self.take_child().0) == self,
128 {
129 let child = self.take_child().0;
130 let cont = self.take_child().1;
131 assert(cont.put_child(child).children == self.children);
132 }
133
134 pub proof fn take_child_preserves_inv(self)
136 requires
137 self.inv(),
138 self.idx < self.children.len(),
139 self.children[self.idx as int] is Some,
140 ensures
141 self.take_child().1.inv(),
142 {
143 }
144
145 pub open spec fn make_cont(self, idx: usize, guard: PageTableGuard<'rcu, C>) -> (Self, Self) {
146 let child = Self {
147 entry_own: self.children[self.idx as int]->0.value(),
148 tree_level: (self.tree_level + 1) as nat,
149 idx: idx,
150 children: self.children[self.idx as int]->0.children(),
151 path: self.path.push_tail(self.idx as int),
152 guard: guard,
153 };
154 let cont = Self { children: self.children.update(self.idx as int, None), ..self };
155 (child, cont)
156 }
157
158 pub proof fn tracked_make_cont(
159 tracked &mut self,
160 idx: usize,
161 guard: PageTableGuard<'rcu, C>,
162 ) -> (tracked res: Self)
163 requires
164 old(self).all_some(),
165 old(self).children.len() == NR_ENTRIES,
166 old(self).idx < NR_ENTRIES,
167 idx < NR_ENTRIES,
168 ensures
169 res == old(self).make_cont(idx, guard).0,
170 *final(self) == old(self).make_cont(idx, guard).1,
171 {
172 lemma_update_is_remove_insert(self.children, old(self).idx as int, None);
173 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
174 self.children.tracked_insert(old(self).idx as int, None);
175 let tracked (entry_own, children) = child.tracked_into_parts();
176 Self {
177 entry_own,
178 tree_level: (old(self).tree_level + 1) as nat,
179 idx,
180 children,
181 path: old(self).path.push_tail(old(self).idx as int),
182 guard,
183 }
184 }
185
186 pub open spec fn restore(self, child: Self) -> (Self, PageTableGuard<'rcu, C>) {
187 let child_node = OwnerSubtree::new(child.entry_own, child.tree_level, child.children);
188 (
189 Self { children: self.children.update(self.idx as int, Some(child_node)), ..self },
190 child.guard,
191 )
192 }
193
194 pub proof fn tracked_restore(tracked &mut self, tracked child: Self) -> (guard: PageTableGuard<
195 'rcu,
196 C,
197 >)
198 requires
199 old(self).idx < old(self).children.len(),
200 ensures
201 *final(self) == old(self).restore(child).0,
202 guard == old(self).restore(child).1,
203 {
204 let tracked child_node = OwnerSubtree::tracked_new(
205 child.entry_own,
206 child.tree_level,
207 child.children,
208 );
209 lemma_update_is_remove_insert(self.children, self.idx as int, Some(child_node));
210 let _ = self.children.tracked_remove(self.idx as int);
211 self.children.tracked_insert(self.idx as int, Some(child_node));
212 child.guard
213 }
214
215 pub open spec fn new(
216 owner_subtree: OwnerSubtree<C>,
217 idx: usize,
218 guard: PageTableGuard<'rcu, C>,
219 ) -> Self {
220 Self {
221 entry_own: owner_subtree.value(),
222 idx: idx,
223 tree_level: owner_subtree.level(),
224 children: owner_subtree.children(),
225 path: TreePath::new(Seq::empty()),
226 guard: guard,
227 }
228 }
229
230 pub proof fn tracked_new(
231 tracked owner_subtree: OwnerSubtree<C>,
232 idx: usize,
233 guard: PageTableGuard<'rcu, C>,
234 ) -> tracked Self
235 returns
236 Self::new(owner_subtree, idx, guard),
237 {
238 let ghost tree_level = owner_subtree.level();
239 let tracked (entry_own, children) = owner_subtree.tracked_into_parts();
240 Self { entry_own, idx, tree_level, children, path: TreePath::new(Seq::empty()), guard }
241 }
242
243 #[verifier::opaque]
245 pub open spec fn map_children(
246 self,
247 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
248 ) -> bool {
249 forall|i: int|
250 #![trigger(self.children[i])]
251 0 <= i < self.children.len() ==> self.children[i] is Some
252 ==> self.children[i]->0.subtree_satisfies(self.path().push_tail(i), f)
253 }
254
255 pub proof fn lemma_map_children_unroll(
257 self,
258 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
259 i: int,
260 )
261 requires
262 self.map_children(f),
263 0 <= i < self.children.len(),
264 self.children[i] is Some,
265 ensures
266 self.children[i]->0.subtree_satisfies(self.path().push_tail(i), f),
267 {
268 reveal(CursorContinuation::map_children);
269 }
270
271 pub open spec fn level(self) -> PagingLevel {
274 self.entry_own.node().level()
275 }
276
277 pub open spec fn inv_children(self) -> bool {
278 self.children.all(|child: Option<OwnerSubtree<C>>| child is Some ==> child->0.inv())
279 }
280
281 pub proof fn lemma_inv_children_unroll(self, i: int)
282 requires
283 self.inv_children(),
284 0 <= i < self.children.len(),
285 self.children[i] is Some,
286 ensures
287 self.children[i]->0.inv(),
288 {
289 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
290 assert(pred(self.children[i]));
291 }
292
293 pub proof fn lemma_inv_children_unroll_all(self)
294 requires
295 self.inv_children(),
296 ensures
297 forall|i: int|
298 #![auto]
299 0 <= i < self.children.len() ==> self.children[i] is Some
300 ==> self.children[i]->0.inv(),
301 {
302 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
303 assert forall|i: int|
304 0 <= i < self.children.len()
305 && #[trigger] self.children[i] is Some implies self.children[i].unwrap().inv() by {
306 self.lemma_inv_children_unroll(i)
307 }
308 }
309
310 pub open spec fn inv_children_rel_pred(self) -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
311 |i: int, child: Option<OwnerSubtree<C>>|
312 {
313 child is Some ==> {
314 &&& child->0.value().parent_level == self.level()
315 &&& child->0.level() == self.tree_level + 1
316 &&& child->0.value().path.len() == self.entry_own.node().tree_level + 1
317 &&& child->0.value().match_pte(
318 self.entry_own.node().children_perm.value()[i],
319 self.entry_own.node().level(),
320 )
321 &&& child->0.value().path == self.path().push_tail(i)
322 }
323 }
324 }
325
326 pub open spec fn inv_children_rel(self) -> bool {
327 forall_seq(self.children, self.inv_children_rel_pred())
328 }
329
330 pub open spec fn pt_inv_children_pred() -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
331 |i: int, child: Option<OwnerSubtree<C>>| child is Some ==> PageTableOwner(child->0).pt_inv()
332 }
333
334 pub open spec fn pt_inv_children(self) -> bool {
335 forall_seq(self.children, Self::pt_inv_children_pred())
336 }
337
338 pub proof fn lemma_pt_inv_children_unroll(self, i: int)
339 requires
340 self.pt_inv_children(),
341 0 <= i < self.children.len(),
342 self.children[i] is Some,
343 ensures
344 PageTableOwner(self.children[i]->0).pt_inv(),
345 {
346 }
347
348 pub proof fn lemma_inv_children_rel_unroll(self, i: int)
349 requires
350 self.inv_children_rel(),
351 0 <= i < self.children.len(),
352 self.children[i] is Some,
353 ensures
354 self.children[i]->0.value().parent_level == self.level(),
355 self.children[i]->0.level() == self.tree_level + 1,
356 self.children[i]->0.value().path.len() == self.entry_own.node().tree_level + 1,
357 self.children[i]->0.value().match_pte(
358 self.entry_own.node().children_perm.value()[i],
359 self.entry_own.node().level(),
360 ),
361 self.children[i]->0.value().path == self.path().push_tail(i),
362 {
363 }
364
365 pub open spec fn inv(self) -> bool {
366 &&& self.children.len() == NR_ENTRIES
367 &&& 0 <= self.idx < NR_ENTRIES
368 &&& self.inv_children()
369 &&& self.inv_children_rel()
370 &&& self.pt_inv_children()
371 &&& self.entry_own.is_node()
372 &&& self.entry_own.inv()
373 &&& self.entry_own.node().relate_guard(self.guard)
374 &&& self.tree_level == INC_LEVELS - self.level() - 1
375 &&& self.tree_level < INC_LEVELS - 1
376 &&& self.path().len() == self.tree_level
377 }
378
379 pub open spec fn all_some(self) -> bool {
380 forall|i: int| 0 <= i < NR_ENTRIES ==> self.children[i] is Some
381 }
382
383 pub open spec fn all_but_index_some(self) -> bool {
384 &&& forall|i: int| 0 <= i < self.idx ==> self.children[i] is Some
385 &&& forall|i: int| self.idx < i < NR_ENTRIES ==> self.children[i] is Some
386 &&& self.children[self.idx as int] is None
387 }
388
389 pub open spec fn inc_index(self) -> Self {
390 Self { idx: (self.idx + 1) as usize, ..self }
391 }
392
393 pub proof fn do_inc_index(tracked &mut self)
394 requires
395 old(self).idx + 1 < NR_ENTRIES,
396 ensures
397 *final(self) == old(self).inc_index(),
398 {
399 self.idx = (self.idx + 1) as usize;
400 }
401
402 pub open spec fn node_locked(self, guards: Guards) -> bool {
403 guards.lock_held(self.guard.inner.inner@.ptr.addr())
404 }
405
406 pub open spec fn view_mappings(self) -> Set<Mapping> {
407 self.children.map(
408 |i, child: Option<OwnerSubtree<C>>|
409 if child is Some {
410 PageTableOwner(child->0).view_rec(self.path().push_tail(i))
411 } else {
412 Set::empty()
413 },
414 ).to_set().flatten()
415 }
416
417 pub broadcast proof fn lemma_view_mappings_contains(self)
418 ensures
419 #![trigger self.view_mappings()]
420 forall|m: Mapping| #[trigger]
421 self.view_mappings().contains(m) ==> exists|i: int|
422 #![trigger self.children[i]]
423 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
424 self.children[i]->0,
425 ).view_rec(self.path().push_tail(i)).contains(m),
426 {
427 broadcast use vstd::seq_lib::group_seq_properties;
428
429 }
430
431 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
432 requires
433 0 <= i < self.children.len(),
434 self.children[i] is Some,
435 #[trigger] PageTableOwner(self.children[i]->0).view_rec(
436 self.path().push_tail(i),
437 ).contains(m),
438 ensures
439 self.view_mappings().contains(m),
440 {
441 broadcast use vstd::seq_lib::group_seq_properties;
442
443 let mapped = self.children.map(
444 |i, child: Option<OwnerSubtree<C>>|
445 if child is Some {
446 PageTableOwner(child->0).view_rec(self.path().push_tail(i))
447 } else {
448 Set::empty()
449 },
450 );
451 assert(mapped.to_set().contains(mapped[i]));
452 }
453
454 pub open spec fn as_subtree(self) -> OwnerSubtree<C> {
455 OwnerSubtree::new(self.entry_own, self.tree_level, self.children)
456 }
457
458 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
459 PageTableOwner(self.as_subtree())
460 }
461
462 pub open spec fn view_mappings_take_child_spec(self) -> Set<Mapping> {
463 PageTableOwner(self.children[self.idx as int]->0).view_rec(
464 self.path().push_tail(self.idx as int),
465 )
466 }
467
468 pub proof fn lemma_rel_children_from_node_matching(
480 entry: &Entry<'_, 'rcu, C>,
481 child_value: EntryOwner<C>,
482 parent_owner: NodeOwner<C>,
483 guard: PageTableGuard<'rcu, C>,
484 entry_own: EntryOwner<C>,
485 idx: usize,
486 )
487 requires
488 entry.node_matching(child_value, parent_owner, guard),
489 entry.idx == idx,
490 entry_own.is_node(),
491 entry_own.node() == parent_owner,
492 child_value.path == entry_own.path.push_tail(idx as int),
493 child_value.path.len() == parent_owner.tree_level + 1,
494 ensures
495 child_value.path.len() == parent_owner.tree_level + 1,
496 child_value.match_pte(
497 parent_owner.children_perm.value()[idx as int],
498 parent_owner.level(),
499 ),
500 child_value.path == entry_own.path.push_tail(idx as int),
501 child_value.parent_level == parent_owner.level(),
502 {
503 }
504
505 pub proof fn lemma_continuation_inv_holds_after_child_restore(
515 self,
516 cont_old: Self,
517 parent_old: NodeOwner<C>,
518 )
519 requires
520 cont_old.inv(),
523 cont_old.entry_own.is_node(),
524 cont_old.entry_own.node() == parent_old,
525 self.children.len() == cont_old.children.len(),
527 self.idx == cont_old.idx,
528 self.tree_level == cont_old.tree_level,
529 self.guard == cont_old.guard,
530 self.path == cont_old.path,
531 self.entry_own.is_absent() == cont_old.entry_own.is_absent(),
534 self.entry_own.path == cont_old.entry_own.path,
535 self.entry_own.parent_level == cont_old.entry_own.parent_level,
536 self.entry_own.is_node(),
538 self.entry_own.inv(),
539 self.entry_own.node().relate_guard(self.guard),
540 self.entry_own.node().level() == parent_old.level(),
541 self.entry_own.node().tree_level == parent_old.tree_level,
542 forall|j: int|
544 0 <= j < NR_ENTRIES && j != self.idx
545 ==> #[trigger] self.entry_own.node().children_perm.value()[j]
546 == parent_old.children_perm.value()[j],
547 forall|j: int|
549 0 <= j < NR_ENTRIES && j != self.idx ==> #[trigger] self.children[j]
550 == cont_old.children[j],
551 self.children.len() == NR_ENTRIES,
554 0 <= self.idx < NR_ENTRIES,
555 self.tree_level == INC_LEVELS - self.level() - 1,
556 self.tree_level < INC_LEVELS - 1,
557 self.path().len() == self.tree_level,
558 self.children[self.idx as int] is Some,
560 self.children[self.idx as int]->0.inv(),
561 self.children[self.idx as int]->0.value().parent_level == self.level(),
562 self.children[self.idx as int]->0.value().path == self.path().push_tail(
563 self.idx as int,
564 ),
565 self.children[self.idx as int]->0.level() == self.tree_level + 1,
566 self.children[self.idx as int]->0.value().path.len() == self.entry_own.node().tree_level
567 + 1,
568 self.children[self.idx as int]->0.value().match_pte(
569 self.entry_own.node().children_perm.value()[self.idx as int],
570 self.entry_own.node().level(),
571 ),
572 PageTableOwner(self.children[self.idx as int]->0).pt_inv(),
577 ensures
578 self.inv(),
579 {
580 }
581
582 pub proof fn tracked_new_child(
583 tracked &self,
584 paddr: Paddr,
585 prop: PageProperty,
586 tracked permission: Option<C::Perm>,
587 tracked regions: &mut MetaRegionOwners,
588 ) -> (tracked res: OwnerSubtree<C>)
589 requires
590 self.inv(),
591 self.level() < NR_LEVELS,
592 old(regions).slots.contains_key(frame_to_index(paddr)),
593 valid_frame_paddr(paddr),
594 paddr % page_size::<PagingConsts>(self.level()) == 0,
595 paddr + page_size::<PagingConsts>(self.level()) <= MAX_PADDR,
596 C::raw_item_well_formed((paddr, self.level(), prop, Tracked(permission))),
597 C::E::new_page_req(paddr, self.level(), prop),
598 self.path().push_tail(self.idx as int).inv(),
599 ensures
600 final(regions).slot_owners == old(regions).slot_owners,
601 final(regions).slots == old(regions).slots,
602 res.value() == EntryOwner::<C>::new_frame(
604 paddr,
605 self.path().push_tail(self.idx as int),
606 self.level(),
607 prop,
608 permission,
609 ),
610 res.inv(),
611 res.level() == self.tree_level + 1,
612 res == OwnerSubtree::new_val(res.value(), res.level() as nat),
613 {
614 let tracked mut owner = EntryOwner::<C>::tracked_new_frame(
615 paddr,
616 self.path().push_tail(self.idx as int),
617 self.level(),
618 prop,
619 permission,
620 );
621 OwnerSubtree::tracked_new_val(owner, self.tree_level + 1)
622 }
623
624 pub broadcast group group_lemmas {
625 CursorContinuation::lemma_view_mappings_contains,
626 CursorContinuation::lemma_view_mappings_intro,
627 }
628}
629
630pub tracked struct CursorOwner<'rcu, C: PageTableConfig> {
631 pub ghost level: PagingLevel,
632 pub continuations: Map<int, CursorContinuation<'rcu, C>>,
633 pub ghost va: Vaddr,
634 pub ghost guard_level: PagingLevel,
635 pub ghost prefix: Vaddr,
636 pub ghost popped_too_high: bool,
637}
638
639impl<'rcu, C: PageTableConfig> Inv for CursorOwner<'rcu, C> {
640 open spec fn inv(self) -> bool {
641 &&& self.va % C::BASE_PAGE_SIZE() == 0
642 &&& 1 <= self.level <= NR_LEVELS
643 &&& 1 <= self.guard_level
644 <= NR_LEVELS
645 &&& C::TOP_LEVEL_INDEX_RANGE().start <= pte_index_spec::<C>(
649 self.va,
650 (NR_LEVELS - 1 + 1) as PagingLevel,
651 )
652 &&& pte_index_spec::<C>(self.va, (NR_LEVELS - 1 + 1) as PagingLevel)
656 <= C::TOP_LEVEL_INDEX_RANGE().end
657 &&& self.in_locked_range()
659 || self.above_locked_range()
660 &&& self.popped_too_high ==> self.level >= self.guard_level
663 &&& !self.popped_too_high ==> self.level <= self.guard_level || self.above_locked_range()
664 &&& self.continuations[self.level - 1].all_some()
665 &&& forall|i: int|
666 self.level <= i < NR_LEVELS ==> {
667 (#[trigger] self.continuations[i]).all_but_index_some()
668 }
669 &&& self.level <= NR_LEVELS - 1 ==> {
678 &&& C::TOP_LEVEL_INDEX_RANGE().start <= self.continuations[NR_LEVELS - 1].idx
679 &&& self.continuations[NR_LEVELS - 1].idx < C::TOP_LEVEL_INDEX_RANGE().end
680 }
681 &&& forall|j: int|
682 #![trigger self.continuations[NR_LEVELS - 1].children[j]]
683 0 <= j < NR_ENTRIES && !(C::TOP_LEVEL_INDEX_RANGE().start <= j
684 < C::TOP_LEVEL_INDEX_RANGE().end) ==> self.continuations[NR_LEVELS
685 - 1].children[j] is Some ==> (self.continuations[NR_LEVELS
686 - 1].children[j].unwrap().value().is_borrowed() || self.continuations[NR_LEVELS
687 - 1].children[j].unwrap().value().is_absent())
688 &&& self.prefix % C::BASE_PAGE_SIZE() == 0
689 &&& forall|i: int|
690 1 <= i <= self.guard_level ==> #[trigger] pte_index_spec::<C>(
691 self.prefix,
692 i as PagingLevel,
693 )
694 == 0
695 &&& pte_index_spec::<C>(self.prefix, (NR_LEVELS - 1 + 1) as PagingLevel)
699 >= C::TOP_LEVEL_INDEX_RANGE().start
700 &&& pte_index_spec::<C>(self.prefix, (NR_LEVELS - 1 + 1) as PagingLevel)
701 < C::TOP_LEVEL_INDEX_RANGE().end
702 &&& pte_index_spec::<C>(self.prefix, (NR_LEVELS - 1 + 1) as PagingLevel) + 1
705 < NR_ENTRIES
706 &&& self.locked_range().end <= vaddr_range_spec::<C>().end
710 + 1
711 &&& self.locked_range().end
716 <= C::LOCKED_END_BOUND_spec()
717 &&& vaddr_upper_bits_spec::<C>(self.va) == vaddr_upper_bits_spec::<C>(
720 self.prefix,
721 )
722 &&& vaddr_upper_bits_spec::<C>(self.prefix) == C::LEADING_BITS_spec()
725 &&& self.level <= self.guard_level ==> forall|i: int|
726 #![trigger self.continuations[i].idx]
727 self.guard_level <= i < NR_LEVELS ==> self.continuations[i].idx == pte_index_spec::<C>(
728 self.prefix,
729 (i + 1) as PagingLevel,
730 )
731 &&& !self.popped_too_high && (self.in_locked_range() || self.level < self.guard_level)
739 ==> forall|i: int|
740 self.guard_level <= i < NR_LEVELS ==> #[trigger] pte_index_spec::<C>(
741 self.va,
742 (i + 1) as PagingLevel,
743 ) == pte_index_spec::<C>(self.prefix, (i + 1) as PagingLevel)
744 &&& !self.popped_too_high && self.guard_level >= 1 && self.level < self.guard_level
745 ==> pte_index_spec::<C>(self.va, (self.guard_level - 1 + 1) as PagingLevel)
746 == pte_index_spec::<C>(self.prefix, (self.guard_level - 1 + 1) as PagingLevel)
747 &&& self.level <= 4 ==> {
748 &&& self.continuations.contains_key(3)
749 &&& self.continuations[3].inv()
750 &&& self.continuations[3].level()
751 == 4
752 &&& self.continuations[3].entry_own.parent_level
754 == 5
755 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (3 + 1) as PagingLevel)
760 == self.continuations[3].idx
761 }
762 &&& self.level <= 3 ==> {
763 &&& self.continuations.contains_key(2)
764 &&& self.continuations[2].inv()
765 &&& self.continuations[2].level() == 3
766 &&& self.continuations[2].entry_own.parent_level == 4
767 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (2 + 1) as PagingLevel)
768 == self.continuations[2].idx
769 &&& self.continuations[2].guard.inner.inner@.ptr.addr()
770 != self.continuations[3].guard.inner.inner@.ptr.addr()
771 &&& self.continuations[2].path() == self.continuations[3].path().push_tail(
773 self.continuations[3].idx as int,
774 )
775 &&& self.continuations[2].entry_own.path.len()
777 == self.continuations[3].entry_own.node().tree_level + 1
778 &&& self.continuations[2].entry_own.match_pte(
779 self.continuations[3].entry_own.node().children_perm.value()[self.continuations[3].idx as int],
780 self.continuations[3].entry_own.node().level(),
781 )
782 &&& self.continuations[2].entry_own.parent_level
783 == self.continuations[3].entry_own.node().level()
784 }
785 &&& self.level <= 2 ==> {
786 &&& self.continuations.contains_key(1)
787 &&& self.continuations[1].inv()
788 &&& self.continuations[1].level() == 2
789 &&& self.continuations[1].entry_own.parent_level == 3
790 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (1 + 1) as PagingLevel)
791 == self.continuations[1].idx
792 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
793 != self.continuations[2].guard.inner.inner@.ptr.addr()
794 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
795 != self.continuations[3].guard.inner.inner@.ptr.addr()
796 &&& self.continuations[1].path() == self.continuations[2].path().push_tail(
798 self.continuations[2].idx as int,
799 )
800 &&& self.continuations[1].entry_own.path.len()
802 == self.continuations[2].entry_own.node().tree_level + 1
803 &&& self.continuations[1].entry_own.match_pte(
804 self.continuations[2].entry_own.node().children_perm.value()[self.continuations[2].idx as int],
805 self.continuations[2].entry_own.node().level(),
806 )
807 &&& self.continuations[1].entry_own.parent_level
808 == self.continuations[2].entry_own.node().level()
809 }
810 &&& self.level == 1 ==> {
811 &&& self.continuations.contains_key(0)
812 &&& self.continuations[0].inv()
813 &&& self.continuations[0].level() == 1
814 &&& self.continuations[0].entry_own.parent_level == 2
815 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (0 + 1) as PagingLevel)
816 == self.continuations[0].idx
817 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
818 != self.continuations[1].guard.inner.inner@.ptr.addr()
819 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
820 != self.continuations[2].guard.inner.inner@.ptr.addr()
821 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
822 != self.continuations[3].guard.inner.inner@.ptr.addr()
823 &&& self.continuations[0].path() == self.continuations[1].path().push_tail(
825 self.continuations[1].idx as int,
826 )
827 &&& self.continuations[0].entry_own.path.len()
829 == self.continuations[1].entry_own.node().tree_level + 1
830 &&& self.continuations[0].entry_own.match_pte(
831 self.continuations[1].entry_own.node().children_perm.value()[self.continuations[1].idx as int],
832 self.continuations[1].entry_own.node().level(),
833 )
834 &&& self.continuations[0].entry_own.parent_level
835 == self.continuations[1].entry_own.node().level()
836 }
837 }
838}
839
840impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
841 pub open spec fn node_unlocked(guards: Guards) -> (spec_fn(
842 EntryOwner<C>,
843 TreePath<NR_ENTRIES>,
844 ) -> bool) {
845 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
846 owner.is_node() ==> guards.unlocked(owner.node().slot_vaddr())
847 }
848
849 pub open spec fn node_unlocked_except(guards: Guards, addr: usize) -> (spec_fn(
850 EntryOwner<C>,
851 TreePath<NR_ENTRIES>,
852 ) -> bool) {
853 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
854 owner.is_node() ==> owner.node().slot_vaddr() != addr ==> guards.unlocked(
855 owner.node().slot_vaddr(),
856 )
857 }
858
859 pub open spec fn map_full_tree(
860 self,
861 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
862 ) -> bool {
863 forall|i: int|
864 #![trigger self.continuations[i]]
865 self.level - 1 <= i < NR_LEVELS ==> { self.continuations[i].map_children(f) }
866 }
867
868 pub open spec fn map_only_children(
869 self,
870 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
871 ) -> bool {
872 forall|i: int|
873 #![trigger self.continuations[i]]
874 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(f)
875 }
876
877 pub open spec fn children_not_locked(self, guards: Guards) -> bool {
878 self.map_only_children(Self::node_unlocked(guards))
879 }
880
881 pub proof fn lemma_children_not_locked_unroll(self, guards: Guards)
882 requires
883 self.children_not_locked(guards),
884 ensures
885 forall|i: int|
886 #![trigger self.continuations[i]]
887 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(
888 Self::node_unlocked(guards),
889 ),
890 {
891 }
892
893 pub open spec fn only_current_locked(self, guards: Guards) -> bool {
894 self.map_only_children(
895 Self::node_unlocked_except(guards, self.cur_entry_owner().node().slot_vaddr()),
896 )
897 }
898
899 pub proof fn lemma_never_drop_restores_children_not_locked(
900 self,
901 guard: PageTableGuard<'rcu, C>,
902 guards0: Guards,
903 guards1: Guards,
904 )
905 requires
906 self.inv(),
907 self.only_current_locked(guards0),
908 guards0.lock_held(guard.inner.inner@.ptr.addr()),
909 guards1.guards == guards0.guards.remove(guard.inner.inner@.ptr.addr()),
910 self.cur_entry_owner().is_node(),
912 guard.inner.inner@.ptr.addr() == self.cur_entry_owner().node().slot_vaddr(),
913 ensures
914 self.children_not_locked(guards1),
915 {
916 let current_addr = self.cur_entry_owner().node().slot_vaddr();
917 let f = Self::node_unlocked_except(guards0, current_addr);
918 let g = Self::node_unlocked(guards1);
919
920 self.map_children_implies(f, g);
921 }
922
923 pub open spec fn nodes_locked(self, guards: Guards) -> bool {
937 forall|i: int|
943 #![trigger self.continuations[i]]
944 self.level - 1 <= i < self.guard_level ==> { self.continuations[i].node_locked(guards) }
945 }
946
947 pub open spec fn index(self) -> usize {
948 self.continuations[self.level - 1].idx
949 }
950
951 pub open spec fn inc_index(self) -> Self {
952 Self {
953 continuations: self.continuations.insert(
954 self.level - 1,
955 self.continuations[self.level - 1].inc_index(),
956 ),
957 va: vaddr_replace_pte_index_spec::<C>(
958 self.va,
959 self.level,
960 self.continuations[self.level - 1].inc_index().idx as int,
961 ),
962 popped_too_high: false,
963 ..self
964 }
965 }
966
967 #[verifier::spinoff_prover]
968 pub proof fn do_inc_index(tracked &mut self)
969 requires
970 old(self).inv(),
971 old(self).level <= old(self).guard_level,
972 old(self).in_locked_range(),
973 old(self).continuations[old(self).level - 1].idx + 1 < NR_ENTRIES,
974 old(self).level == NR_LEVELS ==> (old(self).continuations[old(self).level - 1].idx + 1)
975 <= C::TOP_LEVEL_INDEX_RANGE().end,
976 ensures
977 final(self).inv(),
978 *final(self) == old(self).inc_index(),
979 {
980 C::lemma_paging_consts_properties();
981 lemma_inc_slot_indices::<C>(old(self).va, old(self).level);
982 old(self).lemma_inc_index_va();
983 self.popped_too_high = false;
984 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
985 cont.do_inc_index();
986 self.va = old(self).inc_index().va;
987 self.continuations.tracked_insert(self.level - 1, cont);
988 assert(self.continuations == old(self).continuations.insert(self.level - 1, cont));
989
990 }
991
992 pub proof fn lemma_inv_continuation(self, i: int)
993 requires
994 self.inv(),
995 self.level - 1 <= i <= NR_LEVELS - 1,
996 ensures
997 self.continuations.contains_key(i),
998 self.continuations[i].inv(),
999 self.continuations[i].children.len() == NR_ENTRIES,
1000 {
1001 }
1002
1003 pub open spec fn view_mappings(self) -> Set<Mapping> {
1004 self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS).map_values(
1005 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
1006 ).values().flatten()
1007 }
1008
1009 pub broadcast proof fn lemma_view_mappings_contains(self)
1010 requires
1011 1 <= self.level <= NR_LEVELS,
1012 ensures
1013 #![trigger self.view_mappings()]
1014 forall|m: Mapping| #[trigger]
1015 self.view_mappings().contains(m) ==> exists|i: int|
1016 #![trigger self.continuations[i]]
1017 self.level - 1 <= i < NR_LEVELS
1018 && self.continuations[i].view_mappings().contains(m),
1019 {
1020 broadcast use vstd::map_lib::group_map_properties;
1021
1022 }
1023
1024 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
1025 requires
1026 1 <= self.level <= NR_LEVELS,
1027 self.level - 1 <= i < NR_LEVELS,
1028 self.continuations.contains_key(i),
1029 #[trigger] self.continuations[i].view_mappings().contains(m),
1030 ensures
1031 self.view_mappings().contains(m),
1032 {
1033 broadcast use vstd::map_lib::group_map_properties;
1034
1035 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
1036 let mapped = filtered.map_values(|cont: CursorContinuation<'rcu, C>| cont.view_mappings());
1037 let values = mapped.values();
1038 assert(values.contains(mapped[i]));
1039 }
1040
1041 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
1042 if self.level == 1 {
1043 let l1 = self.continuations[0];
1044 let l2 = self.continuations[1].restore(l1).0;
1045 let l3 = self.continuations[2].restore(l2).0;
1046 let l4 = self.continuations[3].restore(l3).0;
1047 l4.as_page_table_owner()
1048 } else if self.level == 2 {
1049 let l2 = self.continuations[1];
1050 let l3 = self.continuations[2].restore(l2).0;
1051 let l4 = self.continuations[3].restore(l3).0;
1052 l4.as_page_table_owner()
1053 } else if self.level == 3 {
1054 let l3 = self.continuations[2];
1055 let l4 = self.continuations[3].restore(l3).0;
1056 l4.as_page_table_owner()
1057 } else {
1058 let l4 = self.continuations[3];
1059 l4.as_page_table_owner()
1060 }
1061 }
1062
1063 pub open spec fn cur_entry_owner(self) -> EntryOwner<C> {
1064 self.cur_subtree().value()
1065 }
1066
1067 pub open spec fn cur_subtree(self) -> OwnerSubtree<C> {
1068 self.continuations[self.level - 1].children[self.index() as int]->0
1069 }
1070
1071 pub proof fn lemma_cur_frame_clone_requires(
1086 self,
1087 item: C::Item,
1088 pa: Paddr,
1089 level: PagingLevel,
1090 prop: PageProperty,
1091 regions: MetaRegionOwners,
1092 )
1093 requires
1094 self.inv(),
1095 regions.inv(),
1096 self.metaregion_sound(regions),
1097 self.cur_entry_owner().is_frame(),
1098 pa == self.cur_entry_owner().frame().mapped_pa,
1099 C::item_from_raw(pa, level, prop, C::item_into_raw(item).3) == item,
1100 C::item_into_raw(item).3@ == self.cur_entry_owner().frame_permission(),
1101 valid_frame_paddr(pa),
1102 C::raw_item_well_formed((pa, level, prop, C::item_into_raw(item).3)),
1103 (C::item_into_raw(item).3@ is Some) == self.cur_entry_owner().frame_is_tracked(),
1105 C::item_into_raw(item).3@ is Some ==> (regions.slot_owner(pa).ref_count()
1107 < REF_COUNT_MAX || may_panic()),
1108 ensures
1109 item.clone_requires(regions),
1110 {
1111 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1112
1113 let entry = self.cur_entry_owner();
1114 let idx = frame_to_index(pa);
1115 EntryOwner::<C>::axiom_frame_is_tracked_iff_not_mmio(entry);
1116 let cont = self.continuations[self.level - 1];
1117 cont.lemma_map_children_unroll(
1118 PageTableOwner::<C>::metaregion_sound_pred(regions),
1119 cont.idx as int,
1120 );
1121 C::lemma_clone_requires_concrete(item, pa, level, prop, regions);
1122 }
1123
1124 pub proof fn lemma_clone_item_preserves_invariants(
1127 self,
1128 old_regions: MetaRegionOwners,
1129 new_regions: MetaRegionOwners,
1130 idx: int,
1131 )
1132 requires
1133 self.inv(),
1134 self.metaregion_sound(old_regions),
1135 old_regions.inv(),
1136 self.cur_entry_owner().is_frame(),
1137 idx == frame_to_index(self.cur_entry_owner().frame().mapped_pa),
1138 old_regions.slot_owners.contains_key(idx),
1139 new_regions.slot_owners.contains_key(idx),
1140 new_regions.ref_count(idx) == old_regions.ref_count(idx) + 1,
1142 new_regions.slot_owners[idx].ref_count_perm.id()
1144 == old_regions.slot_owners[idx].ref_count_perm.id(),
1145 new_regions.slot_owners[idx].metadata_perm.id()
1146 == old_regions.slot_owners[idx].metadata_perm.id(),
1147 new_regions.slot_owners[idx].metadata_perm.frac() + 1
1148 == old_regions.slot_owners[idx].metadata_perm.frac(),
1149 new_regions.slot_owners[idx].in_list_perm == old_regions.slot_owners[idx].in_list_perm,
1150 new_regions.slot_owners[idx].paths_in_pt == old_regions.slot_owners[idx].paths_in_pt,
1152 new_regions.slot_owners[idx].slot_vaddr == old_regions.slot_owners[idx].slot_vaddr,
1153 new_regions.slot_owners[idx].usage == old_regions.slot_owners[idx].usage,
1154 new_regions.slot_owners.dom() == old_regions.slot_owners.dom(),
1156 forall|i: int|
1157 #![trigger new_regions.slot_owners[i]]
1158 i != idx && old_regions.slot_owners.contains_key(i) ==> new_regions.slot_owners[i]
1159 == old_regions.slot_owners[i],
1160 new_regions.slots == old_regions.slots,
1162 new_regions.inv(),
1163 0 < old_regions.ref_count(idx),
1169 old_regions.ref_count(idx) + 1 <= REF_COUNT_MAX,
1170 ensures
1171 new_regions.inv(),
1172 self.metaregion_sound(new_regions),
1173 {
1174 self.lemma_metaregion_slot_owners_rc_increment(old_regions, new_regions, idx);
1175 }
1176
1177 pub proof fn lemma_new_child_mappings_eq_target(
1180 self,
1181 new_subtree: OwnerSubtree<C>,
1182 pa: Paddr,
1183 level: PagingLevel,
1184 prop: PageProperty,
1185 )
1186 requires
1187 self.inv(),
1188 self.in_locked_range(),
1189 level == self.level,
1190 new_subtree.inv(),
1191 new_subtree.value().is_frame(),
1192 new_subtree.value().path == self.continuations[self.level - 1].path().push_tail(
1193 self.continuations[self.level - 1].idx as int,
1194 ),
1195 new_subtree.value().frame().mapped_pa == pa,
1196 new_subtree.value().frame().prop == prop,
1197 ensures
1198 PageTableOwner(new_subtree)@.mappings
1199 == set![Mapping {
1200 va_range: self@.cur_slot_range(page_size::<PagingConsts>(level)),
1201 pa_range: pa..(pa + page_size::<PagingConsts>(level)) as usize,
1202 page_size: page_size::<PagingConsts>(level),
1203 property: prop,
1204 }],
1205 {
1206 self.cur_va_in_subtree_range();
1207 }
1208
1209 pub open spec fn locked_range(self) -> Range<Vaddr> {
1211 let size = page_size::<C>(self.guard_level) as nat;
1212 let start = nat_align_down(self.prefix as nat, size);
1213 Range { start: start as Vaddr, end: (start + size) as Vaddr }
1214 }
1215
1216 pub open spec fn in_locked_range(self) -> bool {
1217 self.locked_range().start <= self.va < self.locked_range().end
1218 }
1219
1220 pub open spec fn above_locked_range(self) -> bool {
1221 self.va >= self.locked_range().end
1222 }
1223
1224 pub proof fn lemma_prefix_in_locked_range(self)
1225 requires
1226 self.inv(),
1227 !self.popped_too_high,
1228 self.level < self.guard_level,
1229 ensures
1230 self.in_locked_range(),
1231 {
1232 C::lemma_paging_consts_properties();
1233 self.lemma_locked_range_span();
1234 let gl = self.guard_level;
1235 let path = TreePath::new(
1236 Seq::new(
1237 (C::NR_LEVELS() - gl + 1) as nat,
1238 |k: int|
1239 pte_index_spec::<C>(self.prefix, (C::NR_LEVELS() - k) as PagingLevel) as int,
1240 ),
1241 );
1242 assert forall|k: int| 0 <= k < path.len() implies {
1243 &&& TreePath::<NR_ENTRIES>::elem_inv(#[trigger] path[k])
1244 &&& path[k] == pte_index_spec::<C>(self.va, (C::NR_LEVELS() - k) as PagingLevel)
1245 } by {
1246 let level = (C::NR_LEVELS() - k) as PagingLevel;
1247 lemma_pte_index_bound::<C>(self.prefix, level);
1248 lemma_pte_index_bound::<C>(self.va, level);
1249 };
1250 lemma_vaddr_path_aligned::<C>(path, self.prefix);
1251 lemma_vaddr_path_aligned::<C>(path, self.va);
1252 lemma_page_size_ge_base::<PagingConsts>(gl);
1253 lemma_nat_align_down_sound(self.va as nat, page_size::<PagingConsts>(gl) as nat);
1254 }
1255
1256 #[verifier::rlimit(200)]
1258 pub proof fn lemma_in_locked_range_guard_index_eq_prefix(self)
1259 requires
1260 self.inv(),
1261 1 <= self.guard_level <= NR_LEVELS,
1262 self.in_locked_range(),
1263 ensures
1264 pte_index_spec::<C>(self.va, (self.guard_level - 1 + 1) as PagingLevel)
1265 == pte_index_spec::<C>(self.prefix, (self.guard_level - 1 + 1) as PagingLevel),
1266 {
1267 C::lemma_paging_consts_properties();
1268 self.lemma_locked_range_vaddr_prefix_match(self.va);
1269 assert(pte_index_spec::<C>(self.va, self.guard_level) == pte_index_spec::<C>(
1270 self.prefix,
1271 self.guard_level,
1272 ));
1273 lemma_pte_index_bound::<C>(self.va, self.guard_level);
1274 lemma_pte_index_bound::<C>(self.prefix, self.guard_level);
1275 }
1276
1277 pub proof fn lemma_in_locked_range_level_le_nr_levels(self)
1278 requires
1279 self.inv(),
1280 self.in_locked_range(),
1281 !self.popped_too_high,
1282 ensures
1283 self.level <= NR_LEVELS,
1284 {
1285 }
1286
1287 pub proof fn lemma_in_locked_range_top_index_lt_top_end(self)
1291 requires
1292 self.inv(),
1293 self.in_locked_range(),
1294 !self.popped_too_high,
1295 ensures
1296 pte_index_spec::<C>(self.va, (NR_LEVELS - 1 + 1) as PagingLevel)
1297 < C::TOP_LEVEL_INDEX_RANGE().end,
1298 {
1299 if self.guard_level == NR_LEVELS {
1300 if self.level >= self.guard_level {
1303 self.lemma_in_locked_range_guard_index_eq_prefix();
1314 }
1315 }
1316 }
1317
1318 pub proof fn lemma_in_locked_range_level_le_guard_level(self)
1319 requires
1320 self.inv(),
1321 self.in_locked_range(),
1322 !self.popped_too_high,
1323 ensures
1324 self.level <= self.guard_level,
1325 {
1326 }
1327
1328 pub proof fn lemma_locked_range_span(self)
1331 requires
1332 self.inv(),
1333 ensures
1334 self.locked_range().start as nat == nat_align_down(
1335 self.prefix as nat,
1336 page_size::<PagingConsts>(self.guard_level as PagingLevel) as nat,
1337 ),
1338 self.locked_range().start == self.prefix,
1339 self.locked_range().end == self.prefix + page_size::<PagingConsts>(self.guard_level),
1340 self.locked_range().start as nat % page_size::<PagingConsts>(
1341 self.guard_level as PagingLevel,
1342 ) as nat == 0,
1343 self.locked_range().end - self.locked_range().start == page_size::<PagingConsts>(
1344 self.guard_level as PagingLevel,
1345 ),
1346 {
1347 C::lemma_paging_consts_properties();
1348 self.lemma_prefix_aligned_to_guard_level();
1349 self.lemma_prefix_plus_ps_no_overflow();
1350 lemma_page_size_ge_base::<PagingConsts>(self.guard_level);
1351 lemma_nat_align_down_sound(
1352 self.prefix as nat,
1353 page_size::<PagingConsts>(self.guard_level) as nat,
1354 );
1355 }
1356
1357 pub proof fn lemma_prefix_aligned_to_guard_level(self)
1361 requires
1362 self.inv(),
1363 ensures
1364 self.prefix as nat % page_size::<PagingConsts>(self.guard_level) as nat == 0,
1365 {
1366 C::lemma_paging_consts_properties();
1367 lemma_lower_indices_aligned::<C>(self.prefix, self.guard_level);
1368 }
1369
1370 pub proof fn lemma_in_node_holds_at_top(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1373 requires
1374 self.inv(),
1375 self_va == self.va,
1376 self.guard_level == NR_LEVELS,
1377 node_size == page_size::<PagingConsts>((NR_LEVELS + 1) as PagingLevel),
1378 self.locked_range().start <= va < self.locked_range().end,
1379 ensures
1380 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1381 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1382 {
1383 C::lemma_paging_consts_properties();
1384 self.lemma_locked_range_span();
1385 let body_level = (C::NR_LEVELS() + 1) as PagingLevel;
1386 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(body_level);
1387 lemma_page_size_next::<C>(self.guard_level);
1388 lemma_usize_shr_is_div(self_va, page_table_vaddr_bits_spec::<C>());
1389 lemma_fundamental_div_mod(self_va as int, node_size as int);
1390 lemma_mul_is_commutative(self_va as int / node_size as int, node_size as int);
1391 lemma_nat_align_down_sound(self_va as nat, node_size as nat);
1392 assert(nat_align_down(self_va as nat, node_size as nat) == vaddr_upper_part_spec::<C>(
1393 self_va,
1394 ));
1395
1396 lemma_vaddr_upper_part_is_align_down::<C>(self_va);
1397 lemma_lower_indices_aligned::<C>(self.prefix, body_level);
1398 lemma_usize_shr_is_div(self.prefix, page_table_vaddr_bits_spec::<C>());
1399 lemma_fundamental_div_mod(self.prefix as int, node_size as int);
1400 assert(nat_align_down(self_va as nat, node_size as nat) == self.prefix);
1401 }
1402
1403 pub proof fn lemma_prefix_plus_ps_no_overflow(self)
1408 requires
1409 self.inv(),
1410 ensures
1411 self.prefix + page_size::<PagingConsts>(self.guard_level) <= usize::MAX,
1412 {
1413 C::lemma_paging_consts_properties();
1414 let gl = self.guard_level;
1415 lemma_lower_indices_aligned::<C>(self.prefix, (gl + 1) as PagingLevel);
1416 lemma_aligned_vaddr_slack::<C>(self.prefix, (gl + 1) as PagingLevel);
1417 lemma_page_size_next::<C>(gl);
1418 vstd::arithmetic::mul::lemma_mul_left_inequality(
1419 page_size::<C>(gl) as int,
1420 2,
1421 crate::mm::nr_subpage_per_huge::<C>() as int,
1422 );
1423 }
1424
1425 pub proof fn lemma_va_plus_page_size_no_overflow(self, level: PagingLevel)
1433 requires
1434 self.inv(),
1435 self.in_locked_range(),
1436 1 <= level <= self.guard_level,
1437 ensures
1438 self.va + page_size::<PagingConsts>(level) <= usize::MAX,
1439 {
1440 C::lemma_paging_consts_properties();
1441 self.lemma_locked_range_span();
1442 let gl = self.guard_level;
1443 lemma_lower_indices_aligned::<C>(self.prefix, (gl + 1) as PagingLevel);
1444 lemma_aligned_vaddr_slack::<C>(self.prefix, (gl + 1) as PagingLevel);
1445 lemma_page_size_next::<C>(gl);
1446 lemma_page_size_divides::<C>(level, gl);
1447 vstd::arithmetic::mul::lemma_mul_left_inequality(
1448 page_size::<C>(gl) as int,
1449 2,
1450 crate::mm::nr_subpage_per_huge::<C>() as int,
1451 );
1452 }
1453
1454 pub proof fn lemma_locked_range_page_aligned(self)
1455 requires
1456 self.inv(),
1457 ensures
1458 self.locked_range().end % PAGE_SIZE == 0,
1459 self.locked_range().start % PAGE_SIZE == 0,
1460 {
1461 self.lemma_locked_range_span();
1462 let gl = self.guard_level;
1463 lemma_page_size_base::<PagingConsts>();
1464 lemma_page_size_ge_base::<PagingConsts>(gl);
1465 lemma_page_size_divides::<PagingConsts>(1u8, gl);
1466 lemma_div_non_zero(page_size::<PagingConsts>(gl) as int, PAGE_SIZE as int);
1467 lemma_fundamental_div_mod(page_size::<PagingConsts>(gl) as int, PAGE_SIZE as int);
1468 vstd::arithmetic::div_mod::lemma_mod_mod(
1469 self.prefix as int,
1470 PAGE_SIZE as int,
1471 page_size::<PagingConsts>(gl) as int / PAGE_SIZE as int,
1472 );
1473 vstd::arithmetic::div_mod::lemma_add_mod_noop(
1474 self.prefix as int,
1475 page_size::<PagingConsts>(gl) as int,
1476 PAGE_SIZE as int,
1477 );
1478 }
1479
1480 pub proof fn lemma_cur_subtree_inv(self)
1481 requires
1482 self.inv(),
1483 ensures
1484 self.cur_subtree().inv(),
1485 {
1486 let cont = self.continuations[self.level - 1];
1487 cont.lemma_inv_children_unroll(cont.idx as int)
1488 }
1489
1490 pub proof fn lemma_cur_entry_absent_not_present(self)
1492 requires
1493 self.inv(),
1494 self.in_locked_range(),
1495 self.cur_entry_owner().is_absent(),
1496 ensures
1497 !self@.present(),
1498 {
1499 let cur_va = self.cur_va();
1500
1501 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1502 <= cur_va < m.va_range.end) by {
1503 if m.va_range.start <= cur_va < m.va_range.end {
1504 self.mapping_covering_cur_va_from_cur_subtree(m);
1505 }
1506 };
1507
1508 let filtered = self@.mappings.filter(
1509 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1510 );
1511 assert(filtered == set![]) by {};
1512 }
1513
1514 pub proof fn lemma_cur_subtree_empty_not_present(self)
1516 requires
1517 self.inv(),
1518 self.in_locked_range(),
1519 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value().path) =~= set![],
1520 ensures
1521 !self@.present(),
1522 {
1523 let cur_va = self.cur_va();
1524
1525 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1526 <= cur_va < m.va_range.end) by {
1527 if m.va_range.start <= cur_va < m.va_range.end {
1528 self.mapping_covering_cur_va_from_cur_subtree(m);
1529 }
1530 };
1531
1532 let filtered = self@.mappings.filter(
1533 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1534 );
1535 assert(filtered == set![]) by {};
1536 }
1537
1538 pub proof fn lemma_cur_entry_frame_present(self)
1539 requires
1540 self.inv(),
1541 self.in_locked_range(),
1542 self.cur_entry_owner().is_frame(),
1543 ensures
1544 self@.present(),
1545 self@.query(
1546 self.cur_entry_owner().frame().mapped_pa,
1547 page_size::<PagingConsts>(self.cur_entry_owner().parent_level),
1548 self.cur_entry_owner().frame().prop,
1549 ),
1550 {
1551 self.view_preserves_inv();
1552 let subtree = self.cur_subtree();
1553 let path = subtree.value().path;
1554 let frame = self.cur_entry_owner().frame();
1555 let pt_level = INC_LEVELS - path.len();
1556 let cont = self.continuations[self.level - 1];
1557
1558 let m = Mapping {
1559 va_range: Range {
1560 start: vaddr_of::<C>(path) as int,
1561 end: vaddr_of::<C>(path) + page_size::<PagingConsts>(pt_level as PagingLevel),
1562 },
1563 pa_range: Range {
1564 start: frame.mapped_pa,
1565 end: (frame.mapped_pa + page_size::<PagingConsts>(
1566 pt_level as PagingLevel,
1567 )) as Paddr,
1568 },
1569 page_size: page_size::<PagingConsts>(pt_level as PagingLevel),
1570 property: frame.prop,
1571 };
1572 cont.lemma_view_mappings_intro(m, cont.idx as int);
1573 self.lemma_view_mappings_intro(m, self.level - 1);
1574 assert(m.va_range.start <= self@.cur_va < m.va_range.end) by {
1575 self.cur_va_in_subtree_range();
1576 };
1577
1578 let filtered = self@.mappings.filter(
1579 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
1580 );
1581 lemma_set_contains_len(filtered, m);
1582 let queried = self@.query_mapping();
1584 assert(filtered.contains(queried));
1585 assert(queried == m);
1586 }
1587
1588 #[verifier::opaque]
1590 pub open spec fn path_metaregion_sound(self, regions: MetaRegionOwners) -> bool {
1591 forall|i: int|
1592 #![trigger self.continuations[i]]
1593 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].entry_own.metaregion_sound(
1594 regions,
1595 )
1596 }
1597
1598 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
1599 &&& self.map_full_tree(
1600 |entry_owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1601 entry_owner.metaregion_sound(regions),
1602 )
1603 &&& self.path_metaregion_sound(regions)
1604 }
1605
1606 pub proof fn lemma_metaregion_preserved(
1607 self,
1608 other: Self,
1609 regions0: MetaRegionOwners,
1610 regions1: MetaRegionOwners,
1611 )
1612 requires
1613 self.inv(),
1614 self.metaregion_sound(regions0),
1615 self.level == other.level,
1616 self.continuations =~= other.continuations,
1617 OwnerSubtree::implies(
1618 PageTableOwner::<C>::metaregion_sound_pred(regions0),
1619 PageTableOwner::<C>::metaregion_sound_pred(regions1),
1620 ),
1621 ensures
1622 other.metaregion_sound(regions1),
1623 {
1624 let f = PageTableOwner::metaregion_sound_pred(regions0);
1625 let g = PageTableOwner::metaregion_sound_pred(regions1);
1626
1627 assert forall|i: int| #![auto] self.level - 1 <= i < NR_LEVELS implies {
1628 other.continuations[i].map_children(g)
1629 } by {
1630 reveal(CursorContinuation::map_children);
1631 let cont = self.continuations[i];
1632 assert forall|j: int|
1633 0 <= j < NR_ENTRIES
1634 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
1635 cont.path().push_tail(j), g) by {
1636 cont.children[j].unwrap().lemma_subtree_satisfies_implies(
1637 cont.path().push_tail(j),
1638 f,
1639 g,
1640 );
1641 };
1642 };
1643 assert(other.path_metaregion_sound(regions1)) by {
1644 reveal(CursorOwner::path_metaregion_sound);
1645 assert forall|i: int|
1646 #![trigger other.continuations[i]]
1647 self.level - 1 <= i
1648 < NR_LEVELS implies other.continuations[i].entry_own.metaregion_sound(
1649 regions1,
1650 ) by {
1651 let eo = self.continuations[i].entry_own;
1652 assert(g(eo, self.continuations[i].path()));
1653 };
1654 };
1655 }
1656
1657 pub proof fn lemma_metaregion_slot_owners_preserved(
1659 self,
1660 regions0: MetaRegionOwners,
1661 regions1: MetaRegionOwners,
1662 )
1663 requires
1664 self.inv(),
1665 self.metaregion_sound(regions0),
1666 regions0.slot_owners =~= regions1.slot_owners,
1667 forall|k: int|
1668 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
1669 forall|k: int|
1670 regions0.slots.contains_key(k) ==> regions0.slots[k]
1671 == #[trigger] regions1.slots[k],
1672 ensures
1673 self.metaregion_sound(regions1),
1674 {
1675 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
1676 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
1677 assert(OwnerSubtree::implies(f, g)) by {
1678 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1679 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
1680 entry.metaregion_sound_slot_owners_only(regions0, regions1);
1681 };
1682 };
1683 self.lemma_metaregion_preserved(self, regions0, regions1);
1684 }
1685
1686 pub proof fn lemma_metaregion_slot_owners_rc_increment(
1687 self,
1688 regions0: MetaRegionOwners,
1689 regions1: MetaRegionOwners,
1690 idx: int,
1691 )
1692 requires
1693 self.inv(),
1694 self.metaregion_sound(regions0),
1695 regions0.inv(),
1696 regions1.slots == regions0.slots,
1697 regions1.slot_owners.dom() == regions0.slot_owners.dom(),
1698 regions1.ref_count(idx) == regions0.ref_count(idx) + 1,
1699 regions1.slot_owners[idx].ref_count_perm.id()
1700 == regions0.slot_owners[idx].ref_count_perm.id(),
1701 regions1.slot_owners[idx].metadata_perm.id()
1702 == regions0.slot_owners[idx].metadata_perm.id(),
1703 regions1.slot_owners[idx].metadata_perm.frac() + 1
1704 == regions0.slot_owners[idx].metadata_perm.frac(),
1705 regions1.slot_owners[idx].in_list_perm == regions0.slot_owners[idx].in_list_perm,
1706 regions1.slot_owners[idx].paths_in_pt == regions0.slot_owners[idx].paths_in_pt,
1707 regions1.slot_owners[idx].slot_vaddr == regions0.slot_owners[idx].slot_vaddr,
1708 regions1.slot_owners[idx].usage == regions0.slot_owners[idx].usage,
1709 regions1.ref_count(idx) != REF_COUNT_UNUSED,
1710 regions1.ref_count(idx) <= REF_COUNT_MAX,
1712 regions1.inv(),
1713 forall|i: int|
1714 #![trigger regions1.slot_owners[i]]
1715 i != idx && regions0.slot_owners.contains_key(i) ==> regions1.slot_owners[i]
1716 == regions0.slot_owners[i],
1717 ensures
1718 self.metaregion_sound(regions1),
1719 {
1720 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
1721 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
1722 assert(OwnerSubtree::implies(f, g)) by {
1723 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1724 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
1725 if entry.is_frame() {
1726 let pa = entry.frame().mapped_pa;
1727 C::lemma_perm_well_formed_with_region_preserved(
1728 pa,
1729 Tracked(entry.frame_permission()),
1730 regions0,
1731 regions1,
1732 );
1733 }
1734 };
1735 };
1736 self.lemma_metaregion_preserved(self, regions0, regions1);
1737 }
1738
1739 pub proof fn lemma_cont_entry_metaregion_at(self, regions: MetaRegionOwners, i: int)
1741 requires
1742 self.inv(),
1743 self.metaregion_sound(regions),
1744 self.level - 1 <= i < NR_LEVELS,
1745 ensures
1746 self.continuations[i].entry_own.metaregion_sound(regions),
1747 {
1748 reveal(CursorOwner::path_metaregion_sound);
1749 }
1750
1751 pub open spec fn new(
1752 owner_subtree: OwnerSubtree<C>,
1753 idx: usize,
1754 guard: PageTableGuard<'rcu, C>,
1755 ) -> Self {
1756 let va = (C::LEADING_BITS_spec() as int * pow2(page_table_vaddr_bits_spec::<C>() as nat)
1757 + idx * pow2(pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat)) as Vaddr;
1758 Self {
1759 level: C::NR_LEVELS(),
1760 continuations: Map::empty().insert(
1761 C::NR_LEVELS() - 1,
1762 CursorContinuation::new(owner_subtree, idx, guard),
1763 ),
1764 va,
1765 guard_level: C::NR_LEVELS(),
1766 prefix: va,
1767 popped_too_high: false,
1768 }
1769 }
1770
1771 pub proof fn tracked_new(
1772 tracked owner_subtree: OwnerSubtree<C>,
1773 idx: usize,
1774 guard: PageTableGuard<'rcu, C>,
1775 ) -> tracked Self
1776 returns
1777 Self::new(owner_subtree, idx, guard),
1778 {
1779 let ghost va = (C::LEADING_BITS_spec() as int * pow2(
1780 page_table_vaddr_bits_spec::<C>() as nat,
1781 ) + idx * pow2(pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat)) as Vaddr;
1782 let tracked continuation = CursorContinuation::tracked_new(owner_subtree, idx, guard);
1783 let tracked mut continuations = Map::tracked_empty();
1784 continuations.tracked_insert(C::NR_LEVELS() - 1, continuation);
1785 Self {
1786 level: C::NR_LEVELS(),
1787 continuations,
1788 va,
1789 guard_level: C::NR_LEVELS(),
1790 prefix: va,
1791 popped_too_high: false,
1792 }
1793 }
1794
1795 pub broadcast group group_lemmas {
1796 CursorOwner::lemma_view_mappings_contains,
1797 CursorOwner::lemma_view_mappings_intro,
1798 }
1799}
1800
1801pub ghost struct CursorView<C: PageTableConfig> {
1802 pub cur_va: Vaddr,
1803 pub mappings: Set<Mapping>,
1804 pub phantom: PhantomData<C>,
1805}
1806
1807impl<'rcu, C: PageTableConfig> View for CursorOwner<'rcu, C> {
1808 type V = CursorView<C>;
1809
1810 open spec fn view(&self) -> Self::V {
1811 CursorView { cur_va: self.cur_va(), mappings: self.view_mappings(), phantom: PhantomData }
1812 }
1813}
1814
1815impl<C: PageTableConfig> Inv for CursorView<C> {
1816 open spec fn inv(self) -> bool {
1817 &&& forall|m: Mapping|
1818 #![auto]
1819 self.mappings.contains(m)
1820 ==> m.inv()
1821 &&& forall|m: Mapping|
1827 #![auto]
1828 self.mappings.contains(m) ==> {
1829 &&& vaddr_range_spec::<C>().start <= m.va_range.start
1830 &&& m.va_range.end <= vaddr_range_spec::<C>().end + 1
1831 }
1832 &&& self.non_overlapping()
1833 }
1834}
1835
1836impl<C: PageTableConfig> CursorView<C> {
1837 pub open spec fn non_overlapping(self) -> bool {
1840 forall|m: Mapping, n: Mapping|
1841 #![auto]
1842 self.mappings.contains(m) ==> self.mappings.contains(n) ==> m != n ==> m.va_range.end
1843 <= n.va_range.start || n.va_range.end <= m.va_range.start
1844 }
1845}
1846
1847pub proof fn lemma_view_in_vaddr_range<'rcu, C: PageTableConfig>(owner: &CursorOwner<'rcu, C>)
1850 requires
1851 owner.inv(),
1852 ensures
1853 forall|m: Mapping|
1854 #![auto]
1855 owner.view_mappings().contains(m) ==> {
1856 &&& vaddr_range_spec::<C>().start <= m.va_range.start
1857 &&& m.va_range.end <= vaddr_range_spec::<C>().end + 1
1858 },
1859{
1860 C::lemma_paging_consts_properties();
1861 C::lemma_page_table_config_constant_properties();
1862 lemma_arch_specific_consts_properties::<C>();
1863
1864 let idx = C::TOP_LEVEL_INDEX_RANGE();
1865 let start = idx.start as int;
1866 let end = idx.end as int;
1867 let lb = C::LEADING_BITS_spec() as int;
1868 let base = lb * 0x1_0000_0000_0000int;
1869 let cell = 0x80_0000_0000int;
1870 let bounds = vaddr_range_spec::<C>();
1871
1872 let end_exclusive = base + end * cell;
1873 let end_pre = end_exclusive - 1;
1874
1875 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
1876 &&& vaddr_range_spec::<C>().start <= m.va_range.start
1877 &&& m.va_range.end <= vaddr_range_spec::<C>().end + 1
1878 } by {
1879 let i = choose|i: int|
1880 owner.level - 1 <= i < NR_LEVELS && (
1881 #[trigger] owner.continuations[i]).view_mappings().contains(m);
1882 let cont = owner.continuations[i];
1883 let j = choose|j: int|
1884 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
1885 cont.children[j].unwrap(),
1886 ).view_rec(cont.path().push_tail(j)).contains(m);
1887 let child = PageTableOwner(cont.children[j].unwrap());
1888 let p = cont.path().push_tail(j);
1889 let pidx = p[0] as int;
1890 child.view_rec_top_index_va_bound(p, m, end);
1891 }
1892}
1893
1894pub proof fn lemma_view_in_vaddr_range_user<'rcu>(
1903 owner: &CursorOwner<'rcu, crate::mm::vm_space::UserPtConfig>,
1904)
1905 requires
1906 owner.inv(),
1907 ensures
1908 forall|m: Mapping|
1909 #![auto]
1910 owner.view_mappings().contains(m) ==> {
1911 &&& 0 <= m.va_range.start
1912 &&& m.va_range.end <= 0x8000_0000_0000int
1913 },
1914{
1915 let end = crate::mm::vm_space::UserPtConfig::TOP_LEVEL_INDEX_RANGE().end as int;
1916 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
1917 &&& 0 <= m.va_range.start
1918 &&& m.va_range.end <= 0x8000_0000_0000int
1919 } by {
1920 let i = choose|i: int|
1921 owner.level - 1 <= i < NR_LEVELS && (
1922 #[trigger] owner.continuations[i]).view_mappings().contains(m);
1923 let cont = owner.continuations[i];
1924 let j = choose|j: int|
1925 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
1926 cont.children[j].unwrap(),
1927 ).view_rec(cont.path().push_tail(j)).contains(m);
1928 let child = PageTableOwner(cont.children[j].unwrap());
1929 let p = cont.path().push_tail(j);
1930 child.view_rec_top_index_va_bound(p, m, end);
1931 }
1932}
1933
1934pub proof fn lemma_view_in_vaddr_range_kernel<'rcu>(owner: CursorOwner<'rcu, KernelPtConfig>)
1939 requires
1940 owner.inv(),
1941 ensures
1942 forall|m: Mapping|
1943 #![auto]
1944 owner.view_mappings().contains(m) ==> {
1945 &&& vaddr_range_spec::<KernelPtConfig>().start <= m.va_range.start
1946 &&& m.va_range.end <= vaddr_range_spec::<KernelPtConfig>().end + 1
1947 },
1948{
1949 lemma_vaddr_range_spec_kernel();
1950 let end = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end as int;
1951 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
1952 &&& vaddr_range_spec::<KernelPtConfig>().start <= m.va_range.start
1953 &&& m.va_range.end <= vaddr_range_spec::<KernelPtConfig>().end + 1
1954 } by {
1955 let i = choose|i: int|
1956 owner.level - 1 <= i < NR_LEVELS && (
1957 #[trigger] owner.continuations[i]).view_mappings().contains(m);
1958 let cont = owner.continuations[i];
1959 let j = choose|j: int|
1960 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
1961 cont.children[j].unwrap(),
1962 ).view_rec(cont.path().push_tail(j)).contains(m);
1963 let child = PageTableOwner(cont.children[j].unwrap());
1964 let p = cont.path().push_tail(j);
1965 child.view_rec_top_index_va_bound(p, m, end);
1966 }
1968}
1969
1970impl<'rcu, C: PageTableConfig> InvView for CursorOwner<'rcu, C> {
1971 proof fn view_preserves_inv(self) {
1972 self.view_non_overlapping();
1974 self.view_mapping_inv();
1977 lemma_view_in_vaddr_range::<C>(&self);
1980 }
1981}
1982
1983impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
1984 pub proof fn view_non_overlapping(self)
1990 requires
1991 self.inv(),
1992 ensures
1993 self@.non_overlapping(),
1994 {
1995 self.as_page_table_owner_view_non_overlapping();
1996 }
1997}
1998
1999impl<'rcu, C: PageTableConfig, A: InAtomicMode> Inv for Cursor<'rcu, C, A> {
2000 open spec fn inv(self) -> bool {
2001 &&& 1 <= self.level <= NR_LEVELS
2009 + 1
2010 &&& self.level <= self.guard_level + 1
2018 &&& self.guard_level
2019 <= NR_LEVELS
2020 &&& self.va >= self.barrier_va.start
2022 &&& self.va % PAGE_SIZE == 0
2023 }
2024}
2025
2026impl<'rcu, C: PageTableConfig, A: InAtomicMode> OwnerOf for Cursor<'rcu, C, A> {
2027 type Owner = CursorOwner<'rcu, C>;
2028
2029 open spec fn wf(self, owner: Self::Owner) -> bool {
2030 &&& owner.va == self.va
2031 &&& self.level == owner.level
2032 &&& owner.guard_level
2033 == self.guard_level
2034 &&& self.level <= 4 ==> {
2043 &&& 4 <= self.guard_level ==> {
2044 &&& self.path[3] is Some
2045 &&& owner.continuations.contains_key(3)
2046 &&& owner.continuations[3].guard == self.path[3]->0
2047 }
2048 &&& 4 > self.guard_level ==> self.path[3] is None
2049 }
2050 &&& self.level <= 3 ==> {
2051 &&& 3 <= self.guard_level ==> {
2052 &&& self.path[2] is Some
2053 &&& owner.continuations.contains_key(2)
2054 &&& owner.continuations[2].guard == self.path[2]->0
2055 }
2056 &&& 3 > self.guard_level ==> self.path[2] is None
2057 }
2058 &&& self.level <= 2 ==> {
2059 &&& 2 <= self.guard_level ==> {
2060 &&& self.path[1] is Some
2061 &&& owner.continuations.contains_key(1)
2062 &&& owner.continuations[1].guard == self.path[1]->0
2063 }
2064 &&& 2 > self.guard_level ==> self.path[1] is None
2065 }
2066 &&& self.level == 1 ==> {
2067 &&& 1 <= self.guard_level ==> {
2071 &&& self.path[0] is Some
2072 &&& owner.continuations.contains_key(0)
2073 &&& owner.continuations[0].guard == self.path[0]->0
2074 }
2075 &&& 1 > self.guard_level ==> self.path[0] is None
2076 }
2077 &&& self.barrier_va.start == owner.locked_range().start
2078 &&& self.barrier_va.end == owner.locked_range().end
2079 }
2080}
2081
2082}