1use core::{marker::PhantomData, ops::Range};
2
3use vstd::prelude::*;
4
5use vstd::{arithmetic::power2::pow2, seq_lib::*, set::lemma_set_contains_len};
6use vstd_extra::{
7 drop_tracking::*,
8 ghost_tree::*,
9 ownership::*,
10 panic::may_panic,
11 prelude::*,
12 seq_extra::{forall_seq, lemma_forall_seq_index},
13};
14
15use crate::specs::{
16 arch::*,
17 mm::{
18 frame::{
19 mapping::{frame_to_index, index_to_meta},
20 meta_region_owners::MetaRegionOwners,
21 },
22 page_table::{
23 AbstractVaddr, Guards, Mapping,
24 cursor::page_size_lemmas::{
25 lemma_page_size_divides, lemma_page_size_ge_page_size, lemma_page_size_spec_level1,
26 },
27 lemma_vaddr_range_spec_kernel, lemma_vaddr_range_spec_user,
28 owners::*,
29 pte_index_bit_offset_spec, vaddr_range_spec,
30 },
31 },
32 task::InAtomicMode,
33};
34
35use crate::arch::mm::PagingConsts;
36use crate::mm::{
37 MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr,
38 frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
39 kspace::KernelPtConfig,
40 nr_subpage_per_huge,
41 page_prop::PageProperty,
42 page_size,
43 page_table::*,
44};
45
46verus! {
47
48broadcast use group_ghost_tree_lemmas;
49
50pub tracked struct CursorContinuation<'rcu, C: PageTableConfig> {
51 pub entry_own: EntryOwner<C>,
52 pub ghost idx: usize,
53 pub ghost tree_level: nat,
54 pub children: Seq<Option<OwnerSubtree<C>>>,
55 pub ghost path: TreePath<NR_ENTRIES>,
56 pub ghost guard: PageTableGuard<'rcu, C>,
57}
58
59impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
60 pub open spec fn path(self) -> TreePath<NR_ENTRIES> {
61 self.entry_own.path
62 }
63
64 pub open spec fn child(self) -> OwnerSubtree<C> {
65 self.children[self.idx as int]->0
66 }
67
68 pub open spec fn take_child(self) -> (OwnerSubtree<C>, Self) {
69 let child = self.children[self.idx as int]->0;
70 let cont = Self {
71 children: self.children.remove(self.idx as int).insert(self.idx as int, None),
72 ..self
73 };
74 (child, cont)
75 }
76
77 pub proof fn tracked_take_child(tracked &mut self) -> (tracked res: OwnerSubtree<C>)
78 requires
79 old(self).inv(),
80 old(self).idx < old(self).children.len(),
81 old(self).children[old(self).idx as int] is Some,
82 ensures
83 res == old(self).take_child().0,
84 *final(self) == old(self).take_child().1,
85 res.inv(),
86 {
87 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
88 self.children.tracked_insert(old(self).idx as int, None);
89 child
90 }
91
92 pub open spec fn put_child(self, child: OwnerSubtree<C>) -> Self {
93 Self {
94 children: self.children.remove(self.idx as int).insert(self.idx as int, Some(child)),
95 ..self
96 }
97 }
98
99 pub proof fn tracked_put_child(tracked &mut self, tracked child: OwnerSubtree<C>)
100 requires
101 old(self).idx < old(self).children.len(),
102 old(self).children[old(self).idx as int] is None,
103 ensures
104 *final(self) == old(self).put_child(child),
105 {
106 let _ = self.children.tracked_remove(old(self).idx as int);
107 self.children.tracked_insert(old(self).idx as int, Some(child));
108 }
109
110 pub proof fn take_put_child(self)
111 requires
112 self.idx < self.children.len(),
113 self.children[self.idx as int] is Some,
114 ensures
115 self.take_child().1.put_child(self.take_child().0) == self,
116 {
117 let child = self.take_child().0;
118 let cont = self.take_child().1;
119 assert(cont.put_child(child).children == self.children);
120 }
121
122 pub open spec fn make_cont(self, idx: usize, guard: PageTableGuard<'rcu, C>) -> (Self, Self) {
123 let child = Self {
124 entry_own: self.children[self.idx as int]->0.value(),
125 tree_level: (self.tree_level + 1) as nat,
126 idx: idx,
127 children: self.children[self.idx as int]->0.children(),
128 path: self.path.push_tail(self.idx as int),
129 guard: guard,
130 };
131 let cont = Self { children: self.children.update(self.idx as int, None), ..self };
132 (child, cont)
133 }
134
135 pub proof fn tracked_make_cont(
136 tracked &mut self,
137 idx: usize,
138 guard: PageTableGuard<'rcu, C>,
139 ) -> (tracked res: Self)
140 requires
141 old(self).all_some(),
142 old(self).children.len() == NR_ENTRIES,
143 old(self).idx < NR_ENTRIES,
144 idx < NR_ENTRIES,
145 ensures
146 res == old(self).make_cont(idx, guard).0,
147 *final(self) == old(self).make_cont(idx, guard).1,
148 {
149 lemma_update_is_remove_insert(self.children, old(self).idx as int, None);
150 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
151 self.children.tracked_insert(old(self).idx as int, None);
152 let tracked (entry_own, children) = child.tracked_into_parts();
153 Self {
154 entry_own,
155 tree_level: (old(self).tree_level + 1) as nat,
156 idx,
157 children,
158 path: old(self).path.push_tail(old(self).idx as int),
159 guard,
160 }
161 }
162
163 pub open spec fn restore(self, child: Self) -> (Self, PageTableGuard<'rcu, C>) {
164 let child_node = OwnerSubtree::new(child.entry_own, child.tree_level, child.children);
165 (
166 Self { children: self.children.update(self.idx as int, Some(child_node)), ..self },
167 child.guard,
168 )
169 }
170
171 pub proof fn tracked_restore(tracked &mut self, tracked child: Self) -> (guard: PageTableGuard<
172 'rcu,
173 C,
174 >)
175 requires
176 old(self).idx < old(self).children.len(),
177 ensures
178 *final(self) == old(self).restore(child).0,
179 guard == old(self).restore(child).1,
180 {
181 let tracked child_node = OwnerSubtree::tracked_new(
182 child.entry_own,
183 child.tree_level,
184 child.children,
185 );
186 lemma_update_is_remove_insert(self.children, self.idx as int, Some(child_node));
187 let _ = self.children.tracked_remove(self.idx as int);
188 self.children.tracked_insert(self.idx as int, Some(child_node));
189 child.guard
190 }
191
192 pub open spec fn new(
193 owner_subtree: OwnerSubtree<C>,
194 idx: usize,
195 guard: PageTableGuard<'rcu, C>,
196 ) -> Self {
197 Self {
198 entry_own: owner_subtree.value(),
199 idx: idx,
200 tree_level: owner_subtree.level(),
201 children: owner_subtree.children(),
202 path: TreePath::new(Seq::empty()),
203 guard: guard,
204 }
205 }
206
207 pub proof fn tracked_new(
208 tracked owner_subtree: OwnerSubtree<C>,
209 idx: usize,
210 guard: PageTableGuard<'rcu, C>,
211 ) -> tracked Self
212 returns
213 Self::new(owner_subtree, idx, guard),
214 {
215 let ghost tree_level = owner_subtree.level();
216 let tracked (entry_own, children) = owner_subtree.tracked_into_parts();
217 Self { entry_own, idx, tree_level, children, path: TreePath::new(Seq::empty()), guard }
218 }
219
220 pub open spec fn map_children(
221 self,
222 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
223 ) -> bool {
224 forall|i: int|
225 #![trigger(self.children[i])]
226 0 <= i < self.children.len() ==> self.children[i] is Some
227 ==> self.children[i]->0.subtree_satisfies(self.path().push_tail(i), f)
228 }
229
230 pub open spec fn level(self) -> PagingLevel {
233 self.entry_own.node().level
234 }
235
236 pub open spec fn inv_children(self) -> bool {
237 self.children.all(|child: Option<OwnerSubtree<C>>| child is Some ==> child->0.inv())
238 }
239
240 pub proof fn inv_children_unroll(self, i: int)
241 requires
242 self.inv_children(),
243 0 <= i < self.children.len(),
244 self.children[i] is Some,
245 ensures
246 self.children[i]->0.inv(),
247 {
248 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
249 assert(pred(self.children[i]));
250 }
251
252 pub proof fn inv_children_unroll_all(self)
253 requires
254 self.inv_children(),
255 ensures
256 forall|i: int|
257 #![auto]
258 0 <= i < self.children.len() ==> self.children[i] is Some
259 ==> self.children[i]->0.inv(),
260 {
261 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
262 assert forall|i: int|
263 0 <= i < self.children.len()
264 && #[trigger] self.children[i] is Some implies self.children[i].unwrap().inv() by {
265 self.inv_children_unroll(i)
266 }
267 }
268
269 pub open spec fn inv_children_rel_pred(self) -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
270 |i: int, child: Option<OwnerSubtree<C>>|
271 {
272 child is Some ==> {
273 &&& child->0.value().parent_level == self.level()
274 &&& child->0.level() == self.tree_level + 1
275 &&& child->0.value().path.len() == self.entry_own.node().tree_level + 1
276 &&& child->0.value().match_pte(
277 self.entry_own.node().children_perm.value()[i],
278 self.entry_own.node().level,
279 )
280 &&& child->0.value().path == self.path().push_tail(i)
281 }
282 }
283 }
284
285 pub open spec fn inv_children_rel(self) -> bool {
286 forall_seq(self.children, self.inv_children_rel_pred())
287 }
288
289 pub open spec fn pt_inv_children_pred() -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
290 |i: int, child: Option<OwnerSubtree<C>>| child is Some ==> PageTableOwner(child->0).pt_inv()
291 }
292
293 pub open spec fn pt_inv_children(self) -> bool {
294 forall_seq(self.children, Self::pt_inv_children_pred())
295 }
296
297 pub proof fn pt_inv_children_unroll(self, i: int)
298 requires
299 self.pt_inv_children(),
300 0 <= i < self.children.len(),
301 self.children[i] is Some,
302 ensures
303 PageTableOwner(self.children[i]->0).pt_inv(),
304 {
305 }
306
307 pub proof fn inv_children_rel_unroll(self, i: int)
308 requires
309 self.inv_children_rel(),
310 0 <= i < self.children.len(),
311 self.children[i] is Some,
312 ensures
313 self.children[i]->0.value().parent_level == self.level(),
314 self.children[i]->0.level() == self.tree_level + 1,
315 self.children[i]->0.value().path.len() == self.entry_own.node().tree_level + 1,
316 self.children[i]->0.value().match_pte(
317 self.entry_own.node().children_perm.value()[i],
318 self.entry_own.node().level,
319 ),
320 self.children[i]->0.value().path == self.path().push_tail(i),
321 {
322 }
323
324 pub open spec fn inv(self) -> bool {
325 &&& self.children.len() == NR_ENTRIES
326 &&& 0 <= self.idx < NR_ENTRIES
327 &&& self.inv_children()
328 &&& self.inv_children_rel()
329 &&& self.pt_inv_children()
330 &&& self.entry_own.is_node()
331 &&& self.entry_own.inv()
332 &&& self.entry_own.node().relate_guard(self.guard)
333 &&& self.tree_level == INC_LEVELS - self.level() - 1
334 &&& self.tree_level < INC_LEVELS - 1
335 &&& self.path().len() == self.tree_level
336 }
337
338 pub open spec fn all_some(self) -> bool {
339 forall|i: int| 0 <= i < NR_ENTRIES ==> self.children[i] is Some
340 }
341
342 pub open spec fn all_but_index_some(self) -> bool {
343 &&& forall|i: int| 0 <= i < self.idx ==> self.children[i] is Some
344 &&& forall|i: int| self.idx < i < NR_ENTRIES ==> self.children[i] is Some
345 &&& self.children[self.idx as int] is None
346 }
347
348 pub open spec fn inc_index(self) -> Self {
349 Self { idx: (self.idx + 1) as usize, ..self }
350 }
351
352 pub proof fn do_inc_index(tracked &mut self)
353 requires
354 old(self).idx + 1 < NR_ENTRIES,
355 ensures
356 *final(self) == old(self).inc_index(),
357 {
358 self.idx = (self.idx + 1) as usize;
359 }
360
361 pub open spec fn node_locked(self, guards: Guards<'rcu>) -> bool {
362 guards.lock_held(self.guard.inner.inner@.ptr.addr())
363 }
364
365 pub open spec fn view_mappings(self) -> Set<Mapping> {
366 self.children.map(
367 |i, child: Option<OwnerSubtree<C>>|
368 if child is Some {
369 PageTableOwner(child->0).view_rec(self.path().push_tail(i))
370 } else {
371 Set::empty()
372 },
373 ).to_set().flatten()
374 }
375
376 pub broadcast proof fn lemma_view_mappings_contains(self)
377 ensures
378 #![trigger self.view_mappings()]
379 forall|m: Mapping| #[trigger]
380 self.view_mappings().contains(m) ==> exists|i: int|
381 #![trigger self.children[i]]
382 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
383 self.children[i]->0,
384 ).view_rec(self.path().push_tail(i)).contains(m),
385 {
386 broadcast use vstd::seq_lib::group_seq_properties;
387
388 assert forall|m: Mapping| self.view_mappings().contains(m) implies exists|i: int|
389 #![trigger self.children[i]]
390 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
391 self.children[i]->0,
392 ).view_rec(self.path().push_tail(i)).contains(m) by {
393 let mapped = self.children.map(
394 |i, child: Option<OwnerSubtree<C>>|
395 if child is Some {
396 PageTableOwner(child->0).view_rec(self.path().push_tail(i))
397 } else {
398 Set::empty()
399 },
400 );
401 let elem_s = choose|elem_s: Set<Mapping>| #[trigger]
402 mapped.to_set().contains(elem_s) && elem_s.contains(m);
403 mapped.to_set_ensures();
404 let i = mapped.lemma_contains_to_index(elem_s);
405 if self.children[i] is Some {
406 } else {
407 assert(false);
408 }
409 }
410 }
411
412 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
413 requires
414 0 <= i < self.children.len(),
415 self.children[i] is Some,
416 #[trigger] PageTableOwner(self.children[i]->0).view_rec(
417 self.path().push_tail(i),
418 ).contains(m),
419 ensures
420 self.view_mappings().contains(m),
421 {
422 broadcast use vstd::seq_lib::group_seq_properties;
423
424 let mapped = self.children.map(
425 |i, child: Option<OwnerSubtree<C>>|
426 if child is Some {
427 PageTableOwner(child->0).view_rec(self.path().push_tail(i))
428 } else {
429 Set::empty()
430 },
431 );
432 assert(mapped.to_set().contains(mapped[i]));
433 }
434
435 pub open spec fn as_subtree(self) -> OwnerSubtree<C> {
436 OwnerSubtree::new(self.entry_own, self.tree_level, self.children)
437 }
438
439 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
440 PageTableOwner(self.as_subtree())
441 }
442
443 pub open spec fn view_mappings_take_child_spec(self) -> Set<Mapping> {
444 PageTableOwner(self.children[self.idx as int]->0).view_rec(
445 self.path().push_tail(self.idx as int),
446 )
447 }
448
449 pub proof fn rel_children_from_node_matching(
461 entry: &Entry<'_, 'rcu, C>,
462 child_value: EntryOwner<C>,
463 parent_owner: NodeOwner<C>,
464 guard: PageTableGuard<'rcu, C>,
465 entry_own: EntryOwner<C>,
466 idx: usize,
467 )
468 requires
469 entry.node_matching(child_value, parent_owner, guard),
470 entry.idx == idx,
471 entry_own.is_node(),
472 entry_own.node() == parent_owner,
473 child_value.path == entry_own.path.push_tail(idx as int),
474 child_value.path.len() == parent_owner.tree_level + 1,
475 ensures
476 child_value.path.len() == parent_owner.tree_level + 1,
477 child_value.match_pte(
478 parent_owner.children_perm.value()[idx as int],
479 parent_owner.level,
480 ),
481 child_value.path == entry_own.path.push_tail(idx as int),
482 child_value.parent_level == parent_owner.level,
483 {
484 }
485
486 pub proof fn continuation_inv_holds_after_child_restore(
496 self,
497 cont_old: Self,
498 parent_old: NodeOwner<C>,
499 )
500 requires
501 cont_old.inv(),
504 cont_old.entry_own.is_node(),
505 cont_old.entry_own.node() == parent_old,
506 self.children.len() == cont_old.children.len(),
508 self.idx == cont_old.idx,
509 self.tree_level == cont_old.tree_level,
510 self.guard == cont_old.guard,
511 self.path == cont_old.path,
512 self.entry_own.is_absent() == cont_old.entry_own.is_absent(),
515 self.entry_own.path == cont_old.entry_own.path,
516 self.entry_own.parent_level == cont_old.entry_own.parent_level,
517 self.entry_own.is_node(),
519 self.entry_own.inv(),
520 self.entry_own.node().relate_guard(self.guard),
521 self.entry_own.node().level == parent_old.level,
522 self.entry_own.node().tree_level == parent_old.tree_level,
523 forall|j: int|
525 0 <= j < NR_ENTRIES && j != self.idx as int
526 ==> #[trigger] self.entry_own.node().children_perm.value()[j]
527 == parent_old.children_perm.value()[j],
528 forall|j: int|
530 0 <= j < NR_ENTRIES && j != self.idx as int ==> #[trigger] self.children[j]
531 == cont_old.children[j],
532 self.children.len() == NR_ENTRIES,
535 0 <= self.idx < NR_ENTRIES,
536 self.tree_level == INC_LEVELS - self.level() - 1,
537 self.tree_level < INC_LEVELS - 1,
538 self.path().len() == self.tree_level,
539 self.children[self.idx as int] is Some,
541 self.children[self.idx as int]->0.inv(),
542 self.children[self.idx as int]->0.value().parent_level == self.level(),
543 self.children[self.idx as int]->0.value().path == self.path().push_tail(
544 self.idx as int,
545 ),
546 self.children[self.idx as int]->0.level() == self.tree_level + 1,
547 self.children[self.idx as int]->0.value().path.len() == self.entry_own.node().tree_level
548 + 1,
549 self.children[self.idx as int]->0.value().match_pte(
550 self.entry_own.node().children_perm.value()[self.idx as int],
551 self.entry_own.node().level,
552 ),
553 PageTableOwner(self.children[self.idx as int]->0).pt_inv(),
558 ensures
559 self.inv(),
560 {
561 }
562
563 pub proof fn new_child(
564 tracked &self,
565 paddr: Paddr,
566 prop: PageProperty,
567 tracked regions: &mut MetaRegionOwners,
568 ) -> (tracked res: OwnerSubtree<C>)
569 requires
570 self.inv(),
571 self.level() < NR_LEVELS,
572 old(regions).slots.contains_key(frame_to_index(paddr)),
573 valid_frame_paddr(paddr),
574 paddr % page_size(self.level()) == 0,
575 paddr + page_size(self.level()) <= MAX_PADDR,
576 C::raw_item_well_formed(paddr, self.level(), prop),
577 C::E::new_page_req(paddr, self.level(), prop),
578 self.path().push_tail(self.idx as int).inv(),
579 ensures
580 final(regions).slot_owners == old(regions).slot_owners,
581 final(regions).slots == old(regions).slots,
582 res.value() == EntryOwner::<C>::new_frame(
584 paddr,
585 self.path().push_tail(self.idx as int),
586 self.level(),
587 prop,
588 ),
589 res.inv(),
590 res.level() == self.tree_level + 1,
591 res == OwnerSubtree::new_val(res.value(), res.level() as nat),
592 {
593 let tracked mut owner = EntryOwner::<C>::tracked_new_frame(
594 paddr,
595 self.path().push_tail(self.idx as int),
596 self.level(),
597 prop,
598 );
599 OwnerSubtree::tracked_new_val(owner, self.tree_level + 1)
600 }
601
602 pub broadcast group group_lemmas {
603 CursorContinuation::lemma_view_mappings_contains,
604 CursorContinuation::lemma_view_mappings_intro,
605 }
606}
607
608pub tracked struct CursorOwner<'rcu, C: PageTableConfig> {
609 pub ghost level: PagingLevel,
610 pub continuations: Map<int, CursorContinuation<'rcu, C>>,
611 pub ghost va: AbstractVaddr,
612 pub ghost guard_level: PagingLevel,
613 pub ghost prefix: AbstractVaddr,
614 pub ghost popped_too_high: bool,
615}
616
617impl<'rcu, C: PageTableConfig> Inv for CursorOwner<'rcu, C> {
618 open spec fn inv(self) -> bool {
619 &&& self.va.inv()
620 &&& self.va.offset == 0
621 &&& 1 <= self.level <= NR_LEVELS
622 &&& 1 <= self.guard_level
623 <= NR_LEVELS
624 &&& C::TOP_LEVEL_INDEX_RANGE().start <= self.va.index[NR_LEVELS
628 - 1]
629 &&& self.va.index[NR_LEVELS - 1]
633 <= C::TOP_LEVEL_INDEX_RANGE().end
634 &&& self.in_locked_range()
636 || self.above_locked_range()
637 &&& self.popped_too_high ==> self.level >= self.guard_level
640 &&& !self.popped_too_high ==> self.level <= self.guard_level || self.above_locked_range()
641 &&& self.continuations[self.level - 1].all_some()
642 &&& forall|i: int|
643 self.level <= i < NR_LEVELS ==> {
644 (#[trigger] self.continuations[i]).all_but_index_some()
645 }
646 &&& self.level <= NR_LEVELS - 1 ==> {
655 &&& C::TOP_LEVEL_INDEX_RANGE().start <= self.continuations[NR_LEVELS - 1].idx
656 &&& self.continuations[NR_LEVELS - 1].idx < C::TOP_LEVEL_INDEX_RANGE().end
657 }
658 &&& forall|j: int|
659 #![trigger self.continuations[NR_LEVELS - 1].children[j]]
660 0 <= j < NR_ENTRIES && !(C::TOP_LEVEL_INDEX_RANGE().start <= j
661 < C::TOP_LEVEL_INDEX_RANGE().end) ==> self.continuations[NR_LEVELS
662 - 1].children[j] is Some ==> (self.continuations[NR_LEVELS
663 - 1].children[j].unwrap().value().is_borrowed() || self.continuations[NR_LEVELS
664 - 1].children[j].unwrap().value().is_absent())
665 &&& self.prefix.inv()
666 &&& self.prefix.offset == 0
667 &&& forall|i: int|
668 i < self.guard_level ==> self.prefix.index[i]
669 == 0
670 &&& self.prefix.index[NR_LEVELS - 1] >= C::TOP_LEVEL_INDEX_RANGE().start
674 &&& self.prefix.index[NR_LEVELS - 1]
675 < C::TOP_LEVEL_INDEX_RANGE().end
676 &&& self.prefix.index[NR_LEVELS - 1] + 1
679 < NR_ENTRIES
680 &&& self.locked_range().end <= vaddr_range_spec::<C>().end
684 + 1
685 &&& self.locked_range().end
690 <= C::LOCKED_END_BOUND_spec()
691 &&& self.va.leading_bits
694 == self.prefix.leading_bits
695 &&& self.prefix.leading_bits == C::LEADING_BITS_spec()
698 &&& self.level <= self.guard_level ==> forall|i: int|
699 #![auto]
700 self.guard_level <= i < NR_LEVELS ==> self.continuations[i].idx
701 == self.prefix.index[i]
702 &&& !self.popped_too_high && (self.in_locked_range() || self.level < self.guard_level)
710 ==> forall|i: int|
711 self.guard_level <= i < NR_LEVELS ==> self.va.index[i] == self.prefix.index[i]
712 &&& !self.popped_too_high && self.guard_level >= 1 && self.level < self.guard_level
713 ==> self.va.index[self.guard_level - 1] == self.prefix.index[self.guard_level - 1]
714 &&& self.level <= 4 ==> {
715 &&& self.continuations.contains_key(3)
716 &&& self.continuations[3].inv()
717 &&& self.continuations[3].level()
718 == 4
719 &&& self.continuations[3].entry_own.parent_level
721 == 5
722 &&& self.in_locked_range() ==> self.va.index[3] == self.continuations[3].idx
727 }
728 &&& self.level <= 3 ==> {
729 &&& self.continuations.contains_key(2)
730 &&& self.continuations[2].inv()
731 &&& self.continuations[2].level() == 3
732 &&& self.continuations[2].entry_own.parent_level == 4
733 &&& self.in_locked_range() ==> self.va.index[2] == self.continuations[2].idx
734 &&& self.continuations[2].guard.inner.inner@.ptr.addr()
735 != self.continuations[3].guard.inner.inner@.ptr.addr()
736 &&& self.continuations[2].path() == self.continuations[3].path().push_tail(
738 self.continuations[3].idx as int,
739 )
740 &&& self.continuations[2].entry_own.path.len()
742 == self.continuations[3].entry_own.node().tree_level + 1
743 &&& self.continuations[2].entry_own.match_pte(
744 self.continuations[3].entry_own.node().children_perm.value()[self.continuations[3].idx as int],
745 self.continuations[3].entry_own.node().level,
746 )
747 &&& self.continuations[2].entry_own.parent_level
748 == self.continuations[3].entry_own.node().level
749 }
750 &&& self.level <= 2 ==> {
751 &&& self.continuations.contains_key(1)
752 &&& self.continuations[1].inv()
753 &&& self.continuations[1].level() == 2
754 &&& self.continuations[1].entry_own.parent_level == 3
755 &&& self.in_locked_range() ==> self.va.index[1] == self.continuations[1].idx
756 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
757 != self.continuations[2].guard.inner.inner@.ptr.addr()
758 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
759 != self.continuations[3].guard.inner.inner@.ptr.addr()
760 &&& self.continuations[1].path() == self.continuations[2].path().push_tail(
762 self.continuations[2].idx as int,
763 )
764 &&& self.continuations[1].entry_own.path.len()
766 == self.continuations[2].entry_own.node().tree_level + 1
767 &&& self.continuations[1].entry_own.match_pte(
768 self.continuations[2].entry_own.node().children_perm.value()[self.continuations[2].idx as int],
769 self.continuations[2].entry_own.node().level,
770 )
771 &&& self.continuations[1].entry_own.parent_level
772 == self.continuations[2].entry_own.node().level
773 }
774 &&& self.level == 1 ==> {
775 &&& self.continuations.contains_key(0)
776 &&& self.continuations[0].inv()
777 &&& self.continuations[0].level() == 1
778 &&& self.continuations[0].entry_own.parent_level == 2
779 &&& self.in_locked_range() ==> self.va.index[0] == self.continuations[0].idx
780 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
781 != self.continuations[1].guard.inner.inner@.ptr.addr()
782 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
783 != self.continuations[2].guard.inner.inner@.ptr.addr()
784 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
785 != self.continuations[3].guard.inner.inner@.ptr.addr()
786 &&& self.continuations[0].path() == self.continuations[1].path().push_tail(
788 self.continuations[1].idx as int,
789 )
790 &&& self.continuations[0].entry_own.path.len()
792 == self.continuations[1].entry_own.node().tree_level + 1
793 &&& self.continuations[0].entry_own.match_pte(
794 self.continuations[1].entry_own.node().children_perm.value()[self.continuations[1].idx as int],
795 self.continuations[1].entry_own.node().level,
796 )
797 &&& self.continuations[0].entry_own.parent_level
798 == self.continuations[1].entry_own.node().level
799 }
800 }
801}
802
803impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
804 pub open spec fn node_unlocked(guards: Guards<'rcu>) -> (spec_fn(
805 EntryOwner<C>,
806 TreePath<NR_ENTRIES>,
807 ) -> bool) {
808 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
809 owner.is_node() ==> guards.unlocked(owner.node().meta_vaddr())
810 }
811
812 pub open spec fn node_unlocked_except(guards: Guards<'rcu>, addr: usize) -> (spec_fn(
813 EntryOwner<C>,
814 TreePath<NR_ENTRIES>,
815 ) -> bool) {
816 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
817 owner.is_node() ==> owner.node().meta_vaddr() != addr ==> guards.unlocked(
818 owner.node().meta_vaddr(),
819 )
820 }
821
822 pub open spec fn map_full_tree(
823 self,
824 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
825 ) -> bool {
826 forall|i: int|
827 #![trigger self.continuations[i]]
828 self.level - 1 <= i < NR_LEVELS ==> { self.continuations[i].map_children(f) }
829 }
830
831 pub open spec fn map_only_children(
832 self,
833 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
834 ) -> bool {
835 forall|i: int|
836 #![trigger self.continuations[i]]
837 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(f)
838 }
839
840 pub open spec fn children_not_locked(self, guards: Guards<'rcu>) -> bool {
841 self.map_only_children(Self::node_unlocked(guards))
842 }
843
844 pub open spec fn only_current_locked(self, guards: Guards<'rcu>) -> bool {
845 self.map_only_children(
846 Self::node_unlocked_except(guards, self.cur_entry_owner().node().meta_vaddr()),
847 )
848 }
849
850 pub proof fn never_drop_restores_children_not_locked(
851 self,
852 guard: PageTableGuard<'rcu, C>,
853 guards0: Guards<'rcu>,
854 guards1: Guards<'rcu>,
855 )
856 requires
857 self.inv(),
858 self.only_current_locked(guards0),
859 guards0.lock_held(guard.inner.inner@.ptr.addr()),
860 guards1.guards == guards0.guards.remove(guard.inner.inner@.ptr.addr()),
861 self.cur_entry_owner().is_node(),
863 guard.inner.inner@.ptr.addr() == self.cur_entry_owner().node().meta_vaddr(),
864 ensures
865 self.children_not_locked(guards1),
866 {
867 let current_addr = self.cur_entry_owner().node().meta_vaddr();
868 let f = Self::node_unlocked_except(guards0, current_addr);
869 let g = Self::node_unlocked(guards1);
870
871 self.map_children_implies(f, g);
872 }
873
874 pub proof fn never_drop_restores_nodes_locked(
878 self,
879 guard: PageTableGuard<'rcu, C>,
880 guards0: Guards<'rcu>,
881 guards1: Guards<'rcu>,
882 )
883 requires
884 self.inv(),
885 self.nodes_locked(guards0),
886 guards0.lock_held(guard.inner.inner@.ptr.addr()),
887 guards1.guards == guards0.guards.remove(guard.inner.inner@.ptr.addr()),
888 forall|i: int|
889 #![trigger self.continuations[i]]
890 self.level - 1 <= i < NR_LEVELS
891 ==> self.continuations[i].guard.inner.inner@.ptr.addr()
892 != guard.inner.inner@.ptr.addr(),
893 ensures
894 self.nodes_locked(guards1),
895 {
896 }
897
898 pub open spec fn nodes_locked(self, guards: Guards<'rcu>) -> bool {
912 forall|i: int|
918 #![trigger self.continuations[i]]
919 self.level - 1 <= i < self.guard_level ==> { self.continuations[i].node_locked(guards) }
920 }
921
922 pub open spec fn index(self) -> usize {
923 self.continuations[self.level - 1].idx
924 }
925
926 pub open spec fn inc_index(self) -> Self {
927 Self {
928 continuations: self.continuations.insert(
929 self.level - 1,
930 self.continuations[self.level - 1].inc_index(),
931 ),
932 va: AbstractVaddr {
933 index: self.va.index.insert(
934 self.level - 1,
935 self.continuations[self.level - 1].inc_index().idx as int,
936 ),
937 ..self.va
938 },
939 popped_too_high: false,
940 ..self
941 }
942 }
943
944 pub proof fn lemma_inc_index_va_inv(self)
946 requires
947 self.inv(),
948 self.index() + 1 < NR_ENTRIES,
949 ensures
950 self.inc_index().va.inv(),
951 {
952 let new_index = self.continuations[self.level - 1].inc_index().idx as int;
953 self.va.lemma_insert_preserves_inv(self.level - 1, new_index);
954 }
955
956 #[verifier::spinoff_prover]
957 pub proof fn do_inc_index(tracked &mut self)
958 requires
959 old(self).inv(),
960 old(self).level <= old(self).guard_level,
961 old(self).in_locked_range(),
962 old(self).continuations[old(self).level - 1].idx + 1 < NR_ENTRIES,
963 old(self).level == NR_LEVELS ==> (old(self).continuations[old(self).level - 1].idx + 1)
964 <= C::TOP_LEVEL_INDEX_RANGE().end,
965 ensures
966 final(self).inv(),
967 *final(self) == old(self).inc_index(),
968 {
969 old(self).lemma_inc_index_va_inv();
970 self.popped_too_high = false;
971 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
972 cont.do_inc_index();
973 self.va = AbstractVaddr {
974 index: self.va.index.insert(self.level - 1, cont.idx as int),
975 ..self.va
976 };
977 self.continuations.tracked_insert(self.level - 1, cont);
978 assert(self.continuations == old(self).continuations.insert(self.level - 1, cont));
979
980 old(self).va.index_increment_adds_page_size(old(self).level as int);
981
982 if old(self).popped_too_high {
983 old(self).in_locked_range_prefix_match();
984 }
985 assert(self.va.inv());
986 }
987
988 pub proof fn inv_continuation(self, i: int)
989 requires
990 self.inv(),
991 self.level - 1 <= i <= NR_LEVELS - 1,
992 ensures
993 self.continuations.contains_key(i),
994 self.continuations[i].inv(),
995 self.continuations[i].children.len() == NR_ENTRIES,
996 {
997 }
998
999 pub open spec fn view_mappings(self) -> Set<Mapping> {
1000 self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS).map_values(
1001 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
1002 ).values().flatten()
1003 }
1004
1005 pub broadcast proof fn lemma_view_mappings_contains(self)
1006 requires
1007 1 <= self.level <= NR_LEVELS,
1008 ensures
1009 #![trigger self.view_mappings()]
1010 forall|m: Mapping| #[trigger]
1011 self.view_mappings().contains(m) ==> exists|i: int|
1012 #![trigger self.continuations[i]]
1013 self.level - 1 <= i < NR_LEVELS
1014 && self.continuations[i].view_mappings().contains(m),
1015 {
1016 broadcast use vstd::map_lib::group_map_properties;
1017
1018 assert forall|m: Mapping| #[trigger] self.view_mappings().contains(m) implies exists|i: int|
1019
1020 #![trigger self.continuations[i]]
1021 self.level - 1 <= i < NR_LEVELS && self.continuations[i].view_mappings().contains(
1022 m,
1023 ) by {
1024 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
1025 let mapped = filtered.map_values(
1026 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
1027 );
1028 let values = mapped.values();
1029 let elem_s = choose|elem_s: Set<Mapping>| #[trigger]
1030 values.contains(elem_s) && elem_s.contains(m);
1031 let i = choose|i: int| #[trigger] mapped.dom().contains(i) && mapped[i] == elem_s;
1032 }
1033 }
1034
1035 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
1036 requires
1037 1 <= self.level <= NR_LEVELS,
1038 self.level - 1 <= i < NR_LEVELS,
1039 self.continuations.contains_key(i),
1040 #[trigger] self.continuations[i].view_mappings().contains(m),
1041 ensures
1042 self.view_mappings().contains(m),
1043 {
1044 broadcast use vstd::map_lib::group_map_properties;
1045
1046 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
1047 let mapped = filtered.map_values(|cont: CursorContinuation<'rcu, C>| cont.view_mappings());
1048 let values = mapped.values();
1049 assert(values.contains(mapped[i]));
1050 values.lemma_flatten_contains(m);
1051 }
1052
1053 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
1054 if self.level == 1 {
1055 let l1 = self.continuations[0];
1056 let l2 = self.continuations[1].restore(l1).0;
1057 let l3 = self.continuations[2].restore(l2).0;
1058 let l4 = self.continuations[3].restore(l3).0;
1059 l4.as_page_table_owner()
1060 } else if self.level == 2 {
1061 let l2 = self.continuations[1];
1062 let l3 = self.continuations[2].restore(l2).0;
1063 let l4 = self.continuations[3].restore(l3).0;
1064 l4.as_page_table_owner()
1065 } else if self.level == 3 {
1066 let l3 = self.continuations[2];
1067 let l4 = self.continuations[3].restore(l3).0;
1068 l4.as_page_table_owner()
1069 } else {
1070 let l4 = self.continuations[3];
1071 l4.as_page_table_owner()
1072 }
1073 }
1074
1075 pub open spec fn cur_entry_owner(self) -> EntryOwner<C> {
1076 self.cur_subtree().value()
1077 }
1078
1079 pub open spec fn cur_subtree(self) -> OwnerSubtree<C> {
1080 self.continuations[self.level - 1].children[self.index() as int]->0
1081 }
1082
1083 pub proof fn cur_frame_clone_requires(
1098 self,
1099 item: C::Item,
1100 pa: Paddr,
1101 level: PagingLevel,
1102 prop: PageProperty,
1103 regions: MetaRegionOwners,
1104 )
1105 requires
1106 self.inv(),
1107 regions.inv(),
1108 self.metaregion_sound(regions),
1109 self.cur_entry_owner().is_frame(),
1110 pa == self.cur_entry_owner().frame().mapped_pa,
1111 C::item_from_raw_spec(pa, level, prop) == item,
1112 valid_frame_paddr(pa),
1113 C::raw_item_well_formed(pa, level, prop),
1114 C::tracked(item) == self.cur_entry_owner().frame_is_tracked(),
1116 C::tracked(item) ==> (regions.slot_owner(pa).ref_count() < REF_COUNT_MAX
1118 || may_panic()),
1119 ensures
1120 item.clone_requires(regions),
1121 {
1122 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1123
1124 let entry = self.cur_entry_owner();
1125 let idx = frame_to_index(pa);
1126 EntryOwner::<C>::axiom_frame_is_tracked_iff_not_mmio(entry);
1127 C::lemma_clone_requires_concrete(item, pa, level, prop, regions);
1128 }
1129
1130 pub proof fn clone_item_preserves_invariants(
1133 self,
1134 old_regions: MetaRegionOwners,
1135 new_regions: MetaRegionOwners,
1136 idx: int,
1137 )
1138 requires
1139 self.inv(),
1140 self.metaregion_sound(old_regions),
1141 old_regions.inv(),
1142 self.cur_entry_owner().is_frame(),
1143 idx == frame_to_index(self.cur_entry_owner().frame().mapped_pa),
1144 old_regions.slot_owners.contains_key(idx),
1145 new_regions.slot_owners.contains_key(idx),
1146 new_regions.slot_owners[idx].ref_count() == old_regions.slot_owners[idx].ref_count()
1148 + 1,
1149 new_regions.slot_owners[idx].ref_count_perm.id()
1151 == old_regions.slot_owners[idx].ref_count_perm.id(),
1152 new_regions.slot_owners[idx].storage_perm()
1153 == old_regions.slot_owners[idx].storage_perm(),
1154 new_regions.slot_owners[idx].vtable_ptr_perm()
1155 == old_regions.slot_owners[idx].vtable_ptr_perm(),
1156 new_regions.slot_owners[idx].in_list_perm == old_regions.slot_owners[idx].in_list_perm,
1157 new_regions.slot_owners[idx].paths_in_pt == old_regions.slot_owners[idx].paths_in_pt,
1159 new_regions.slot_owners[idx].slot_vaddr == old_regions.slot_owners[idx].slot_vaddr,
1160 new_regions.slot_owners[idx].usage == old_regions.slot_owners[idx].usage,
1161 new_regions.slot_owners.dom() == old_regions.slot_owners.dom(),
1163 forall|i: int|
1164 #![trigger new_regions.slot_owners[i]]
1165 i != idx && old_regions.slot_owners.contains_key(i) ==> new_regions.slot_owners[i]
1166 == old_regions.slot_owners[i],
1167 new_regions.slots == old_regions.slots,
1169 0 < old_regions.slot_owners[idx].ref_count(),
1175 old_regions.slot_owners[idx].ref_count() + 1 <= REF_COUNT_MAX,
1176 ensures
1177 new_regions.inv(),
1178 self.metaregion_sound(new_regions),
1179 {
1180 self.metaregion_slot_owners_rc_increment(old_regions, new_regions, idx);
1181 }
1182
1183 pub proof fn new_child_mappings_eq_target(
1186 self,
1187 new_subtree: OwnerSubtree<C>,
1188 pa: Paddr,
1189 level: PagingLevel,
1190 prop: PageProperty,
1191 )
1192 requires
1193 self.inv(),
1194 self.in_locked_range(),
1195 level == self.level,
1196 new_subtree.inv(),
1197 new_subtree.value().is_frame(),
1198 new_subtree.value().path == self.continuations[self.level - 1].path().push_tail(
1199 self.continuations[self.level - 1].idx as int,
1200 ),
1201 new_subtree.value().frame().mapped_pa == pa,
1202 new_subtree.value().frame().prop == prop,
1203 ensures
1204 PageTableOwner(new_subtree)@.mappings
1205 == set![Mapping {
1206 va_range: self@.cur_slot_range(page_size(level)),
1207 pa_range: pa..(pa + page_size(level)) as usize,
1208 page_size: page_size(level),
1209 property: prop,
1210 }],
1211 {
1212 let path = new_subtree.value().path;
1213 let ps = page_size(level);
1214 let cont = self.continuations[self.level - 1];
1215
1216 self.cur_va_in_subtree_range();
1221 assert(vaddr_of::<C>(path) == nat_align_down(self@.cur_va as nat, ps as nat) as Vaddr) by {
1222 self.va.to_path_vaddr_concrete(self.level - 1);
1223 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
1224 let va_path = self.va.to_path(self.level - 1);
1225 self.va.to_path_len(self.level - 1);
1226 self.va.to_path_inv(self.level - 1);
1227 self.cur_subtree_inv();
1228 assert forall|i: int| 0 <= i < path.len() implies path[i] == va_path[i] by {
1229 self.va.to_path_index(self.level - 1, i);
1230 };
1231 AbstractVaddr::rec_vaddr_eq_if_indices_eq(path, va_path, 0);
1232 };
1233 let target = Mapping {
1238 va_range: self@.cur_slot_range(page_size(level)),
1239 pa_range: pa..(pa + page_size(level)) as usize,
1240 page_size: page_size(level),
1241 property: prop,
1242 };
1243 let from_view = Mapping {
1244 va_range: Range { start: vaddr_of::<C>(path) as int, end: vaddr_of::<C>(path) + ps },
1245 pa_range: pa..(pa + ps) as usize,
1246 page_size: ps,
1247 property: prop,
1248 };
1249 let nad = nat_align_down(self@.cur_va as nat, ps as nat);
1252 assert(nad <= self@.cur_va as nat) by {
1253 vstd_extra::arithmetic::lemma_nat_align_down_sound(self@.cur_va as nat, ps as nat);
1254 };
1255 }
1256
1257 pub open spec fn locked_range(self) -> Range<Vaddr> {
1258 let start = self.prefix.align_down(self.guard_level as int).to_vaddr();
1259 let end = self.prefix.align_up(self.guard_level as int).to_vaddr();
1260 Range { start, end }
1261 }
1262
1263 pub open spec fn in_locked_range(self) -> bool {
1264 self.locked_range().start <= self.va.to_vaddr() < self.locked_range().end
1265 }
1266
1267 pub open spec fn above_locked_range(self) -> bool {
1268 self.va.to_vaddr() >= self.locked_range().end
1269 }
1270
1271 pub proof fn inc_at_guard_level_above_locked_range(
1273 old_va: AbstractVaddr,
1274 prefix: AbstractVaddr,
1275 guard_level: u8,
1276 level: u8,
1277 new_va_val: Vaddr,
1278 )
1279 requires
1280 old_va.inv(),
1281 prefix.inv(),
1282 1 <= guard_level <= NR_LEVELS,
1283 level == guard_level,
1284 new_va_val == old_va.to_vaddr() + page_size(level as PagingLevel),
1285 prefix.align_down(guard_level as int).to_vaddr() <= old_va.to_vaddr(),
1286 old_va.to_vaddr() < prefix.align_up(guard_level as int).to_vaddr(),
1287 prefix.align_down(guard_level as int).to_vaddr() + page_size(guard_level as PagingLevel)
1289 <= usize::MAX,
1290 ensures
1291 new_va_val >= prefix.align_up(guard_level as int).to_vaddr(),
1292 {
1293 let ps_gl = page_size(guard_level as PagingLevel);
1294 lemma_page_size_ge_page_size(guard_level as PagingLevel);
1295 let aligned = prefix.align_down(guard_level as int);
1296 prefix.align_down_concrete(guard_level as int);
1297 prefix.align_down_shape(guard_level as int);
1298
1299 assert(aligned.to_vaddr() as nat % ps_gl as nat == 0) by {
1305 vstd_extra::arithmetic::lemma_nat_align_down_sound(
1306 prefix.to_vaddr() as nat,
1307 ps_gl as nat,
1308 );
1309 prefix.to_vaddr_bounded();
1310 aligned.reflect_prop(nat_align_down(prefix.to_vaddr() as nat, ps_gl as nat) as Vaddr);
1311 };
1312 aligned.aligned_align_up_advances(guard_level as int);
1314 aligned.aligned_align_down_is_self(guard_level as int);
1319 }
1320
1321 pub proof fn prefix_in_locked_range(self)
1322 requires
1323 self.inv(),
1324 !self.popped_too_high,
1325 self.level < self.guard_level,
1326 ensures
1327 self.in_locked_range(),
1328 {
1329 let gl = self.guard_level;
1330 if gl >= 1 && gl <= NR_LEVELS {
1331 self.va.align_down_to_vaddr_eq_if_upper_indices_eq(self.prefix, gl as int);
1335 self.va.align_down_concrete(gl as int);
1336 self.prefix.align_down_concrete(gl as int);
1337 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1338 nat_align_down(
1339 self.va.to_vaddr() as nat,
1340 page_size(gl as PagingLevel) as nat,
1341 ) as Vaddr,
1342 );
1343 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1344 nat_align_down(
1345 self.prefix.to_vaddr() as nat,
1346 page_size(gl as PagingLevel) as nat,
1347 ) as Vaddr,
1348 );
1349 lemma_page_size_ge_page_size(gl as PagingLevel);
1350
1351 self.prefix_aligned_to_guard_level();
1353 self.prefix_plus_ps_no_overflow();
1354 self.prefix.aligned_align_up_advances(gl as int);
1355 }
1356 }
1357
1358 pub proof fn in_locked_range_prefix_match(self)
1361 requires
1362 self.inv(),
1363 self.prefix.inv(),
1364 1 <= self.guard_level <= NR_LEVELS,
1365 self.in_locked_range(),
1366 ensures
1367 forall|i: int|
1368 self.guard_level <= i < NR_LEVELS ==> self.va.index[i] == self.prefix.index[i],
1369 {
1370 let gl = self.guard_level;
1371 let start = self.prefix.align_down(gl as int).to_vaddr();
1372
1373 let prefix_ad = self.prefix.align_down(gl as int);
1375
1376 self.prefix.align_down_concrete(gl as int);
1378 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1379 nat_align_down(
1380 self.prefix.to_vaddr() as nat,
1381 page_size(gl as PagingLevel) as nat,
1382 ) as Vaddr,
1383 );
1384 lemma_page_size_ge_page_size(gl as PagingLevel);
1385 lemma_nat_align_down_sound(
1386 self.prefix.to_vaddr() as nat,
1387 page_size(gl as PagingLevel) as nat,
1388 );
1389
1390 self.prefix_aligned_to_guard_level();
1392 self.prefix_plus_ps_no_overflow();
1393 self.prefix.aligned_align_up_advances(gl as int);
1394
1395 if gl >= 2 && gl < NR_LEVELS {
1396 AbstractVaddr::same_node_indices_match(
1399 self.va.to_vaddr(),
1400 self.prefix.to_vaddr(),
1401 start,
1402 (gl - 1) as PagingLevel,
1403 );
1404 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1406 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1407 } else if gl == 1 {
1408 let ps1 = page_size(1 as PagingLevel) as nat;
1412 let ps2 = page_size(2 as PagingLevel) as nat;
1413 let pv = self.prefix.to_vaddr() as nat;
1414 let cv = self.va.to_vaddr() as nat;
1415 let node_start = nat_align_down(pv, ps2) as usize;
1416
1417 lemma_page_size_ge_page_size(1 as PagingLevel);
1418 page_size_monotonic(1 as PagingLevel, 2 as PagingLevel);
1419 lemma_page_size_divides(1 as PagingLevel, 2 as PagingLevel);
1420 lemma_nat_align_down_sound(pv, ps2);
1421
1422 lemma_nat_align_down_within_block(pv, ps1, ps2);
1423
1424 AbstractVaddr::same_node_indices_match(
1425 self.va.to_vaddr(),
1426 self.prefix.to_vaddr(),
1427 node_start,
1428 1 as PagingLevel,
1429 );
1430 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1431 }
1432 }
1433
1434 #[verifier::rlimit(200)]
1438 pub proof fn in_locked_range_guard_index_eq_prefix(self)
1439 requires
1440 self.inv(),
1441 self.prefix.inv(),
1442 1 <= self.guard_level <= NR_LEVELS,
1443 self.in_locked_range(),
1444 ensures
1445 self.va.index[self.guard_level - 1] == self.prefix.index[self.guard_level - 1],
1446 {
1447 let gl = self.guard_level;
1448 let start = self.prefix.align_down(gl as int).to_vaddr();
1449
1450 self.prefix.align_down_concrete(gl as int);
1451 self.prefix_aligned_to_guard_level();
1454 self.prefix_plus_ps_no_overflow();
1455 self.prefix.aligned_align_up_advances(gl as int);
1456 lemma_page_size_ge_page_size(gl as PagingLevel);
1457
1458 self.prefix.align_down(gl as int).reflect_prop(
1459 nat_align_down(
1460 self.prefix.to_vaddr() as nat,
1461 page_size(gl as PagingLevel) as nat,
1462 ) as Vaddr,
1463 );
1464
1465 let ps = page_size(gl as PagingLevel);
1473 let va_val = self.va.to_vaddr();
1474 let k = start as int / ps as int;
1475 assert(start == k * ps) by {
1476 lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps as nat);
1477 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps as int);
1478 };
1479 assert(va_val as int / ps as int == k) by {
1481 let r = va_val - start;
1482 vstd::arithmetic::div_mod::lemma_fundamental_div_mod_converse(
1483 va_val as int,
1484 ps as int,
1485 k,
1486 r,
1487 );
1488 };
1489 use crate::specs::mm::page_table::cursor::page_size_lemmas::*;
1508 lemma_page_size_spec_values();
1509 vstd::arithmetic::power2::lemma2_to64();
1512 vstd::arithmetic::power2::lemma2_to64_rest();
1513 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1516 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1517 }
1518
1519 pub proof fn in_locked_range_level_le_nr_levels(self)
1520 requires
1521 self.inv(),
1522 self.in_locked_range(),
1523 !self.popped_too_high,
1524 ensures
1525 self.level <= NR_LEVELS,
1526 {
1527 }
1528
1529 pub proof fn in_locked_range_top_index_lt_top_end(self)
1533 requires
1534 self.inv(),
1535 self.in_locked_range(),
1536 !self.popped_too_high,
1537 ensures
1538 self.va.index[NR_LEVELS - 1] < C::TOP_LEVEL_INDEX_RANGE().end,
1539 {
1540 if self.guard_level == NR_LEVELS {
1541 if self.level < self.guard_level {
1542 } else {
1544 self.in_locked_range_guard_index_eq_prefix();
1555 }
1556 }
1557 }
1558
1559 pub proof fn in_locked_range_level_le_guard_level(self)
1560 requires
1561 self.inv(),
1562 self.in_locked_range(),
1563 !self.popped_too_high,
1564 ensures
1565 self.level <= self.guard_level,
1566 {
1567 }
1568
1569 pub proof fn cursor_top_idx_strict_lt_nr_entries(self)
1585 requires
1586 self.inv(),
1587 self.in_locked_range(),
1588 !self.popped_too_high,
1589 self.level == NR_LEVELS,
1590 self.guard_level == NR_LEVELS,
1591 ensures
1592 self.continuations[self.level - 1].idx + 1 < NR_ENTRIES,
1593 {
1594 self.in_locked_range_guard_index_eq_prefix();
1595 }
1596
1597 pub proof fn locked_range_span(self)
1605 requires
1606 self.inv(),
1607 ensures
1608 self.locked_range().start as nat == nat_align_down(
1609 self.prefix.to_vaddr() as nat,
1610 page_size(self.guard_level as PagingLevel) as nat,
1611 ),
1612 self.locked_range().start as nat % page_size(self.guard_level as PagingLevel) as nat
1613 == 0,
1614 self.locked_range().end - self.locked_range().start == page_size(
1615 self.guard_level as PagingLevel,
1616 ),
1617 {
1618 let gl = self.guard_level;
1619 let ps_gl = page_size(gl as PagingLevel) as nat;
1620 let pv = self.prefix.to_vaddr() as nat;
1621
1622 lemma_page_size_ge_page_size(gl as PagingLevel);
1623 self.prefix.align_down_concrete(gl as int);
1624 self.prefix_aligned_to_guard_level();
1625 self.prefix_plus_ps_no_overflow();
1626 self.prefix.aligned_align_up_advances(gl as int);
1627 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(pv, ps_gl) as Vaddr);
1628 }
1629
1630 pub proof fn in_node_holds_at_guard(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1638 requires
1639 self.inv(),
1640 self.in_locked_range(),
1641 self.va.reflect(self_va),
1642 node_size == page_size((self.guard_level + 1) as PagingLevel),
1643 self.locked_range().start <= va < self.locked_range().end,
1644 ensures
1645 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1646 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1647 {
1648 let gl = self.guard_level;
1649 let pg = page_size(gl as PagingLevel) as nat;
1650 let pg1 = node_size as nat;
1651 let ls = self.locked_range().start as nat;
1652
1653 lemma_page_size_ge_page_size((gl + 1) as PagingLevel);
1655
1656 self.locked_range_span();
1657 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(
1658 gl as PagingLevel,
1659 (gl + 1) as PagingLevel,
1660 );
1661 self.va.reflect_prop(self_va);
1662 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg1);
1668 assert(nat_align_down(self_va as nat, pg) == ls) by {
1671 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg);
1672 let nad = nat_align_down(self_va as nat, pg) as int;
1673 let lsi = ls as int;
1674 let pgi = pg as int;
1675 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(nad, pgi);
1679 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(lsi, pgi);
1680 let kn = nad / pgi;
1681 let kl = lsi / pgi;
1682 assert(nad - lsi == pgi * (kn - kl)) by (nonlinear_arith)
1683 requires
1684 nad == pgi * kn,
1685 lsi == pgi * kl,
1686 ;
1687 assert(kn - kl == 0) by (nonlinear_arith)
1688 requires
1689 0 <= pgi * (kn - kl) < pgi,
1690 pgi > 0,
1691 ;
1692 };
1693 vstd_extra::arithmetic::lemma_nat_align_down_monotone(self_va as nat, pg, pg1);
1694 vstd_extra::arithmetic::lemma_nat_align_down_within_block(self_va as nat, pg, pg1);
1695 }
1702
1703 #[verifier::rlimit(200)]
1705 pub proof fn node_within_locked_range(self, level: PagingLevel)
1706 requires
1707 self.inv(),
1708 self.in_locked_range(),
1709 1 <= level < self.guard_level,
1710 ensures
1711 self.locked_range().start <= nat_align_down(
1712 self.va.to_vaddr() as nat,
1713 page_size((level + 1) as PagingLevel) as nat,
1714 ) as usize,
1715 nat_align_down(
1716 self.va.to_vaddr() as nat,
1717 page_size((level + 1) as PagingLevel) as nat,
1718 ) as usize + page_size((level + 1) as PagingLevel) <= self.locked_range().end,
1719 {
1720 let gl = self.guard_level;
1721 let ps_gl = page_size(gl as PagingLevel) as nat;
1722 let ps = page_size((level + 1) as PagingLevel) as nat;
1723 let va = self.va.to_vaddr() as nat;
1724 let start = self.locked_range().start as nat;
1725
1726 lemma_page_size_ge_page_size(gl as PagingLevel);
1727 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1728 lemma_page_size_divides((level + 1) as PagingLevel, gl as PagingLevel);
1729 self.locked_range_span();
1730
1731 vstd::arithmetic::div_mod::lemma_indistinguishable_quotients(
1732 start as int,
1733 va as int,
1734 ps_gl as int,
1735 );
1736 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps_gl as int);
1737 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(va as int, ps_gl as int);
1738
1739 lemma_nat_align_down_sound(va, ps);
1740 lemma_nat_align_down_monotone(va, ps, ps_gl);
1741 lemma_nat_align_down_within_block(va, ps, ps_gl);
1742 }
1743
1744 pub proof fn prefix_aligned_to_guard_level(self)
1748 requires
1749 self.inv(),
1750 ensures
1751 self.prefix.to_vaddr() as nat % page_size(self.guard_level as PagingLevel) as nat == 0,
1752 {
1753 let gl = self.guard_level;
1754 let ps = page_size(gl as PagingLevel) as nat;
1755 lemma_page_size_ge_page_size(gl as PagingLevel);
1756
1757 self.prefix.align_down_shape(gl as int);
1760 self.prefix.align_down_leading_bits(gl as int);
1761 let aligned = self.prefix.align_down(gl as int);
1762
1763 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] aligned.index[i]
1764 == self.prefix.index[i] by {};
1765 assert(aligned.index == self.prefix.index);
1766
1767 self.prefix.align_down_concrete(gl as int);
1769 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps);
1770 aligned.reflect_prop(nat_align_down(self.prefix.to_vaddr() as nat, ps) as Vaddr);
1771 }
1772
1773 pub proof fn in_node_holds_at_top(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1786 requires
1787 self.inv(),
1788 self.va.reflect(self_va),
1789 self.guard_level == NR_LEVELS,
1790 node_size == page_size((NR_LEVELS + 1) as PagingLevel),
1791 self.locked_range().start <= va < self.locked_range().end,
1792 ensures
1793 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1794 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1795 {
1796 let gl = self.guard_level;
1797
1798 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
1799 self.prefix.to_vaddr_indices_drop_zero_range(0, NR_LEVELS as int);
1804
1805 self.prefix_aligned_to_guard_level();
1807 self.prefix.aligned_align_up_advances(gl as int);
1808 self.prefix.align_down_shape(gl as int);
1810 self.prefix.align_down_leading_bits(gl as int);
1811 let aligned = self.prefix.align_down(gl as int);
1812 assert(aligned.index == self.prefix.index);
1813
1814 self.va.reflect_prop(self_va); }
1821
1822 pub proof fn prefix_plus_ps_no_overflow(self)
1828 requires
1829 self.inv(),
1830 ensures
1831 self.prefix.to_vaddr() + page_size(self.guard_level as PagingLevel) <= usize::MAX,
1832 {
1833 let gl = self.guard_level;
1834 self.prefix.to_vaddr_bounded();
1835 self.prefix.to_vaddr_indices_gap_bound(0);
1836 vstd::arithmetic::power2::lemma2_to64();
1837 vstd::arithmetic::power2::lemma2_to64_rest();
1838 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
1839
1840 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
1841 self.prefix.to_vaddr_indices_gap_bound(gl as int);
1842 }
1843
1844 pub proof fn va_plus_page_size_no_overflow(self, level: PagingLevel)
1854 requires
1855 self.inv(),
1856 self.in_locked_range(),
1857 1 <= level <= self.guard_level,
1858 ensures
1859 self.va.to_vaddr() + page_size(level) <= usize::MAX,
1860 {
1861 let gl = self.guard_level;
1862 lemma_page_size_ge_page_size(gl as PagingLevel);
1863 lemma_page_size_ge_page_size(level as PagingLevel);
1864 page_size_monotonic(level as PagingLevel, gl as PagingLevel);
1865
1866 self.prefix_aligned_to_guard_level();
1868 self.prefix_plus_ps_no_overflow();
1869 self.prefix.aligned_align_up_advances(gl as int);
1870
1871 self.prefix.to_vaddr_indices_gap_bound(0);
1874 vstd::arithmetic::power2::lemma2_to64();
1875 vstd::arithmetic::power2::lemma2_to64_rest();
1876 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
1877
1878 assert forall|i: int| 0 <= i < gl implies self.prefix.index[i] == 0 by {
1879 assert(self.prefix.index.contains_key(i));
1880 };
1881 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
1882 self.prefix.to_vaddr_indices_gap_bound(gl as int);
1883 }
1884
1885 pub proof fn locked_range_page_aligned(self)
1886 requires
1887 self.inv(),
1888 ensures
1889 self.locked_range().end % PAGE_SIZE == 0,
1890 self.locked_range().start % PAGE_SIZE == 0,
1891 {
1892 let gl = self.guard_level;
1893 let pv = self.prefix.to_vaddr() as nat;
1894 let ps = page_size(gl as PagingLevel) as nat;
1895 lemma_page_size_ge_page_size(gl as PagingLevel);
1896 lemma_page_size_divides(1u8, gl as PagingLevel);
1897 let start_va = nat_align_down(pv, ps);
1898 let end_va = nat_align_up(pv, ps);
1899 vstd::arithmetic::div_mod::lemma_mod_mod(
1900 start_va as int,
1901 PAGE_SIZE as int,
1902 ps as int / PAGE_SIZE as int,
1903 );
1904 self.prefix.align_down_concrete(gl as int);
1905 self.prefix_aligned_to_guard_level();
1906 self.prefix_plus_ps_no_overflow();
1907 self.prefix.aligned_align_up_advances(gl as int);
1908
1909 vstd::arithmetic::power2::lemma2_to64();
1910 vstd_extra::external::ilog2::lemma_pow2_increases(49nat, 64nat);
1911
1912 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(start_va as Vaddr);
1913 }
1914
1915 pub proof fn cur_subtree_inv(self)
1916 requires
1917 self.inv(),
1918 ensures
1919 self.cur_subtree().inv(),
1920 {
1921 let cont = self.continuations[self.level - 1];
1922 cont.inv_children_unroll(cont.idx as int)
1923 }
1924
1925 pub proof fn cur_entry_absent_not_present(self)
1927 requires
1928 self.inv(),
1929 self.in_locked_range(),
1930 self.cur_entry_owner().is_absent(),
1931 ensures
1932 !self@.present(),
1933 {
1934 self.cur_subtree_inv();
1935 let cur_va = self.cur_va();
1936 let cur_subtree = self.cur_subtree();
1937 let cur_path = cur_subtree.value().path;
1938 PageTableOwner(cur_subtree).view_rec_absent_empty(cur_path);
1939
1940 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1941 <= cur_va < m.va_range.end) by {
1942 if m.va_range.start <= cur_va < m.va_range.end {
1943 self.mapping_covering_cur_va_from_cur_subtree(m);
1944 }
1945 };
1946
1947 let filtered = self@.mappings.filter(
1948 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1949 );
1950 assert(filtered == set![]) by {};
1951 }
1952
1953 pub proof fn cur_subtree_empty_not_present(self)
1955 requires
1956 self.inv(),
1957 self.in_locked_range(),
1958 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value().path) =~= set![],
1959 ensures
1960 !self@.present(),
1961 {
1962 let cur_va = self.cur_va();
1963
1964 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1965 <= cur_va < m.va_range.end) by {
1966 if m.va_range.start <= cur_va < m.va_range.end {
1967 self.mapping_covering_cur_va_from_cur_subtree(m);
1968 }
1969 };
1970
1971 let filtered = self@.mappings.filter(
1972 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1973 );
1974 assert(filtered == set![]) by {};
1975 }
1976
1977 pub proof fn cur_entry_frame_present(self)
1978 requires
1979 self.inv(),
1980 self.in_locked_range(),
1981 self.cur_entry_owner().is_frame(),
1982 ensures
1983 self@.present(),
1984 self@.query(
1985 self.cur_entry_owner().frame().mapped_pa,
1986 page_size(self.cur_entry_owner().parent_level),
1987 self.cur_entry_owner().frame().prop,
1988 ),
1989 {
1990 self.cur_subtree_inv();
1991 self.cur_va_in_subtree_range();
1992 self.view_preserves_inv();
1993 let subtree = self.cur_subtree();
1994 let path = subtree.value().path;
1995 let frame = self.cur_entry_owner().frame();
1996 let pt_level = INC_LEVELS - path.len();
1997 let cont = self.continuations[self.level - 1];
1998
1999 let m = Mapping {
2000 va_range: Range {
2001 start: vaddr_of::<C>(path) as int,
2002 end: vaddr_of::<C>(path) + page_size(pt_level as PagingLevel),
2003 },
2004 pa_range: Range {
2005 start: frame.mapped_pa,
2006 end: (frame.mapped_pa + page_size(pt_level as PagingLevel)) as Paddr,
2007 },
2008 page_size: page_size(pt_level as PagingLevel),
2009 property: frame.prop,
2010 };
2011 assert(PageTableOwner(subtree).view_rec(path) == set![m]);
2012 cont.lemma_view_mappings_intro(m, cont.idx as int);
2013 self.lemma_view_mappings_intro(m, self.level - 1);
2014 assert(m.va_range.start <= self@.cur_va < m.va_range.end) by {
2015 self.cur_va_in_subtree_range();
2016 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
2017 };
2018
2019 let filtered = self@.mappings.filter(
2020 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
2021 );
2022 assert(filtered.contains(m));
2023 lemma_set_contains_len(filtered, m);
2024 }
2025
2026 pub open spec fn path_metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2028 forall|i: int|
2029 #![trigger self.continuations[i]]
2030 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].entry_own.metaregion_sound(
2031 regions,
2032 )
2033 }
2034
2035 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2036 &&& self.map_full_tree(
2037 |entry_owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2038 entry_owner.metaregion_sound(regions),
2039 )
2040 &&& self.path_metaregion_sound(regions)
2041 }
2042
2043 pub proof fn metaregion_preserved(
2044 self,
2045 other: Self,
2046 regions0: MetaRegionOwners,
2047 regions1: MetaRegionOwners,
2048 )
2049 requires
2050 self.inv(),
2051 self.metaregion_sound(regions0),
2052 self.level == other.level,
2053 self.continuations =~= other.continuations,
2054 OwnerSubtree::implies(
2055 PageTableOwner::<C>::metaregion_sound_pred(regions0),
2056 PageTableOwner::<C>::metaregion_sound_pred(regions1),
2057 ),
2058 ensures
2059 other.metaregion_sound(regions1),
2060 {
2061 let f = PageTableOwner::metaregion_sound_pred(regions0);
2062 let g = PageTableOwner::metaregion_sound_pred(regions1);
2063
2064 assert forall|i: int| #![auto] self.level - 1 <= i < NR_LEVELS implies {
2065 other.continuations[i].map_children(g)
2066 } by {
2067 let cont = self.continuations[i];
2068 assert forall|j: int|
2069 0 <= j < NR_ENTRIES
2070 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
2071 cont.path().push_tail(j), g) by {
2072 cont.inv_children_unroll(j);
2073 cont.children[j].unwrap().lemma_subtree_satisfies_implies(
2074 cont.path().push_tail(j),
2075 f,
2076 g,
2077 );
2078 };
2079 };
2080 assert(other.path_metaregion_sound(regions1)) by {
2081 assert forall|i: int|
2082 #![trigger other.continuations[i]]
2083 self.level - 1 <= i
2084 < NR_LEVELS implies other.continuations[i].entry_own.metaregion_sound(
2085 regions1,
2086 ) by {
2087 let eo = self.continuations[i].entry_own;
2088 assert(g(eo, self.continuations[i].path()));
2089 };
2090 };
2091 }
2092
2093 pub proof fn metaregion_slot_owners_preserved(
2095 self,
2096 regions0: MetaRegionOwners,
2097 regions1: MetaRegionOwners,
2098 )
2099 requires
2100 self.inv(),
2101 self.metaregion_sound(regions0),
2102 regions0.slot_owners =~= regions1.slot_owners,
2103 forall|k: int|
2104 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2105 forall|k: int|
2106 regions0.slots.contains_key(k) ==> regions0.slots[k]
2107 == #[trigger] regions1.slots[k],
2108 ensures
2109 self.metaregion_sound(regions1),
2110 {
2111 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2112 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2113 self.metaregion_preserved(self, regions0, regions1);
2114 }
2115
2116 pub proof fn metaregion_slot_owners_rc_increment(
2117 self,
2118 regions0: MetaRegionOwners,
2119 regions1: MetaRegionOwners,
2120 idx: int,
2121 )
2122 requires
2123 self.inv(),
2124 self.metaregion_sound(regions0),
2125 regions0.inv(),
2126 regions1.slots == regions0.slots,
2127 regions1.slot_owners.dom() == regions0.slot_owners.dom(),
2128 regions1.slot_owners[idx].ref_count() == regions0.slot_owners[idx].ref_count() + 1,
2129 regions1.slot_owners[idx].ref_count_perm.id()
2130 == regions0.slot_owners[idx].ref_count_perm.id(),
2131 regions1.slot_owners[idx].storage_perm() == regions0.slot_owners[idx].storage_perm(),
2132 regions1.slot_owners[idx].vtable_ptr_perm()
2133 == regions0.slot_owners[idx].vtable_ptr_perm(),
2134 regions1.slot_owners[idx].in_list_perm == regions0.slot_owners[idx].in_list_perm,
2135 regions1.slot_owners[idx].paths_in_pt == regions0.slot_owners[idx].paths_in_pt,
2136 regions1.slot_owners[idx].slot_vaddr == regions0.slot_owners[idx].slot_vaddr,
2137 regions1.slot_owners[idx].usage == regions0.slot_owners[idx].usage,
2138 regions1.slot_owners[idx].ref_count() != REF_COUNT_UNUSED,
2139 regions1.slot_owners[idx].ref_count() <= REF_COUNT_MAX,
2141 forall|i: int|
2142 #![trigger regions1.slot_owners[i]]
2143 i != idx && regions0.slot_owners.contains_key(i) ==> regions1.slot_owners[i]
2144 == regions0.slot_owners[i],
2145 ensures
2146 self.metaregion_sound(regions1),
2147 {
2148 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2149 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2150 self.metaregion_preserved(self, regions0, regions1);
2151 }
2152
2153 pub proof fn metaregion_borrow_slot(
2156 self,
2157 regions0: MetaRegionOwners,
2158 regions1: MetaRegionOwners,
2159 changed_idx: int,
2160 )
2161 requires
2162 self.inv(),
2163 self.metaregion_sound(regions0),
2164 regions1.inv(),
2165 forall|k: int|
2166 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2167 forall|k: int|
2174 regions0.slots.contains_key(k) ==> regions0.slots[k]
2175 == #[trigger] regions1.slots[k],
2176 regions1.slot_owners[changed_idx].same_permissions(regions0.slot_owners[changed_idx]),
2178 regions1.slot_owners[changed_idx].slot_vaddr
2179 == regions0.slot_owners[changed_idx].slot_vaddr,
2180 regions1.slot_owners[changed_idx].usage == regions0.slot_owners[changed_idx].usage,
2181 regions1.slot_owners[changed_idx].paths_in_pt
2182 == regions0.slot_owners[changed_idx].paths_in_pt,
2183 forall|i: int|
2185 #![trigger regions1.slot_owners[i]]
2186 i != changed_idx ==> regions0.slot_owners[i] == regions1.slot_owners[i],
2187 regions0.slot_owners.dom() =~= regions1.slot_owners.dom(),
2188 ensures
2189 self.metaregion_sound(regions1),
2190 {
2191 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2192 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2193 let nsp = PageTableOwner::<C>::not_in_scope_pred();
2194
2195 assert forall|i: int|
2196 #![trigger self.continuations[i]]
2197 self.level - 1 <= i < NR_LEVELS implies { self.continuations[i].map_children(g) } by {
2198 let cont = self.continuations[i];
2199 assert forall|j: int|
2200 0 <= j < NR_ENTRIES
2201 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
2202 cont.path().push_tail(j), nsp) by {
2203 PageTableOwner::tree_not_in_scope(
2204 cont.children[j].unwrap(),
2205 cont.path().push_tail(j),
2206 );
2207 };
2208 assert forall|j: int|
2209 0 <= j < NR_ENTRIES
2210 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
2211 cont.path().push_tail(j), g) by {
2212 cont.children[j].unwrap().lemma_subtree_satisfies_implies_and(
2213 cont.path().push_tail(j),
2214 f,
2215 nsp,
2216 g,
2217 );
2218 };
2219 };
2220
2221 }
2222
2223 pub proof fn cont_entries_metaregion(self, regions: MetaRegionOwners)
2233 requires
2234 self.inv(),
2235 self.metaregion_sound(regions),
2236 ensures
2237 forall|i: int|
2238 #![trigger self.continuations[i]]
2239 self.level - 1 <= i < NR_LEVELS
2240 ==> self.continuations[i].entry_own.metaregion_sound(regions),
2241 {
2242 }
2245
2246 pub open spec fn new(
2247 owner_subtree: OwnerSubtree<C>,
2248 idx: usize,
2249 guard: PageTableGuard<'rcu, C>,
2250 ) -> Self {
2251 let va = AbstractVaddr {
2252 offset: 0,
2253 index: Map::new(Set::<int>::range(0, NR_LEVELS as int), |i: int| 0).insert(
2254 NR_LEVELS - 1,
2255 idx as int,
2256 ),
2257 leading_bits: C::LEADING_BITS_spec() as int,
2263 };
2264 Self {
2265 level: NR_LEVELS as PagingLevel,
2266 continuations: Map::empty().insert(
2267 NR_LEVELS - 1,
2268 CursorContinuation::new(owner_subtree, idx, guard),
2269 ),
2270 va,
2271 guard_level: NR_LEVELS as PagingLevel,
2272 prefix: va,
2273 popped_too_high: false,
2274 }
2275 }
2276
2277 pub proof fn tracked_new(
2278 tracked owner_subtree: OwnerSubtree<C>,
2279 idx: usize,
2280 guard: PageTableGuard<'rcu, C>,
2281 ) -> tracked Self
2282 returns
2283 Self::new(owner_subtree, idx, guard),
2284 {
2285 let ghost va = AbstractVaddr {
2286 offset: 0,
2287 index: Map::new(Set::<int>::range(0, NR_LEVELS as int), |i: int| 0).insert(
2288 NR_LEVELS - 1,
2289 idx as int,
2290 ),
2291 leading_bits: C::LEADING_BITS_spec() as int,
2292 };
2293 let tracked continuation = CursorContinuation::tracked_new(owner_subtree, idx, guard);
2294 let tracked mut continuations = Map::tracked_empty();
2295 continuations.tracked_insert(NR_LEVELS - 1, continuation);
2296 Self {
2297 level: NR_LEVELS as PagingLevel,
2298 continuations,
2299 va,
2300 guard_level: NR_LEVELS as PagingLevel,
2301 prefix: va,
2302 popped_too_high: false,
2303 }
2304 }
2305
2306 pub broadcast group group_lemmas {
2307 CursorOwner::lemma_view_mappings_contains,
2308 CursorOwner::lemma_view_mappings_intro,
2309 }
2310}
2311
2312pub ghost struct CursorView<C: PageTableConfig> {
2313 pub cur_va: Vaddr,
2314 pub mappings: Set<Mapping>,
2315 pub phantom: PhantomData<C>,
2316}
2317
2318impl<'rcu, C: PageTableConfig> View for CursorOwner<'rcu, C> {
2319 type V = CursorView<C>;
2320
2321 open spec fn view(&self) -> Self::V {
2322 CursorView { cur_va: self.cur_va(), mappings: self.view_mappings(), phantom: PhantomData }
2323 }
2324}
2325
2326impl<C: PageTableConfig> Inv for CursorView<C> {
2327 open spec fn inv(self) -> bool {
2328 &&& forall|m: Mapping|
2329 #![auto]
2330 self.mappings.contains(m)
2331 ==> m.inv()
2332 &&& forall|m: Mapping|
2338 #![auto]
2339 self.mappings.contains(m) ==> {
2340 &&& vaddr_range_spec::<C>().start <= m.va_range.start
2341 &&& m.va_range.end <= vaddr_range_spec::<C>().end + 1
2342 }
2343 &&& self.non_overlapping()
2344 }
2345}
2346
2347impl<C: PageTableConfig> CursorView<C> {
2348 pub open spec fn non_overlapping(self) -> bool {
2351 forall|m: Mapping, n: Mapping|
2352 #![auto]
2353 self.mappings.contains(m) ==> self.mappings.contains(n) ==> m != n ==> m.va_range.end
2354 <= n.va_range.start || n.va_range.end <= m.va_range.start
2355 }
2356}
2357
2358pub proof fn lemma_view_in_vaddr_range<'rcu, C: PageTableConfig>(owner: &CursorOwner<'rcu, C>)
2361 requires
2362 owner.inv(),
2363 ensures
2364 forall|m: Mapping|
2365 #![auto]
2366 owner.view_mappings().contains(m) ==> {
2367 &&& vaddr_range_spec::<C>().start <= m.va_range.start
2368 &&& m.va_range.end <= vaddr_range_spec::<C>().end + 1
2369 },
2370{
2371 C::lemma_paging_consts_properties();
2372 C::lemma_page_table_config_constant_properties();
2373 lemma_arch_specific_consts_properties::<C>();
2374
2375 let idx = C::TOP_LEVEL_INDEX_RANGE();
2376 let start = idx.start as int;
2377 let end = idx.end as int;
2378 let lb = C::LEADING_BITS_spec() as int;
2379 let base = lb * 0x1_0000_0000_0000int;
2380 let cell = 0x80_0000_0000int;
2381 let bounds = vaddr_range_spec::<C>();
2382
2383 let end_exclusive = base + end * cell;
2384 let end_pre = end_exclusive - 1;
2385
2386 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2387 &&& vaddr_range_spec::<C>().start <= m.va_range.start
2388 &&& m.va_range.end <= vaddr_range_spec::<C>().end + 1
2389 } by {
2390 let i = choose|i: int|
2391 owner.level - 1 <= i < NR_LEVELS && (
2392 #[trigger] owner.continuations[i]).view_mappings().contains(m);
2393 owner.inv_continuation(i);
2394 let cont = owner.continuations[i];
2395 let j = choose|j: int|
2396 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
2397 cont.children[j].unwrap(),
2398 ).view_rec(cont.path().push_tail(j)).contains(m);
2399 cont.pt_inv_children_unroll(j);
2400 let child = PageTableOwner(cont.children[j].unwrap());
2401 let p = cont.path().push_tail(j);
2402 let pidx = p[0] as int;
2403 child.view_rec_top_index_va_bound(p, m, end);
2404 }
2405}
2406
2407pub proof fn lemma_view_in_vaddr_range_user<'rcu>(
2416 owner: &CursorOwner<'rcu, crate::mm::vm_space::UserPtConfig>,
2417)
2418 requires
2419 owner.inv(),
2420 ensures
2421 forall|m: Mapping|
2422 #![auto]
2423 owner.view_mappings().contains(m) ==> {
2424 &&& 0 <= m.va_range.start
2425 &&& m.va_range.end <= 0x8000_0000_0000int
2426 },
2427{
2428 let end = crate::mm::vm_space::UserPtConfig::TOP_LEVEL_INDEX_RANGE().end as int;
2429 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2430 &&& 0 <= m.va_range.start
2431 &&& m.va_range.end <= 0x8000_0000_0000int
2432 } by {
2433 let i = choose|i: int|
2434 owner.level - 1 <= i < NR_LEVELS && (
2435 #[trigger] owner.continuations[i]).view_mappings().contains(m);
2436 let cont = owner.continuations[i];
2437 let j = choose|j: int|
2438 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
2439 cont.children[j].unwrap(),
2440 ).view_rec(cont.path().push_tail(j)).contains(m);
2441 let child = PageTableOwner(cont.children[j].unwrap());
2442 let p = cont.path().push_tail(j);
2443 child.view_rec_top_index_va_bound(p, m, end);
2444 }
2445}
2446
2447pub proof fn lemma_view_in_vaddr_range_kernel<'rcu>(owner: CursorOwner<'rcu, KernelPtConfig>)
2452 requires
2453 owner.inv(),
2454 ensures
2455 forall|m: Mapping|
2456 #![auto]
2457 owner.view_mappings().contains(m) ==> {
2458 &&& vaddr_range_spec::<KernelPtConfig>().start <= m.va_range.start
2459 &&& m.va_range.end <= vaddr_range_spec::<KernelPtConfig>().end + 1
2460 },
2461{
2462 lemma_vaddr_range_spec_kernel();
2463 let start = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start as int;
2464 let end = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end as int;
2465 let lb = KernelPtConfig::LEADING_BITS_spec() as int;
2466 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2467 &&& vaddr_range_spec::<KernelPtConfig>().start <= m.va_range.start
2468 &&& m.va_range.end <= vaddr_range_spec::<KernelPtConfig>().end + 1
2469 } by {
2470 let i = choose|i: int|
2471 owner.level - 1 <= i < NR_LEVELS && (
2472 #[trigger] owner.continuations[i]).view_mappings().contains(m);
2473 let cont = owner.continuations[i];
2474 cont.lemma_view_mappings_contains();
2475 let j = choose|j: int|
2476 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
2477 cont.children[j].unwrap(),
2478 ).view_rec(cont.path().push_tail(j)).contains(m);
2479 let child = PageTableOwner(cont.children[j].unwrap());
2480 let p = cont.path().push_tail(j);
2481 child.view_rec_top_index_va_bound(p, m, end);
2482 }
2484}
2485
2486impl<'rcu, C: PageTableConfig> InvView for CursorOwner<'rcu, C> {
2487 proof fn view_preserves_inv(self) {
2488 self.view_non_overlapping();
2490 self.view_mapping_inv();
2493 lemma_view_in_vaddr_range::<C>(&self);
2496 }
2497}
2498
2499impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
2500 pub proof fn view_non_overlapping(self)
2506 requires
2507 self.inv(),
2508 ensures
2509 self@.non_overlapping(),
2510 {
2511 self.as_page_table_owner_view_non_overlapping();
2512 }
2513}
2514
2515impl<'rcu, C: PageTableConfig, A: InAtomicMode> Inv for Cursor<'rcu, C, A> {
2516 open spec fn inv(self) -> bool {
2517 &&& 1 <= self.level <= NR_LEVELS
2525 + 1
2526 &&& self.level <= self.guard_level + 1
2534 &&& self.guard_level
2535 <= NR_LEVELS
2536 &&& self.va >= self.barrier_va.start
2538 &&& self.va % PAGE_SIZE == 0
2539 }
2540}
2541
2542impl<'rcu, C: PageTableConfig, A: InAtomicMode> OwnerOf for Cursor<'rcu, C, A> {
2543 type Owner = CursorOwner<'rcu, C>;
2544
2545 open spec fn wf(self, owner: Self::Owner) -> bool {
2546 &&& owner.va.reflect(self.va)
2547 &&& self.level == owner.level
2548 &&& owner.guard_level
2549 == self.guard_level
2550 &&& self.level <= 4 ==> {
2559 &&& 4 <= self.guard_level ==> {
2560 &&& self.path[3] is Some
2561 &&& owner.continuations.contains_key(3)
2562 &&& owner.continuations[3].guard == self.path[3]->0
2563 }
2564 &&& 4 > self.guard_level ==> self.path[3] is None
2565 }
2566 &&& self.level <= 3 ==> {
2567 &&& 3 <= self.guard_level ==> {
2568 &&& self.path[2] is Some
2569 &&& owner.continuations.contains_key(2)
2570 &&& owner.continuations[2].guard == self.path[2]->0
2571 }
2572 &&& 3 > self.guard_level ==> self.path[2] is None
2573 }
2574 &&& self.level <= 2 ==> {
2575 &&& 2 <= self.guard_level ==> {
2576 &&& self.path[1] is Some
2577 &&& owner.continuations.contains_key(1)
2578 &&& owner.continuations[1].guard == self.path[1]->0
2579 }
2580 &&& 2 > self.guard_level ==> self.path[1] is None
2581 }
2582 &&& self.level == 1 ==> {
2583 &&& 1 <= self.guard_level ==> {
2587 &&& self.path[0] is Some
2588 &&& owner.continuations.contains_key(0)
2589 &&& owner.continuations[0].guard == self.path[0]->0
2590 }
2591 &&& 1 > self.guard_level ==> self.path[0] is None
2592 }
2593 &&& self.barrier_va.start == owner.locked_range().start
2594 &&& self.barrier_va.end == owner.locked_range().end
2595 }
2596}
2597
2598}