1use vstd::{
2 arithmetic::{
3 div_mod::{lemma_div_non_zero, lemma_fundamental_div_mod},
4 mul::{lemma_mul_inequality, 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 arithmetic::lemma_nat_align_down_within_block,
14 drop_tracking::*,
15 ghost_tree::*,
16 ownership::*,
17 panic::may_panic,
18 prelude::*,
19 seq_extra::{forall_seq, lemma_forall_seq_index},
20};
21
22use crate::specs::{
23 arch::*,
24 mm::{
25 frame::{
26 mapping::{frame_to_index, index_to_meta},
27 meta_owners::MetaSlotStorage,
28 meta_region_owners::MetaRegionOwners,
29 },
30 page_table::{owners::*, vaddr_range_proofs::*, *},
31 },
32 task::InAtomicMode,
33};
34
35use crate::arch::mm::PagingConsts;
36use crate::mm::{
37 MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr,
38 frame::{
39 Frame,
40 meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
41 },
42 nr_subpage_per_huge,
43 page_prop::PageProperty,
44 page_size,
45 page_table::*,
46};
47use core::{marker::PhantomData, ops::Range};
48
49verus! {
50
51broadcast use group_ghost_tree_lemmas;
52
53pub tracked struct CursorContinuation<'rcu, C: PageTableConfig> {
54 pub entry_own: EntryOwner<C>,
55 pub ghost idx: usize,
56 pub ghost tree_level: nat,
57 pub children: Seq<Option<OwnerSubtree<C>>>,
58 pub ghost path: TreePath<NR_ENTRIES>,
59 pub ghost guard: PageTableGuard<'rcu, C>,
60}
61
62impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
63 pub open spec fn path(self) -> TreePath<NR_ENTRIES> {
64 self.entry_own.path
65 }
66
67 pub open spec fn child(self) -> OwnerSubtree<C> {
68 self.children[self.idx as int]->0
69 }
70
71 pub open spec fn take_child(self) -> (OwnerSubtree<C>, Self) {
72 let child = self.children[self.idx as int]->0;
73 let cont = Self {
74 children: self.children.remove(self.idx as int).insert(self.idx as int, None),
75 ..self
76 };
77 (child, cont)
78 }
79
80 pub proof fn tracked_take_child(tracked &mut self) -> (tracked res: OwnerSubtree<C>)
81 requires
82 old(self).inv(),
83 old(self).idx < old(self).children.len(),
84 old(self).children[old(self).idx as int] is Some,
85 ensures
86 res == old(self).take_child().0,
87 *final(self) == old(self).take_child().1,
88 res.inv(),
89 {
90 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
91 self.children.tracked_insert(old(self).idx as int, None);
92 child
93 }
94
95 pub open spec fn put_child(self, child: OwnerSubtree<C>) -> Self {
96 Self {
97 children: self.children.remove(self.idx as int).insert(self.idx as int, Some(child)),
98 ..self
99 }
100 }
101
102 pub proof fn tracked_put_child(tracked &mut self, tracked child: OwnerSubtree<C>)
103 requires
104 old(self).idx < old(self).children.len(),
105 old(self).children[old(self).idx as int] is None,
106 ensures
107 *final(self) == old(self).put_child(child),
108 {
109 let _ = self.children.tracked_remove(old(self).idx as int);
110 self.children.tracked_insert(old(self).idx as int, Some(child));
111 }
112
113 pub proof fn take_put_child(self)
114 requires
115 self.idx < self.children.len(),
116 self.children[self.idx as int] is Some,
117 ensures
118 self.take_child().1.put_child(self.take_child().0) == self,
119 {
120 let child = self.take_child().0;
121 let cont = self.take_child().1;
122 assert(cont.put_child(child).children == self.children);
123 }
124
125 pub proof fn take_child_preserves_inv(self)
127 requires
128 self.inv(),
129 self.idx < self.children.len(),
130 self.children[self.idx as int] is Some,
131 ensures
132 self.take_child().1.inv(),
133 {
134 }
135
136 pub open spec fn make_cont(self, idx: usize, guard: PageTableGuard<'rcu, C>) -> (Self, Self) {
137 let child = Self {
138 entry_own: self.children[self.idx as int]->0.value(),
139 tree_level: (self.tree_level + 1) as nat,
140 idx: idx,
141 children: self.children[self.idx as int]->0.children(),
142 path: self.path.push_tail(self.idx as int),
143 guard: guard,
144 };
145 let cont = Self { children: self.children.update(self.idx as int, None), ..self };
146 (child, cont)
147 }
148
149 pub proof fn tracked_make_cont(
150 tracked &mut self,
151 idx: usize,
152 guard: PageTableGuard<'rcu, C>,
153 ) -> (tracked res: Self)
154 requires
155 old(self).all_some(),
156 old(self).children.len() == NR_ENTRIES,
157 old(self).idx < NR_ENTRIES,
158 idx < NR_ENTRIES,
159 ensures
160 res == old(self).make_cont(idx, guard).0,
161 *final(self) == old(self).make_cont(idx, guard).1,
162 {
163 lemma_update_is_remove_insert(self.children, old(self).idx as int, None);
164 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
165 self.children.tracked_insert(old(self).idx as int, None);
166 let tracked (entry_own, children) = child.tracked_into_parts();
167 Self {
168 entry_own,
169 tree_level: (old(self).tree_level + 1) as nat,
170 idx,
171 children,
172 path: old(self).path.push_tail(old(self).idx as int),
173 guard,
174 }
175 }
176
177 pub open spec fn restore(self, child: Self) -> (Self, PageTableGuard<'rcu, C>) {
178 let child_node = OwnerSubtree::new(child.entry_own, child.tree_level, child.children);
179 (
180 Self { children: self.children.update(self.idx as int, Some(child_node)), ..self },
181 child.guard,
182 )
183 }
184
185 pub proof fn tracked_restore(tracked &mut self, tracked child: Self) -> (guard: PageTableGuard<
186 'rcu,
187 C,
188 >)
189 requires
190 old(self).idx < old(self).children.len(),
191 ensures
192 *final(self) == old(self).restore(child).0,
193 guard == old(self).restore(child).1,
194 {
195 let tracked child_node = OwnerSubtree::tracked_new(
196 child.entry_own,
197 child.tree_level,
198 child.children,
199 );
200 lemma_update_is_remove_insert(self.children, self.idx as int, Some(child_node));
201 let _ = self.children.tracked_remove(self.idx as int);
202 self.children.tracked_insert(self.idx as int, Some(child_node));
203 child.guard
204 }
205
206 pub open spec fn new(
207 owner_subtree: OwnerSubtree<C>,
208 idx: usize,
209 guard: PageTableGuard<'rcu, C>,
210 ) -> Self {
211 Self {
212 entry_own: owner_subtree.value(),
213 idx: idx,
214 tree_level: owner_subtree.level(),
215 children: owner_subtree.children(),
216 path: TreePath::new(Seq::empty()),
217 guard: guard,
218 }
219 }
220
221 pub proof fn tracked_new(
222 tracked owner_subtree: OwnerSubtree<C>,
223 idx: usize,
224 guard: PageTableGuard<'rcu, C>,
225 ) -> tracked Self
226 returns
227 Self::new(owner_subtree, idx, guard),
228 {
229 let ghost tree_level = owner_subtree.level();
230 let tracked (entry_own, children) = owner_subtree.tracked_into_parts();
231 Self { entry_own, idx, tree_level, children, path: TreePath::new(Seq::empty()), guard }
232 }
233
234 #[verifier::opaque]
236 pub open spec fn map_children(
237 self,
238 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
239 ) -> bool {
240 forall|i: int|
241 #![trigger(self.children[i])]
242 0 <= i < self.children.len() ==> self.children[i] is Some
243 ==> self.children[i]->0.subtree_satisfies(self.path().push_tail(i), f)
244 }
245
246 pub proof fn lemma_map_children_unroll(
248 self,
249 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
250 i: int,
251 )
252 requires
253 self.map_children(f),
254 0 <= i < self.children.len(),
255 self.children[i] is Some,
256 ensures
257 self.children[i]->0.subtree_satisfies(self.path().push_tail(i), f),
258 {
259 reveal(CursorContinuation::map_children);
260 }
261
262 pub open spec fn level(self) -> PagingLevel {
265 self.entry_own.node().level()
266 }
267
268 pub open spec fn inv_children(self) -> bool {
269 self.children.all(|child: Option<OwnerSubtree<C>>| child is Some ==> child->0.inv())
270 }
271
272 pub proof fn lemma_inv_children_unroll(self, i: int)
273 requires
274 self.inv_children(),
275 0 <= i < self.children.len(),
276 self.children[i] is Some,
277 ensures
278 self.children[i]->0.inv(),
279 {
280 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
281 assert(pred(self.children[i]));
282 }
283
284 pub proof fn lemma_inv_children_unroll_all(self)
285 requires
286 self.inv_children(),
287 ensures
288 forall|i: int|
289 #![auto]
290 0 <= i < self.children.len() ==> self.children[i] is Some
291 ==> self.children[i]->0.inv(),
292 {
293 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
294 assert forall|i: int|
295 0 <= i < self.children.len()
296 && #[trigger] self.children[i] is Some implies self.children[i].unwrap().inv() by {
297 self.lemma_inv_children_unroll(i)
298 }
299 }
300
301 pub open spec fn inv_children_rel_pred(self) -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
302 |i: int, child: Option<OwnerSubtree<C>>|
303 {
304 child is Some ==> {
305 &&& child->0.value().parent_level == self.level()
306 &&& child->0.level() == self.tree_level + 1
307 &&& child->0.value().path.len() == self.entry_own.node().tree_level + 1
308 &&& child->0.value().match_pte(
309 self.entry_own.node().children_perm.value()[i],
310 self.entry_own.node().level(),
311 )
312 &&& child->0.value().path == self.path().push_tail(i)
313 }
314 }
315 }
316
317 pub open spec fn inv_children_rel(self) -> bool {
318 forall_seq(self.children, self.inv_children_rel_pred())
319 }
320
321 pub open spec fn pt_inv_children_pred() -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
322 |i: int, child: Option<OwnerSubtree<C>>| child is Some ==> PageTableOwner(child->0).pt_inv()
323 }
324
325 pub open spec fn pt_inv_children(self) -> bool {
326 forall_seq(self.children, Self::pt_inv_children_pred())
327 }
328
329 pub proof fn lemma_pt_inv_children_unroll(self, i: int)
330 requires
331 self.pt_inv_children(),
332 0 <= i < self.children.len(),
333 self.children[i] is Some,
334 ensures
335 PageTableOwner(self.children[i]->0).pt_inv(),
336 {
337 }
338
339 pub proof fn lemma_inv_children_rel_unroll(self, i: int)
340 requires
341 self.inv_children_rel(),
342 0 <= i < self.children.len(),
343 self.children[i] is Some,
344 ensures
345 self.children[i]->0.value().parent_level == self.level(),
346 self.children[i]->0.level() == self.tree_level + 1,
347 self.children[i]->0.value().path.len() == self.entry_own.node().tree_level + 1,
348 self.children[i]->0.value().match_pte(
349 self.entry_own.node().children_perm.value()[i],
350 self.entry_own.node().level(),
351 ),
352 self.children[i]->0.value().path == self.path().push_tail(i),
353 {
354 }
355
356 pub open spec fn inv(self) -> bool {
357 &&& self.children.len() == NR_ENTRIES
358 &&& 0 <= self.idx < NR_ENTRIES
359 &&& self.inv_children()
360 &&& self.inv_children_rel()
361 &&& self.pt_inv_children()
362 &&& self.entry_own.is_node()
363 &&& self.entry_own.inv()
364 &&& self.entry_own.node().relate_guard(self.guard)
365 &&& self.tree_level == INC_LEVELS - self.level() - 1
366 &&& self.tree_level < INC_LEVELS - 1
367 &&& self.path().len() == self.tree_level
368 }
369
370 pub open spec fn all_some(self) -> bool {
371 forall|i: int| 0 <= i < NR_ENTRIES ==> self.children[i] is Some
372 }
373
374 pub open spec fn all_but_index_some(self) -> bool {
375 &&& forall|i: int| 0 <= i < self.idx ==> self.children[i] is Some
376 &&& forall|i: int| self.idx < i < NR_ENTRIES ==> self.children[i] is Some
377 &&& self.children[self.idx as int] is None
378 }
379
380 pub open spec fn inc_index(self) -> Self {
381 Self { idx: (self.idx + 1) as usize, ..self }
382 }
383
384 pub proof fn do_inc_index(tracked &mut self)
385 requires
386 old(self).idx + 1 < NR_ENTRIES,
387 ensures
388 *final(self) == old(self).inc_index(),
389 {
390 self.idx = (self.idx + 1) as usize;
391 }
392
393 pub open spec fn node_locked(self, guards: Guards) -> bool {
394 guards.lock_held(self.guard.inner.inner@.slot_vaddr())
395 }
396
397 pub open spec fn view_mappings(self) -> Set<Mapping> {
398 self.children.map(
399 |i, child: Option<OwnerSubtree<C>>|
400 if child is Some {
401 PageTableOwner(child->0).view_rec(self.path().push_tail(i))
402 } else {
403 Set::empty()
404 },
405 ).to_set().flatten()
406 }
407
408 pub broadcast proof fn lemma_view_mappings_contains(self)
409 ensures
410 #![trigger self.view_mappings()]
411 forall|m: Mapping| #[trigger]
412 self.view_mappings().contains(m) ==> exists|i: int|
413 #![trigger self.children[i]]
414 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
415 self.children[i]->0,
416 ).view_rec(self.path().push_tail(i)).contains(m),
417 {
418 broadcast use vstd::seq_lib::group_seq_properties;
419
420 }
421
422 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
423 requires
424 0 <= i < self.children.len(),
425 self.children[i] is Some,
426 #[trigger] PageTableOwner(self.children[i]->0).view_rec(
427 self.path().push_tail(i),
428 ).contains(m),
429 ensures
430 self.view_mappings().contains(m),
431 {
432 broadcast use vstd::seq_lib::group_seq_properties;
433
434 let mapped = self.children.map(
435 |i, child: Option<OwnerSubtree<C>>|
436 if child is Some {
437 PageTableOwner(child->0).view_rec(self.path().push_tail(i))
438 } else {
439 Set::empty()
440 },
441 );
442 assert(mapped.to_set().contains(mapped[i]));
443 }
444
445 pub open spec fn as_subtree(self) -> OwnerSubtree<C> {
446 OwnerSubtree::new(self.entry_own, self.tree_level, self.children)
447 }
448
449 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
450 PageTableOwner(self.as_subtree())
451 }
452
453 pub open spec fn view_mappings_take_child_spec(self) -> Set<Mapping> {
454 PageTableOwner(self.children[self.idx as int]->0).view_rec(
455 self.path().push_tail(self.idx as int),
456 )
457 }
458
459 pub proof fn lemma_rel_children_from_node_matching(
471 entry: &Entry<'_, 'rcu, C>,
472 child_value: EntryOwner<C>,
473 parent_owner: NodeOwner<C>,
474 guard: PageTableGuard<'rcu, C>,
475 entry_own: EntryOwner<C>,
476 idx: usize,
477 )
478 requires
479 entry.node_matching(child_value, parent_owner, guard),
480 entry.idx == idx,
481 entry_own.is_node(),
482 entry_own.node() == parent_owner,
483 child_value.path == entry_own.path.push_tail(idx as int),
484 child_value.path.len() == parent_owner.tree_level + 1,
485 ensures
486 child_value.path.len() == parent_owner.tree_level + 1,
487 child_value.match_pte(
488 parent_owner.children_perm.value()[idx as int],
489 parent_owner.level(),
490 ),
491 child_value.path == entry_own.path.push_tail(idx as int),
492 child_value.parent_level == parent_owner.level(),
493 {
494 }
495
496 pub proof fn lemma_continuation_inv_holds_after_child_restore(
506 self,
507 cont_old: Self,
508 parent_old: NodeOwner<C>,
509 )
510 requires
511 cont_old.inv(),
514 cont_old.entry_own.is_node(),
515 cont_old.entry_own.node() == parent_old,
516 self.children.len() == cont_old.children.len(),
518 self.idx == cont_old.idx,
519 self.tree_level == cont_old.tree_level,
520 self.guard == cont_old.guard,
521 self.path == cont_old.path,
522 self.entry_own.is_absent() == cont_old.entry_own.is_absent(),
525 self.entry_own.path == cont_old.entry_own.path,
526 self.entry_own.parent_level == cont_old.entry_own.parent_level,
527 self.entry_own.is_node(),
529 self.entry_own.inv(),
530 self.entry_own.node().relate_guard(self.guard),
531 self.entry_own.node().level() == parent_old.level(),
532 self.entry_own.node().tree_level == parent_old.tree_level,
533 forall|j: int|
535 0 <= j < NR_ENTRIES && j != self.idx
536 ==> #[trigger] self.entry_own.node().children_perm.value()[j]
537 == parent_old.children_perm.value()[j],
538 forall|j: int|
540 0 <= j < NR_ENTRIES && j != self.idx ==> #[trigger] self.children[j]
541 == cont_old.children[j],
542 self.children.len() == NR_ENTRIES,
545 0 <= self.idx < NR_ENTRIES,
546 self.tree_level == INC_LEVELS - self.level() - 1,
547 self.tree_level < INC_LEVELS - 1,
548 self.path().len() == self.tree_level,
549 self.children[self.idx as int] is Some,
551 self.children[self.idx as int]->0.inv(),
552 self.children[self.idx as int]->0.value().parent_level == self.level(),
553 self.children[self.idx as int]->0.value().path == self.path().push_tail(
554 self.idx as int,
555 ),
556 self.children[self.idx as int]->0.level() == self.tree_level + 1,
557 self.children[self.idx as int]->0.value().path.len() == self.entry_own.node().tree_level
558 + 1,
559 self.children[self.idx as int]->0.value().match_pte(
560 self.entry_own.node().children_perm.value()[self.idx as int],
561 self.entry_own.node().level(),
562 ),
563 PageTableOwner(self.children[self.idx as int]->0).pt_inv(),
568 ensures
569 self.inv(),
570 {
571 }
572
573 pub proof fn tracked_new_child(
574 tracked &self,
575 paddr: Paddr,
576 prop: PageProperty,
577 tracked permission: Option<C::Perm>,
578 tracked regions: &mut MetaRegionOwners,
579 ) -> (tracked res: OwnerSubtree<C>)
580 requires
581 self.inv(),
582 self.level() < NR_LEVELS,
583 old(regions).slots.contains_key(frame_to_index(paddr)),
584 valid_frame_paddr(paddr),
585 paddr % page_size::<PagingConsts>(self.level()) == 0,
586 paddr + page_size::<PagingConsts>(self.level()) <= MAX_PADDR,
587 C::raw_item_well_formed((paddr, self.level(), prop, Tracked(permission))),
588 C::E::new_page_req(paddr, self.level(), prop),
589 self.path().push_tail(self.idx as int).inv(),
590 ensures
591 final(regions).slot_owners == old(regions).slot_owners,
592 final(regions).slots == old(regions).slots,
593 res.value() == EntryOwner::<C>::new_frame(
595 paddr,
596 self.path().push_tail(self.idx as int),
597 self.level(),
598 prop,
599 permission,
600 ),
601 res.inv(),
602 res.level() == self.tree_level + 1,
603 res == OwnerSubtree::new_val(res.value(), res.level() as nat),
604 {
605 let tracked mut owner = EntryOwner::<C>::tracked_new_frame(
606 paddr,
607 self.path().push_tail(self.idx as int),
608 self.level(),
609 prop,
610 permission,
611 );
612 OwnerSubtree::tracked_new_val(owner, self.tree_level + 1)
613 }
614
615 pub broadcast group group_lemmas {
616 CursorContinuation::lemma_view_mappings_contains,
617 CursorContinuation::lemma_view_mappings_intro,
618 }
619}
620
621pub tracked struct CursorOwner<'rcu, C: PageTableConfig> {
622 pub ghost level: PagingLevel,
623 pub continuations: Map<int, CursorContinuation<'rcu, C>>,
624 pub ghost va: Vaddr,
625 pub ghost barrier_va: Range<Vaddr>,
626 pub ghost guard_level: PagingLevel,
627 pub ghost prefix: Vaddr,
628 pub ghost popped_too_high: bool,
629}
630
631impl<'rcu, C: PageTableConfig> Inv for CursorOwner<'rcu, C> {
632 open spec fn inv(self) -> bool {
633 &&& self.va % C::BASE_PAGE_SIZE() == 0
634 &&& 1 <= self.level <= NR_LEVELS
635 &&& 1 <= self.guard_level
636 <= NR_LEVELS
637 &&& page_table_managed_start_spec::<C>() <= self.va <= page_table_managed_end_spec::<C>()
639 &&& self.locked_range().start <= self.barrier_va.start < self.barrier_va.end
640 <= self.locked_range().end
641 &&& self.barrier_va.start % C::BASE_PAGE_SIZE() == 0
642 &&& self.barrier_va.end % C::BASE_PAGE_SIZE() == 0
643 &&& is_valid_range_spec::<C>(self.barrier_va)
644 &&& self.barrier_va.end + page_size::<C>(self.guard_level)
645 <= page_table_coverage_end_spec::<
646 C,
647 >()
648 &&& self.popped_too_high ==> self.level >= self.guard_level
650 &&& !self.popped_too_high ==> self.level <= self.guard_level
651 || self.at_or_past_barrier_end()
652 &&& self.continuations[self.level - 1].all_some()
653 &&& forall|i: int|
654 self.level <= i < NR_LEVELS ==> {
655 (#[trigger] self.continuations[i]).all_but_index_some()
656 }
657 &&& self.level <= NR_LEVELS - 1 ==> {
658 &&& C::TOP_LEVEL_INDEX_RANGE().start <= self.continuations[NR_LEVELS - 1].idx
659 &&& self.continuations[NR_LEVELS - 1].idx < C::TOP_LEVEL_INDEX_RANGE().end
660 }
661 &&& forall|j: int|
662 #![trigger self.continuations[NR_LEVELS - 1].children[j]]
663 0 <= j < NR_ENTRIES && !(C::TOP_LEVEL_INDEX_RANGE().start <= j
664 < C::TOP_LEVEL_INDEX_RANGE().end) ==> self.continuations[NR_LEVELS
665 - 1].children[j] is Some ==> (self.continuations[NR_LEVELS
666 - 1].children[j].unwrap().value().is_borrowed() || self.continuations[NR_LEVELS
667 - 1].children[j].unwrap().value().is_absent())
668 &&& self.prefix % C::BASE_PAGE_SIZE() == 0
669 &&& self.prefix <= self.va
670 &&& forall|i: int|
671 1 <= i <= self.guard_level ==> #[trigger] pte_index_spec::<C>(
672 self.prefix,
673 i as PagingLevel,
674 ) == 0
675 &&& self.guard_level < NR_LEVELS ==> page_table_managed_start_spec::<C>() <= self.prefix
676 < page_table_managed_end_spec::<C>()
677 &&& vaddr_leading_part_spec::<C>(self.va) == vaddr_leading_part_spec::<C>(self.prefix)
678 &&& vaddr_leading_part_spec::<C>(self.prefix) == page_table_coverage_start_spec::<C>()
679 &&& self.level <= self.guard_level ==> forall|i: int|
680 #![trigger self.continuations[i].idx]
681 self.guard_level <= i < NR_LEVELS ==> self.continuations[i].idx == pte_index_spec::<C>(
682 self.prefix,
683 (i + 1) as PagingLevel,
684 )
685 &&& !self.popped_too_high && (self.in_locked_range() || self.level < self.guard_level)
686 ==> forall|i: int|
687 self.guard_level <= i < NR_LEVELS ==> #[trigger] pte_index_spec::<C>(
688 self.va,
689 (i + 1) as PagingLevel,
690 ) == pte_index_spec::<C>(self.prefix, (i + 1) as PagingLevel)
691 &&& self.level <= 4 ==> {
692 &&& self.continuations.contains_key(3)
693 &&& self.continuations[3].inv()
694 &&& self.continuations[3].level()
695 == 4
696 &&& self.continuations[3].entry_own.parent_level
698 == 5
699 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (3 + 1) as PagingLevel)
701 == self.continuations[3].idx
702 }
703 &&& self.level <= 3 ==> {
704 &&& self.continuations.contains_key(2)
705 &&& self.continuations[2].inv()
706 &&& self.continuations[2].level() == 3
707 &&& self.continuations[2].entry_own.parent_level == 4
708 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (2 + 1) as PagingLevel)
709 == self.continuations[2].idx
710 &&& self.continuations[2].guard.inner.inner@.slot_vaddr()
711 != self.continuations[3].guard.inner.inner@.slot_vaddr()
712 &&& self.continuations[2].path() == self.continuations[3].path().push_tail(
714 self.continuations[3].idx as int,
715 )
716 &&& self.continuations[2].entry_own.path.len()
718 == self.continuations[3].entry_own.node().tree_level + 1
719 &&& self.continuations[2].entry_own.match_pte(
720 self.continuations[3].entry_own.node().children_perm.value()[self.continuations[3].idx as int],
721 self.continuations[3].entry_own.node().level(),
722 )
723 &&& self.continuations[2].entry_own.parent_level
724 == self.continuations[3].entry_own.node().level()
725 }
726 &&& self.level <= 2 ==> {
727 &&& self.continuations.contains_key(1)
728 &&& self.continuations[1].inv()
729 &&& self.continuations[1].level() == 2
730 &&& self.continuations[1].entry_own.parent_level == 3
731 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (1 + 1) as PagingLevel)
732 == self.continuations[1].idx
733 &&& self.continuations[1].guard.inner.inner@.slot_vaddr()
734 != self.continuations[2].guard.inner.inner@.slot_vaddr()
735 &&& self.continuations[1].guard.inner.inner@.slot_vaddr()
736 != self.continuations[3].guard.inner.inner@.slot_vaddr()
737 &&& self.continuations[1].path() == self.continuations[2].path().push_tail(
739 self.continuations[2].idx as int,
740 )
741 &&& self.continuations[1].entry_own.path.len()
743 == self.continuations[2].entry_own.node().tree_level + 1
744 &&& self.continuations[1].entry_own.match_pte(
745 self.continuations[2].entry_own.node().children_perm.value()[self.continuations[2].idx as int],
746 self.continuations[2].entry_own.node().level(),
747 )
748 &&& self.continuations[1].entry_own.parent_level
749 == self.continuations[2].entry_own.node().level()
750 }
751 &&& self.level == 1 ==> {
752 &&& self.continuations.contains_key(0)
753 &&& self.continuations[0].inv()
754 &&& self.continuations[0].level() == 1
755 &&& self.continuations[0].entry_own.parent_level == 2
756 &&& self.in_locked_range() ==> pte_index_spec::<C>(self.va, (0 + 1) as PagingLevel)
757 == self.continuations[0].idx
758 &&& self.continuations[0].guard.inner.inner@.slot_vaddr()
759 != self.continuations[1].guard.inner.inner@.slot_vaddr()
760 &&& self.continuations[0].guard.inner.inner@.slot_vaddr()
761 != self.continuations[2].guard.inner.inner@.slot_vaddr()
762 &&& self.continuations[0].guard.inner.inner@.slot_vaddr()
763 != self.continuations[3].guard.inner.inner@.slot_vaddr()
764 &&& self.continuations[0].path() == self.continuations[1].path().push_tail(
766 self.continuations[1].idx as int,
767 )
768 &&& self.continuations[0].entry_own.path.len()
770 == self.continuations[1].entry_own.node().tree_level + 1
771 &&& self.continuations[0].entry_own.match_pte(
772 self.continuations[1].entry_own.node().children_perm.value()[self.continuations[1].idx as int],
773 self.continuations[1].entry_own.node().level(),
774 )
775 &&& self.continuations[0].entry_own.parent_level
776 == self.continuations[1].entry_own.node().level()
777 }
778 }
779}
780
781impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
782 pub open spec fn node_unlocked(guards: Guards) -> (spec_fn(
783 EntryOwner<C>,
784 TreePath<NR_ENTRIES>,
785 ) -> bool) {
786 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
787 owner.is_node() ==> guards.unlocked(owner.node().slot_vaddr())
788 }
789
790 pub open spec fn node_unlocked_except(guards: Guards, addr: usize) -> (spec_fn(
791 EntryOwner<C>,
792 TreePath<NR_ENTRIES>,
793 ) -> bool) {
794 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
795 owner.is_node() ==> owner.node().slot_vaddr() != addr ==> guards.unlocked(
796 owner.node().slot_vaddr(),
797 )
798 }
799
800 pub open spec fn map_full_tree(
801 self,
802 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
803 ) -> bool {
804 forall|i: int|
805 #![trigger self.continuations[i]]
806 self.level - 1 <= i < NR_LEVELS ==> { self.continuations[i].map_children(f) }
807 }
808
809 pub open spec fn children_not_locked(self, guards: Guards) -> bool {
810 self.map_full_tree(Self::node_unlocked(guards))
811 }
812
813 pub proof fn lemma_children_not_locked_unroll(self, guards: Guards)
814 requires
815 self.children_not_locked(guards),
816 ensures
817 forall|i: int|
818 #![trigger self.continuations[i]]
819 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(
820 Self::node_unlocked(guards),
821 ),
822 {
823 }
824
825 pub open spec fn only_current_locked(self, guards: Guards) -> bool {
826 self.map_full_tree(
827 Self::node_unlocked_except(guards, self.cur_entry_owner().node().slot_vaddr()),
828 )
829 }
830
831 pub proof fn lemma_never_drop_restores_children_not_locked(
832 self,
833 guard: PageTableGuard<'rcu, C>,
834 guards0: Guards,
835 guards1: Guards,
836 )
837 requires
838 self.inv(),
839 self.only_current_locked(guards0),
840 guards0.lock_held(guard.inner.inner@.slot_vaddr()),
841 guards1.guards == guards0.guards.remove(guard.inner.inner@.slot_vaddr()),
842 self.cur_entry_owner().is_node(),
843 guard.inner.inner@.slot_vaddr() == self.cur_entry_owner().node().slot_vaddr(),
844 ensures
845 self.children_not_locked(guards1),
846 {
847 let current_addr = self.cur_entry_owner().node().slot_vaddr();
848 let f = Self::node_unlocked_except(guards0, current_addr);
849 let g = Self::node_unlocked(guards1);
850
851 self.lemma_map_children_implies(f, g);
852 }
853
854 pub open spec fn nodes_locked(self, guards: Guards) -> bool {
855 forall|i: int|
856 #![trigger self.continuations[i]]
857 self.level - 1 <= i < self.guard_level ==> { self.continuations[i].node_locked(guards) }
858 }
859
860 pub open spec fn index(self) -> usize {
861 self.continuations[self.level - 1].idx
862 }
863
864 pub open spec fn inc_index(self) -> Self {
865 Self {
866 continuations: self.continuations.insert(
867 self.level - 1,
868 self.continuations[self.level - 1].inc_index(),
869 ),
870 va: vaddr_replace_pte_index_spec::<C>(
871 self.va,
872 self.level,
873 self.continuations[self.level - 1].inc_index().idx as int,
874 ),
875 popped_too_high: false,
876 ..self
877 }
878 }
879
880 #[verifier::spinoff_prover]
882 pub proof fn do_inc_index_and_zero(tracked &mut self)
883 requires
884 old(self).inv(),
885 old(self).level <= old(self).guard_level,
886 old(self).in_barrier_va(),
887 old(self).continuations[old(self).level - 1].idx + 1 < NR_ENTRIES,
888 old(self).level == NR_LEVELS ==> (old(self).continuations[old(self).level - 1].idx + 1)
889 <= C::TOP_LEVEL_INDEX_RANGE().end,
890 ensures
891 final(self).inv(),
892 *final(self) == old(self).inc_index().zero_below_level(),
893 {
894 C::lemma_paging_consts_properties();
895 C::axiom_current_paging_consts_hardcoded();
896 lemma_page_table_managed_index_bounds::<C>(old(self).va);
897 lemma_inc_slot_indices::<C>(old(self).va, old(self).level);
898 old(self).lemma_inc_index_va();
899 old(self).inc_and_zero_increases_va();
900 lemma_align_down_indices::<C>(old(self).inc_index().va, old(self).level);
901 lemma_page_size_divides::<C>(old(self).level, C::NR_LEVELS());
902 lemma_nat_align_down_within_block(
903 old(self).va as nat,
904 page_size::<C>(old(self).level) as nat,
905 page_size::<C>(C::NR_LEVELS()) as nat,
906 );
907 self.popped_too_high = false;
908 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
909 cont.do_inc_index();
910 self.va = old(self).inc_index().zero_below_level().va;
911 lemma_page_table_managed_index_bounds::<C>(self.va);
912 self.continuations.tracked_insert(self.level - 1, cont);
913 assert(self.continuations == old(self).continuations.insert(self.level - 1, cont));
914 if self.in_barrier_va() {
915 old(self).lemma_barrier_va_bounds(self.va);
916 }
917 }
918
919 pub proof fn lemma_inv_continuation(self, i: int)
920 requires
921 self.inv(),
922 self.level - 1 <= i <= NR_LEVELS - 1,
923 ensures
924 self.continuations.contains_key(i),
925 self.continuations[i].inv(),
926 self.continuations[i].children.len() == NR_ENTRIES,
927 {
928 }
929
930 pub open spec fn view_mappings(self) -> Set<Mapping> {
931 self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS).map_values(
932 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
933 ).values().flatten()
934 }
935
936 pub broadcast proof fn lemma_view_mappings_contains(self)
937 requires
938 1 <= self.level <= NR_LEVELS,
939 ensures
940 #![trigger self.view_mappings()]
941 forall|m: Mapping| #[trigger]
942 self.view_mappings().contains(m) ==> exists|i: int|
943 #![trigger self.continuations[i]]
944 self.level - 1 <= i < NR_LEVELS
945 && self.continuations[i].view_mappings().contains(m),
946 {
947 broadcast use vstd::map_lib::group_map_properties;
948
949 }
950
951 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
952 requires
953 1 <= self.level <= NR_LEVELS,
954 self.level - 1 <= i < NR_LEVELS,
955 self.continuations.contains_key(i),
956 #[trigger] self.continuations[i].view_mappings().contains(m),
957 ensures
958 self.view_mappings().contains(m),
959 {
960 broadcast use vstd::map_lib::group_map_properties;
961
962 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
963 let mapped = filtered.map_values(|cont: CursorContinuation<'rcu, C>| cont.view_mappings());
964 let values = mapped.values();
965 assert(values.contains(mapped[i]));
966 }
967
968 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
969 if self.level == 1 {
970 let l1 = self.continuations[0];
971 let l2 = self.continuations[1].restore(l1).0;
972 let l3 = self.continuations[2].restore(l2).0;
973 let l4 = self.continuations[3].restore(l3).0;
974 l4.as_page_table_owner()
975 } else if self.level == 2 {
976 let l2 = self.continuations[1];
977 let l3 = self.continuations[2].restore(l2).0;
978 let l4 = self.continuations[3].restore(l3).0;
979 l4.as_page_table_owner()
980 } else if self.level == 3 {
981 let l3 = self.continuations[2];
982 let l4 = self.continuations[3].restore(l3).0;
983 l4.as_page_table_owner()
984 } else {
985 let l4 = self.continuations[3];
986 l4.as_page_table_owner()
987 }
988 }
989
990 pub open spec fn cur_entry_owner(self) -> EntryOwner<C> {
991 self.cur_subtree().value()
992 }
993
994 pub open spec fn cur_subtree(self) -> OwnerSubtree<C> {
995 self.continuations[self.level - 1].children[self.index() as int]->0
996 }
997
998 pub proof fn lemma_cur_frame_clone_requires(
1000 self,
1001 item: C::Item,
1002 pa: Paddr,
1003 level: PagingLevel,
1004 prop: PageProperty,
1005 regions: MetaRegionOwners,
1006 )
1007 requires
1008 self.inv(),
1009 regions.inv(),
1010 self.metaregion_sound(regions),
1011 self.cur_entry_owner().is_frame(),
1012 pa == self.cur_entry_owner().frame().mapped_pa,
1013 C::item_from_raw(pa, level, prop, C::item_into_raw(item).3) == item,
1014 C::item_into_raw(item).3@ == self.cur_entry_owner().frame_permission(),
1015 valid_frame_paddr(pa),
1016 C::raw_item_well_formed((pa, level, prop, C::item_into_raw(item).3)),
1017 (C::item_into_raw(item).3@ is Some) == self.cur_entry_owner().frame_is_tracked(),
1019 C::item_into_raw(item).3@ is Some ==> (regions.slot_owner(pa).ref_count()
1021 < REF_COUNT_MAX || may_panic()),
1022 ensures
1023 item.clone_requires(regions),
1024 {
1025 let cont = self.continuations[self.level - 1];
1026 cont.lemma_map_children_unroll(
1027 PageTableOwner::<C>::metaregion_sound_pred(regions),
1028 cont.idx as int,
1029 );
1030 C::lemma_clone_requires_concrete(item, pa, level, prop, regions);
1031 }
1032
1033 pub proof fn lemma_clone_item_preserves_invariants(
1036 self,
1037 old_regions: MetaRegionOwners,
1038 new_regions: MetaRegionOwners,
1039 idx: int,
1040 )
1041 requires
1042 self.inv(),
1043 self.metaregion_sound(old_regions),
1044 old_regions.inv(),
1045 self.cur_entry_owner().is_frame(),
1046 idx == frame_to_index(self.cur_entry_owner().frame().mapped_pa),
1047 old_regions.slot_owners.contains_key(idx),
1048 new_regions.slot_owners.contains_key(idx),
1049 new_regions.ref_count(idx) == old_regions.ref_count(idx) + 1,
1051 new_regions.slot_owners[idx].ref_count_perm.id()
1053 == old_regions.slot_owners[idx].ref_count_perm.id(),
1054 new_regions.slot_owners[idx].metadata_perm.id()
1055 == old_regions.slot_owners[idx].metadata_perm.id(),
1056 new_regions.slot_owners[idx].metadata_perm.frac() + 1
1057 == old_regions.slot_owners[idx].metadata_perm.frac(),
1058 new_regions.slot_owners[idx].in_list_perm == old_regions.slot_owners[idx].in_list_perm,
1059 new_regions.slot_owners[idx].paths_in_pt == old_regions.slot_owners[idx].paths_in_pt,
1061 new_regions.slot_owners[idx].slot_vaddr == old_regions.slot_owners[idx].slot_vaddr,
1062 new_regions.slot_owners[idx].usage == old_regions.slot_owners[idx].usage,
1063 new_regions.slot_owners.dom() == old_regions.slot_owners.dom(),
1065 forall|i: int|
1066 #![trigger new_regions.slot_owners[i]]
1067 i != idx && old_regions.slot_owners.contains_key(i) ==> new_regions.slot_owners[i]
1068 == old_regions.slot_owners[i],
1069 new_regions.slots == old_regions.slots,
1071 new_regions.inv(),
1072 0 < old_regions.ref_count(idx),
1078 old_regions.ref_count(idx) + 1 <= REF_COUNT_MAX,
1079 ensures
1080 new_regions.inv(),
1081 self.metaregion_sound(new_regions),
1082 {
1083 self.lemma_metaregion_slot_owners_rc_increment(old_regions, new_regions, idx);
1084 }
1085
1086 pub proof fn lemma_new_child_mappings_eq_target(
1089 self,
1090 new_subtree: OwnerSubtree<C>,
1091 pa: Paddr,
1092 level: PagingLevel,
1093 prop: PageProperty,
1094 )
1095 requires
1096 self.inv(),
1097 self.in_barrier_va(),
1098 level == self.level,
1099 new_subtree.inv(),
1100 new_subtree.value().is_frame(),
1101 new_subtree.value().path == self.continuations[self.level - 1].path().push_tail(
1102 self.continuations[self.level - 1].idx as int,
1103 ),
1104 new_subtree.value().frame().mapped_pa == pa,
1105 new_subtree.value().frame().prop == prop,
1106 ensures
1107 PageTableOwner(new_subtree)@.mappings
1108 == set![Mapping {
1109 va_range: self@.cur_slot_range(page_size::<PagingConsts>(level)),
1110 pa_range: pa..(pa + page_size::<PagingConsts>(level)) as usize,
1111 page_size: page_size::<PagingConsts>(level),
1112 property: prop,
1113 }],
1114 {
1115 self.cur_va_in_subtree_range();
1116 }
1117
1118 pub open spec fn locked_range(self) -> Range<int> {
1121 let size = page_size::<C>((self.guard_level + 1) as PagingLevel) as int;
1122 Range { start: self.prefix as int, end: self.prefix as int + size }
1123 }
1124
1125 pub open spec fn in_locked_range(self) -> bool {
1127 self.locked_range().start <= self.va < self.locked_range().end
1128 }
1129
1130 pub open spec fn in_barrier_va(self) -> bool {
1132 self.barrier_va.start <= self.va < self.barrier_va.end
1133 }
1134
1135 pub open spec fn at_or_past_barrier_end(self) -> bool {
1137 self.va >= self.barrier_va.end
1138 }
1139
1140 pub proof fn lemma_in_barrier_va_top_index_bounds(self)
1142 requires
1143 self.inv(),
1144 self.in_barrier_va(),
1145 !self.popped_too_high,
1146 ensures
1147 C::TOP_LEVEL_INDEX_RANGE().start <= pte_index_spec::<C>(self.va, C::NR_LEVELS())
1148 < C::TOP_LEVEL_INDEX_RANGE().end,
1149 {
1150 self.lemma_barrier_va_bounds(self.va);
1151 }
1152
1153 pub proof fn lemma_in_barrier_va_level_le_guard_level(self)
1154 requires
1155 self.inv(),
1156 self.in_barrier_va(),
1157 !self.popped_too_high,
1158 ensures
1159 self.level <= self.guard_level,
1160 {
1161 }
1162
1163 pub proof fn lemma_locked_range_span(self)
1165 requires
1166 self.inv(),
1167 ensures
1168 self.locked_range().start == self.prefix,
1169 self.locked_range().end == self.prefix + page_size::<PagingConsts>(
1170 (self.guard_level + 1) as PagingLevel,
1171 ),
1172 self.prefix % page_size::<PagingConsts>((self.guard_level + 1) as PagingLevel) == 0,
1173 {
1174 C::lemma_paging_consts_properties();
1175 C::axiom_current_paging_consts_hardcoded();
1176 lemma_lower_indices_aligned::<C>(self.prefix, (self.guard_level + 1) as PagingLevel);
1177 }
1178
1179 pub proof fn lemma_prefix_aligned_to_guard_level(self)
1180 requires
1181 self.inv(),
1182 ensures
1183 self.prefix as nat % page_size::<PagingConsts>(self.guard_level) as nat == 0,
1184 {
1185 C::lemma_paging_consts_properties();
1186 C::axiom_current_paging_consts_hardcoded();
1187 lemma_lower_indices_aligned::<C>(self.prefix, self.guard_level);
1188 }
1189
1190 pub proof fn lemma_in_node_holds_at_top(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1193 requires
1194 self.inv(),
1195 self_va == self.va,
1196 self.guard_level == NR_LEVELS,
1197 node_size == page_size::<PagingConsts>((NR_LEVELS + 1) as PagingLevel),
1198 self.locked_range().start <= va < self.locked_range().end,
1199 ensures
1200 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1201 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1202 {
1203 C::lemma_paging_consts_properties();
1204 C::axiom_current_paging_consts_hardcoded();
1205 self.lemma_locked_range_span();
1206 let body_level = (C::NR_LEVELS() + 1) as PagingLevel;
1207 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(body_level);
1208 lemma_page_size_next::<C>(self.guard_level);
1209 lemma_usize_shr_is_div(self_va, nr_page_table_coverage_bits_spec::<C>());
1210 lemma_fundamental_div_mod(self_va as int, node_size as int);
1211 lemma_mul_is_commutative(self_va as int / node_size as int, node_size as int);
1212 lemma_nat_align_down_sound(self_va as nat, node_size as nat);
1213 assert(nat_align_down(self_va as nat, node_size as nat) == vaddr_leading_part_spec::<C>(
1214 self_va,
1215 ));
1216
1217 lemma_vaddr_leading_part_is_align_down::<C>(self_va);
1218 lemma_vaddr_leading_part_is_align_down::<C>(self.prefix);
1219 lemma_lower_indices_aligned::<C>(self.prefix, body_level);
1220 lemma_usize_shr_is_div(self.prefix, nr_page_table_coverage_bits_spec::<C>());
1221 lemma_fundamental_div_mod(self.prefix as int, node_size as int);
1222 assert(nat_align_down(self_va as nat, node_size as nat) == self.prefix);
1223 }
1224
1225 pub proof fn lemma_va_plus_page_size_no_overflow(self, level: PagingLevel)
1227 requires
1228 self.inv(),
1229 self.in_barrier_va(),
1230 1 <= level <= self.guard_level,
1231 ensures
1232 self.va + page_size::<PagingConsts>(level) <= usize::MAX,
1233 self.va + page_size::<PagingConsts>(level) < page_table_coverage_end_spec::<C>(),
1234 {
1235 C::lemma_paging_consts_properties();
1236 C::axiom_current_paging_consts_hardcoded();
1237 lemma_leading_bits_properties::<C>();
1238 lemma_page_size_is_pow2_pte_index_bit_offset::<C>((C::NR_LEVELS() + 1) as PagingLevel);
1239 lemma_page_size_monotone::<C>(level, self.guard_level);
1240 vstd::arithmetic::power2::lemma2_to64();
1241 vstd::layout::unsigned_int_max_values();
1242 }
1243
1244 pub proof fn lemma_locked_range_page_aligned(self)
1245 requires
1246 self.inv(),
1247 ensures
1248 self.locked_range().end % (PAGE_SIZE as int) == 0,
1249 self.locked_range().start % (PAGE_SIZE as int) == 0,
1250 {
1251 self.lemma_locked_range_span();
1252 lemma_page_size_base::<PagingConsts>();
1253 C::lemma_paging_consts_properties();
1254 C::axiom_current_paging_consts_hardcoded();
1255 lemma_page_size_divides::<PagingConsts>(1, (self.guard_level + 1) as PagingLevel);
1256 lemma_fundamental_div_mod(
1257 page_size::<PagingConsts>((self.guard_level + 1) as PagingLevel) as int,
1258 PAGE_SIZE as int,
1259 );
1260 assert(self.locked_range().start % (PAGE_SIZE as int) == 0);
1261 assert(page_size::<PagingConsts>((self.guard_level + 1) as PagingLevel) % PAGE_SIZE == 0);
1262 vstd::arithmetic::div_mod::lemma_add_mod_noop(
1263 self.prefix as int,
1264 page_size::<PagingConsts>((self.guard_level + 1) as PagingLevel) as int,
1265 PAGE_SIZE as int,
1266 );
1267 }
1268
1269 pub proof fn lemma_cur_subtree_inv(self)
1270 requires
1271 self.inv(),
1272 ensures
1273 self.cur_subtree().inv(),
1274 {
1275 let cont = self.continuations[self.level - 1];
1276 cont.lemma_inv_children_unroll(cont.idx as int)
1277 }
1278
1279 pub proof fn tracked_new_absent_subtree(self) -> (tracked res: OwnerSubtree<C>)
1281 requires
1282 self.inv(),
1283 ensures
1284 res.inv(),
1285 res.value().is_absent(),
1286 res.level() == self.continuations[self.level - 1].tree_level + 1,
1287 res.value().path.len() <= INC_LEVELS - 1,
1288 res.value().parent_level == self.continuations[self.level
1289 - 1].child().value().parent_level,
1290 res.value().path == self.continuations[self.level - 1].path().push_tail(
1291 self.continuations[self.level - 1].idx as int,
1292 ),
1293 res == OwnerSubtree::new_val(res.value(), res.level() as nat),
1294 {
1295 let cont = self.continuations[self.level - 1];
1296 self.lemma_inv_continuation(self.level - 1);
1297
1298 cont.lemma_inv_children_unroll(cont.idx as int);
1299 cont.lemma_inv_children_rel_unroll(cont.idx as int);
1300
1301 let tracked entry = EntryOwner::tracked_new_absent(self.cur_entry_owner().path, self.level);
1302
1303 let tracked subtree = OwnerSubtree::tracked_new_val(entry, cont.tree_level + 1);
1304 subtree
1305 }
1306
1307 pub proof fn lemma_cur_entry_absent_not_present(self)
1309 requires
1310 self.inv(),
1311 self.in_barrier_va(),
1312 self.cur_entry_owner().is_absent(),
1313 ensures
1314 !self@.present(),
1315 {
1316 let cur_va = self.cur_va();
1317
1318 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1319 <= cur_va < m.va_range.end) by {
1320 if m.va_range.start <= cur_va < m.va_range.end {
1321 self.mapping_covering_cur_va_from_cur_subtree(m);
1322 }
1323 };
1324
1325 let filtered = self@.mappings.filter(
1326 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1327 );
1328 assert(filtered == set![]) by {};
1329 }
1330
1331 pub proof fn lemma_cur_subtree_empty_not_present(self)
1333 requires
1334 self.inv(),
1335 self.in_barrier_va(),
1336 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value().path) =~= set![],
1337 ensures
1338 !self@.present(),
1339 {
1340 let cur_va = self.cur_va();
1341
1342 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1343 <= cur_va < m.va_range.end) by {
1344 if m.va_range.start <= cur_va < m.va_range.end {
1345 self.mapping_covering_cur_va_from_cur_subtree(m);
1346 }
1347 };
1348
1349 let filtered = self@.mappings.filter(
1350 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1351 );
1352 assert(filtered == set![]) by {};
1353 }
1354
1355 pub proof fn lemma_cur_entry_frame_present(self)
1356 requires
1357 self.inv(),
1358 self.in_barrier_va(),
1359 self.cur_entry_owner().is_frame(),
1360 ensures
1361 self@.present(),
1362 self@.query(
1363 self.cur_entry_owner().frame().mapped_pa,
1364 page_size::<PagingConsts>(self.cur_entry_owner().parent_level),
1365 self.cur_entry_owner().frame().prop,
1366 ),
1367 {
1368 self.view_preserves_inv();
1369 let subtree = self.cur_subtree();
1370 let path = subtree.value().path;
1371 let frame = self.cur_entry_owner().frame();
1372 let pt_level = INC_LEVELS - path.len();
1373 let cont = self.continuations[self.level - 1];
1374
1375 let m = Mapping {
1376 va_range: Range {
1377 start: vaddr_of::<C>(path) as int,
1378 end: vaddr_of::<C>(path) + page_size::<PagingConsts>(pt_level as PagingLevel),
1379 },
1380 pa_range: Range {
1381 start: frame.mapped_pa,
1382 end: (frame.mapped_pa + page_size::<PagingConsts>(
1383 pt_level as PagingLevel,
1384 )) as Paddr,
1385 },
1386 page_size: page_size::<PagingConsts>(pt_level as PagingLevel),
1387 property: frame.prop,
1388 };
1389 cont.lemma_view_mappings_intro(m, cont.idx as int);
1390 self.lemma_view_mappings_intro(m, self.level - 1);
1391 assert(m.va_range.start <= self@.cur_va < m.va_range.end) by {
1392 self.cur_va_in_subtree_range();
1393 };
1394
1395 let filtered = self@.mappings.filter(
1396 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
1397 );
1398 lemma_set_contains_len(filtered, m);
1399 let queried = self@.query_mapping();
1401 assert(filtered.contains(queried));
1402 assert(queried == m);
1403 }
1404
1405 #[verifier::opaque]
1407 pub open spec fn path_metaregion_sound(self, regions: MetaRegionOwners) -> bool {
1408 forall|i: int|
1409 #![trigger self.continuations[i]]
1410 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].entry_own.metaregion_sound(
1411 regions,
1412 )
1413 }
1414
1415 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
1416 &&& self.map_full_tree(
1417 |entry_owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1418 entry_owner.metaregion_sound(regions),
1419 )
1420 &&& self.path_metaregion_sound(regions)
1421 }
1422
1423 pub proof fn lemma_metaregion_preserved(
1424 self,
1425 other: Self,
1426 regions0: MetaRegionOwners,
1427 regions1: MetaRegionOwners,
1428 )
1429 requires
1430 self.inv(),
1431 self.metaregion_sound(regions0),
1432 self.level == other.level,
1433 self.continuations =~= other.continuations,
1434 OwnerSubtree::implies(
1435 PageTableOwner::<C>::metaregion_sound_pred(regions0),
1436 PageTableOwner::<C>::metaregion_sound_pred(regions1),
1437 ),
1438 ensures
1439 other.metaregion_sound(regions1),
1440 {
1441 let f = PageTableOwner::metaregion_sound_pred(regions0);
1442 let g = PageTableOwner::metaregion_sound_pred(regions1);
1443
1444 assert forall|i: int| #![auto] self.level - 1 <= i < NR_LEVELS implies {
1445 other.continuations[i].map_children(g)
1446 } by {
1447 reveal(CursorContinuation::map_children);
1448 let cont = self.continuations[i];
1449 assert forall|j: int|
1450 0 <= j < NR_ENTRIES
1451 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
1452 cont.path().push_tail(j), g) by {
1453 cont.children[j].unwrap().lemma_subtree_satisfies_implies(
1454 cont.path().push_tail(j),
1455 f,
1456 g,
1457 );
1458 };
1459 };
1460 assert(other.path_metaregion_sound(regions1)) by {
1461 reveal(CursorOwner::path_metaregion_sound);
1462 assert forall|i: int|
1463 #![trigger other.continuations[i]]
1464 self.level - 1 <= i
1465 < NR_LEVELS implies other.continuations[i].entry_own.metaregion_sound(
1466 regions1,
1467 ) by {
1468 let eo = self.continuations[i].entry_own;
1469 assert(g(eo, self.continuations[i].path()));
1470 };
1471 };
1472 }
1473
1474 pub proof fn lemma_metaregion_slot_owners_preserved(
1476 self,
1477 regions0: MetaRegionOwners,
1478 regions1: MetaRegionOwners,
1479 )
1480 requires
1481 self.inv(),
1482 self.metaregion_sound(regions0),
1483 regions0.slot_owners =~= regions1.slot_owners,
1484 forall|k: int|
1485 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
1486 forall|k: int|
1487 regions0.slots.contains_key(k) ==> regions0.slots[k]
1488 == #[trigger] regions1.slots[k],
1489 ensures
1490 self.metaregion_sound(regions1),
1491 {
1492 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
1493 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
1494 assert(OwnerSubtree::implies(f, g)) by {
1495 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1496 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
1497 entry.metaregion_sound_slot_owners_only(regions0, regions1);
1498 };
1499 };
1500 self.lemma_metaregion_preserved(self, regions0, regions1);
1501 }
1502
1503 pub proof fn lemma_metaregion_slot_owners_rc_increment(
1504 self,
1505 regions0: MetaRegionOwners,
1506 regions1: MetaRegionOwners,
1507 idx: int,
1508 )
1509 requires
1510 self.inv(),
1511 self.metaregion_sound(regions0),
1512 regions0.inv(),
1513 regions1.slots == regions0.slots,
1514 regions1.slot_owners.dom() == regions0.slot_owners.dom(),
1515 regions1.ref_count(idx) == regions0.ref_count(idx) + 1,
1516 regions1.slot_owners[idx].ref_count_perm.id()
1517 == regions0.slot_owners[idx].ref_count_perm.id(),
1518 regions1.slot_owners[idx].metadata_perm.id()
1519 == regions0.slot_owners[idx].metadata_perm.id(),
1520 regions1.slot_owners[idx].metadata_perm.frac() + 1
1521 == regions0.slot_owners[idx].metadata_perm.frac(),
1522 regions1.slot_owners[idx].in_list_perm == regions0.slot_owners[idx].in_list_perm,
1523 regions1.slot_owners[idx].paths_in_pt == regions0.slot_owners[idx].paths_in_pt,
1524 regions1.slot_owners[idx].slot_vaddr == regions0.slot_owners[idx].slot_vaddr,
1525 regions1.slot_owners[idx].usage == regions0.slot_owners[idx].usage,
1526 regions1.ref_count(idx) != REF_COUNT_UNUSED,
1527 regions1.ref_count(idx) <= REF_COUNT_MAX,
1529 regions1.inv(),
1530 forall|i: int|
1531 #![trigger regions1.slot_owners[i]]
1532 i != idx && regions0.slot_owners.contains_key(i) ==> regions1.slot_owners[i]
1533 == regions0.slot_owners[i],
1534 ensures
1535 self.metaregion_sound(regions1),
1536 {
1537 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
1538 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
1539 assert(OwnerSubtree::implies(f, g)) by {
1540 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1541 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
1542 if entry.is_frame() {
1543 let pa = entry.frame().mapped_pa;
1544 C::lemma_perm_well_formed_with_region_preserved(
1545 pa,
1546 Tracked(entry.frame_permission()),
1547 regions0,
1548 regions1,
1549 );
1550 }
1551 };
1552 };
1553 self.lemma_metaregion_preserved(self, regions0, regions1);
1554 }
1555
1556 pub proof fn lemma_cont_entry_metaregion_at(self, regions: MetaRegionOwners, i: int)
1558 requires
1559 self.inv(),
1560 self.metaregion_sound(regions),
1561 self.level - 1 <= i < NR_LEVELS,
1562 ensures
1563 self.continuations[i].entry_own.metaregion_sound(regions),
1564 {
1565 reveal(CursorOwner::path_metaregion_sound);
1566 }
1567
1568 pub open spec fn new(
1569 owner_subtree: OwnerSubtree<C>,
1570 barrier_va: Range<Vaddr>,
1571 guard: PageTableGuard<'rcu, C>,
1572 ) -> Self {
1573 let va = barrier_va.start;
1574 let idx = pte_index_spec::<C>(va, C::NR_LEVELS());
1575 Self {
1576 level: C::NR_LEVELS(),
1577 continuations: Map::empty().insert(
1578 C::NR_LEVELS() - 1,
1579 CursorContinuation::new(owner_subtree, idx, guard),
1580 ),
1581 va,
1582 barrier_va,
1583 guard_level: C::NR_LEVELS(),
1584 prefix: nat_align_down(
1585 va as nat,
1586 page_size::<C>((C::NR_LEVELS() + 1) as PagingLevel) as nat,
1587 ) as Vaddr,
1588 popped_too_high: false,
1589 }
1590 }
1591
1592 pub proof fn tracked_new(
1593 tracked owner_subtree: OwnerSubtree<C>,
1594 barrier_va: Range<Vaddr>,
1595 guard: PageTableGuard<'rcu, C>,
1596 ) -> tracked Self
1597 returns
1598 Self::new(owner_subtree, barrier_va, guard),
1599 {
1600 let ghost va = barrier_va.start;
1601 let ghost idx = pte_index_spec::<C>(va, C::NR_LEVELS());
1602 let tracked continuation = CursorContinuation::tracked_new(owner_subtree, idx, guard);
1603 let tracked mut continuations = Map::tracked_empty();
1604 continuations.tracked_insert(C::NR_LEVELS() - 1, continuation);
1605 Self {
1606 level: C::NR_LEVELS(),
1607 continuations,
1608 va,
1609 barrier_va,
1610 guard_level: C::NR_LEVELS(),
1611 prefix: nat_align_down(
1612 va as nat,
1613 page_size::<C>((C::NR_LEVELS() + 1) as PagingLevel) as nat,
1614 ) as Vaddr,
1615 popped_too_high: false,
1616 }
1617 }
1618
1619 pub broadcast group group_lemmas {
1620 CursorOwner::lemma_view_mappings_contains,
1621 CursorOwner::lemma_view_mappings_intro,
1622 }
1623}
1624
1625pub ghost struct CursorView<C: PageTableConfig> {
1626 pub cur_va: Vaddr,
1627 pub mappings: Set<Mapping>,
1628 pub phantom: PhantomData<C>,
1629}
1630
1631impl<'rcu, C: PageTableConfig> View for CursorOwner<'rcu, C> {
1632 type V = CursorView<C>;
1633
1634 open spec fn view(&self) -> Self::V {
1635 CursorView { cur_va: self.cur_va(), mappings: self.view_mappings(), phantom: PhantomData }
1636 }
1637}
1638
1639impl<C: PageTableConfig> Inv for CursorView<C> {
1640 open spec fn inv(self) -> bool {
1641 &&& mappings_well_formed(
1642 self.mappings,
1643 )
1644 &&& forall|m: Mapping|
1649 #![auto]
1650 self.mappings.contains(m) ==> {
1651 &&& page_table_managed_start_spec::<C>() <= m.va_range.start
1652 &&& m.va_range.end <= page_table_managed_end_spec::<C>()
1653 }
1654 &&& self.non_overlapping()
1655 }
1656}
1657
1658impl<C: PageTableConfig> CursorView<C> {
1659 pub open spec fn non_overlapping(self) -> bool {
1662 mappings_disjoint_vaddrs(self.mappings)
1663 }
1664}
1665
1666pub proof fn lemma_view_in_vaddr_range<'rcu, C: PageTableConfig>(owner: &CursorOwner<'rcu, C>)
1669 requires
1670 owner.inv(),
1671 ensures
1672 forall|m: Mapping|
1673 #![auto]
1674 owner.view_mappings().contains(m) ==> {
1675 &&& page_table_managed_start_spec::<C>() <= m.va_range.start
1676 &&& m.va_range.end <= page_table_managed_end_spec::<C>()
1677 },
1678{
1679 C::lemma_paging_consts_properties();
1680 C::axiom_current_paging_consts_hardcoded();
1681 C::lemma_page_table_config_constant_properties();
1682 lemma_arch_specific_consts_properties::<C>();
1683
1684 lemma_page_table_managed_bounds::<C>();
1685 let end = C::TOP_LEVEL_INDEX_RANGE().end as int;
1686
1687 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
1688 &&& page_table_managed_start_spec::<C>() <= m.va_range.start
1689 &&& m.va_range.end <= page_table_managed_end_spec::<C>()
1690 } by {
1691 let i = choose|i: int|
1692 owner.level - 1 <= i < NR_LEVELS && (
1693 #[trigger] owner.continuations[i]).view_mappings().contains(m);
1694 let cont = owner.continuations[i];
1695 let j = choose|j: int|
1696 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
1697 cont.children[j].unwrap(),
1698 ).view_rec(cont.path().push_tail(j)).contains(m);
1699 let child = PageTableOwner(cont.children[j].unwrap());
1700 let p = cont.path().push_tail(j);
1701 let pidx = p[0] as int;
1702 child.lemma_view_rec_top_index_va_bound(p, m, end);
1703 lemma_mul_inequality(
1704 C::TOP_LEVEL_INDEX_RANGE().start as int,
1705 pidx,
1706 page_size::<C>(C::NR_LEVELS()) as int,
1707 );
1708 }
1709}
1710
1711pub proof fn lemma_view_in_vaddr_range_user<'rcu>(
1714 owner: &CursorOwner<'rcu, crate::mm::vm_space::UserPtConfig>,
1715)
1716 requires
1717 owner.inv(),
1718 ensures
1719 forall|m: Mapping|
1720 #![auto]
1721 owner.view_mappings().contains(m) ==> {
1722 &&& 0 <= m.va_range.start
1723 &&& m.va_range.end <= page_table_managed_end_spec::<
1724 crate::mm::vm_space::UserPtConfig,
1725 >()
1726 },
1727{
1728 lemma_view_in_vaddr_range(owner);
1729 lemma_vaddr_range_spec_user();
1730}
1731
1732impl<'rcu, C: PageTableConfig> InvView for CursorOwner<'rcu, C> {
1733 proof fn view_preserves_inv(self) {
1734 self.view_non_overlapping();
1735 self.lemma_view_mapping_inv();
1736 lemma_view_in_vaddr_range::<C>(&self);
1737 }
1738}
1739
1740impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
1741 pub proof fn view_non_overlapping(self)
1743 requires
1744 self.inv(),
1745 ensures
1746 self@.non_overlapping(),
1747 {
1748 self.as_page_table_owner_view_non_overlapping();
1749 }
1750}
1751
1752impl<'rcu, C: PageTableConfig, A: InAtomicMode> Inv for Cursor<'rcu, C, A> {
1753 open spec fn inv(self) -> bool {
1754 &&& 1 <= self.level <= self.guard_level + 1
1762 &&& self.guard_level <= NR_LEVELS
1763 &&& self.va >= self.barrier_va.start
1764 &&& self.va % PAGE_SIZE == 0
1765 &&& self.barrier_va.start < self.barrier_va.end
1766 &&& self.barrier_va.start % PAGE_SIZE == 0
1767 &&& self.barrier_va.end % PAGE_SIZE == 0
1768 &&& is_valid_range_spec::<C>(self.barrier_va)
1769 &&& self.barrier_va.end + page_size::<C>(self.guard_level)
1770 <= page_table_coverage_end_spec::<C>()
1771 &&& self.barrier_va.end - self.barrier_va.start <= page_size::<C>(
1772 (self.guard_level + 1) as PagingLevel,
1773 )
1774 }
1775}
1776
1777impl<'rcu, C: PageTableConfig, A: InAtomicMode> OwnerOf for Cursor<'rcu, C, A> {
1778 type Owner = CursorOwner<'rcu, C>;
1779
1780 open spec fn wf(self, owner: Self::Owner) -> bool {
1781 &&& owner.va == self.va
1782 &&& owner.barrier_va == self.barrier_va
1783 &&& self.level == owner.level
1784 &&& owner.guard_level == self.guard_level
1785 &&& owner.locked_range().start <= self.barrier_va.start
1786 &&& self.barrier_va.end
1787 <= owner.locked_range().end
1788 &&& self.level <= 4 ==> {
1796 &&& 4 <= self.guard_level ==> {
1797 &&& self.path[3] is Some
1798 &&& owner.continuations.contains_key(3)
1799 &&& owner.continuations[3].guard == self.path[3]->0
1800 }
1801 &&& 4 > self.guard_level ==> self.path[3] is None
1802 }
1803 &&& self.level <= 3 ==> {
1804 &&& 3 <= self.guard_level ==> {
1805 &&& self.path[2] is Some
1806 &&& owner.continuations.contains_key(2)
1807 &&& owner.continuations[2].guard == self.path[2]->0
1808 }
1809 &&& 3 > self.guard_level ==> self.path[2] is None
1810 }
1811 &&& self.level <= 2 ==> {
1812 &&& 2 <= self.guard_level ==> {
1813 &&& self.path[1] is Some
1814 &&& owner.continuations.contains_key(1)
1815 &&& owner.continuations[1].guard == self.path[1]->0
1816 }
1817 &&& 2 > self.guard_level ==> self.path[1] is None
1818 }
1819 &&& self.level == 1 ==> {
1820 &&& 1 <= self.guard_level ==> {
1824 &&& self.path[0] is Some
1825 &&& owner.continuations.contains_key(0)
1826 &&& owner.continuations[0].guard == self.path[0]->0
1827 }
1828 &&& 1 > self.guard_level ==> self.path[0] is None
1829 }
1830 }
1831}
1832
1833}