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 #[verifier::spinoff_prover]
945 pub proof fn do_inc_index(tracked &mut self)
946 requires
947 old(self).inv(),
948 old(self).level <= old(self).guard_level,
949 old(self).in_locked_range(),
950 old(self).continuations[old(self).level - 1].idx + 1 < NR_ENTRIES,
951 old(self).level == NR_LEVELS ==> (old(self).continuations[old(self).level - 1].idx + 1)
952 <= C::TOP_LEVEL_INDEX_RANGE().end,
953 ensures
954 final(self).inv(),
955 *final(self) == old(self).inc_index(),
956 {
957 self.popped_too_high = false;
958 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
959 cont.do_inc_index();
960 self.va = AbstractVaddr {
961 index: self.va.index.insert(self.level - 1, cont.idx as int),
962 ..self.va
963 };
964 self.continuations.tracked_insert(self.level - 1, cont);
965 assert(self.continuations == old(self).continuations.insert(self.level - 1, cont));
966
967 old(self).va.index_increment_adds_page_size(old(self).level as int);
968
969 if old(self).popped_too_high {
970 old(self).in_locked_range_prefix_match();
971 }
972 assert(self.va.inv());
973 }
974
975 pub proof fn inv_continuation(self, i: int)
976 requires
977 self.inv(),
978 self.level - 1 <= i <= NR_LEVELS - 1,
979 ensures
980 self.continuations.contains_key(i),
981 self.continuations[i].inv(),
982 self.continuations[i].children.len() == NR_ENTRIES,
983 {
984 }
985
986 pub open spec fn view_mappings(self) -> Set<Mapping> {
987 self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS).map_values(
988 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
989 ).values().flatten()
990 }
991
992 pub broadcast proof fn lemma_view_mappings_contains(self)
993 requires
994 1 <= self.level <= NR_LEVELS,
995 ensures
996 #![trigger self.view_mappings()]
997 forall|m: Mapping| #[trigger]
998 self.view_mappings().contains(m) ==> exists|i: int|
999 #![trigger self.continuations[i]]
1000 self.level - 1 <= i < NR_LEVELS
1001 && self.continuations[i].view_mappings().contains(m),
1002 {
1003 broadcast use vstd::map_lib::group_map_properties;
1004
1005 assert forall|m: Mapping| #[trigger] self.view_mappings().contains(m) implies exists|i: int|
1006
1007 #![trigger self.continuations[i]]
1008 self.level - 1 <= i < NR_LEVELS && self.continuations[i].view_mappings().contains(
1009 m,
1010 ) by {
1011 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
1012 let mapped = filtered.map_values(
1013 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
1014 );
1015 let values = mapped.values();
1016 let elem_s = choose|elem_s: Set<Mapping>| #[trigger]
1017 values.contains(elem_s) && elem_s.contains(m);
1018 let i = choose|i: int| #[trigger] mapped.dom().contains(i) && mapped[i] == elem_s;
1019 }
1020 }
1021
1022 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
1023 requires
1024 1 <= self.level <= NR_LEVELS,
1025 self.level - 1 <= i < NR_LEVELS,
1026 self.continuations.contains_key(i),
1027 #[trigger] self.continuations[i].view_mappings().contains(m),
1028 ensures
1029 self.view_mappings().contains(m),
1030 {
1031 broadcast use vstd::map_lib::group_map_properties;
1032
1033 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
1034 let mapped = filtered.map_values(|cont: CursorContinuation<'rcu, C>| cont.view_mappings());
1035 let values = mapped.values();
1036 assert(values.contains(mapped[i]));
1037 values.lemma_flatten_contains(m);
1038 }
1039
1040 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
1041 if self.level == 1 {
1042 let l1 = self.continuations[0];
1043 let l2 = self.continuations[1].restore(l1).0;
1044 let l3 = self.continuations[2].restore(l2).0;
1045 let l4 = self.continuations[3].restore(l3).0;
1046 l4.as_page_table_owner()
1047 } else if self.level == 2 {
1048 let l2 = self.continuations[1];
1049 let l3 = self.continuations[2].restore(l2).0;
1050 let l4 = self.continuations[3].restore(l3).0;
1051 l4.as_page_table_owner()
1052 } else if self.level == 3 {
1053 let l3 = self.continuations[2];
1054 let l4 = self.continuations[3].restore(l3).0;
1055 l4.as_page_table_owner()
1056 } else {
1057 let l4 = self.continuations[3];
1058 l4.as_page_table_owner()
1059 }
1060 }
1061
1062 pub open spec fn cur_entry_owner(self) -> EntryOwner<C> {
1063 self.cur_subtree().value()
1064 }
1065
1066 pub open spec fn cur_subtree(self) -> OwnerSubtree<C> {
1067 self.continuations[self.level - 1].children[self.index() as int]->0
1068 }
1069
1070 pub proof fn cur_frame_clone_requires(
1085 self,
1086 item: C::Item,
1087 pa: Paddr,
1088 level: PagingLevel,
1089 prop: PageProperty,
1090 regions: MetaRegionOwners,
1091 )
1092 requires
1093 self.inv(),
1094 regions.inv(),
1095 self.metaregion_sound(regions),
1096 self.cur_entry_owner().is_frame(),
1097 pa == self.cur_entry_owner().frame().mapped_pa,
1098 C::item_from_raw_spec(pa, level, prop) == item,
1099 valid_frame_paddr(pa),
1100 C::raw_item_well_formed(pa, level, prop),
1101 C::tracked(item) == self.cur_entry_owner().frame_is_tracked(),
1103 C::tracked(item) ==> (regions.slot_owners[frame_to_index(
1105 pa,
1106 )].inner_perms.ref_count.value() < REF_COUNT_MAX || may_panic()),
1107 ensures
1108 item.clone_requires(regions),
1109 {
1110 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1111
1112 let entry = self.cur_entry_owner();
1113 let idx = frame_to_index(pa);
1114 EntryOwner::<C>::axiom_frame_is_tracked_iff_not_mmio(entry);
1115 C::lemma_clone_requires_concrete(item, pa, level, prop, regions);
1116 }
1117
1118 pub proof fn clone_item_preserves_invariants(
1121 self,
1122 old_regions: MetaRegionOwners,
1123 new_regions: MetaRegionOwners,
1124 idx: int,
1125 )
1126 requires
1127 self.inv(),
1128 self.metaregion_sound(old_regions),
1129 old_regions.inv(),
1130 self.cur_entry_owner().is_frame(),
1131 idx == frame_to_index(self.cur_entry_owner().frame().mapped_pa),
1132 old_regions.slot_owners.contains_key(idx),
1133 new_regions.slot_owners.contains_key(idx),
1134 new_regions.slot_owners[idx].inner_perms.ref_count.value()
1136 == old_regions.slot_owners[idx].inner_perms.ref_count.value() + 1,
1137 new_regions.slot_owners[idx].inner_perms.ref_count.id()
1139 == old_regions.slot_owners[idx].inner_perms.ref_count.id(),
1140 new_regions.slot_owners[idx].inner_perms.storage
1141 == old_regions.slot_owners[idx].inner_perms.storage,
1142 new_regions.slot_owners[idx].inner_perms.vtable_ptr
1143 == old_regions.slot_owners[idx].inner_perms.vtable_ptr,
1144 new_regions.slot_owners[idx].inner_perms.in_list
1145 == old_regions.slot_owners[idx].inner_perms.in_list,
1146 new_regions.slot_owners[idx].paths_in_pt == old_regions.slot_owners[idx].paths_in_pt,
1148 new_regions.slot_owners[idx].slot_vaddr == old_regions.slot_owners[idx].slot_vaddr,
1149 new_regions.slot_owners[idx].usage == old_regions.slot_owners[idx].usage,
1150 new_regions.slot_owners.dom() == old_regions.slot_owners.dom(),
1152 forall|i: int|
1153 #![trigger new_regions.slot_owners[i]]
1154 i != idx && old_regions.slot_owners.contains_key(i) ==> new_regions.slot_owners[i]
1155 == old_regions.slot_owners[i],
1156 new_regions.slots == old_regions.slots,
1158 0 < old_regions.slot_owners[idx].inner_perms.ref_count.value(),
1164 old_regions.slot_owners[idx].inner_perms.ref_count.value() + 1 <= REF_COUNT_MAX,
1165 ensures
1166 new_regions.inv(),
1167 self.metaregion_sound(new_regions),
1168 {
1169 self.metaregion_slot_owners_rc_increment(old_regions, new_regions, idx);
1170 }
1171
1172 pub proof fn new_child_mappings_eq_target(
1175 self,
1176 new_subtree: OwnerSubtree<C>,
1177 pa: Paddr,
1178 level: PagingLevel,
1179 prop: PageProperty,
1180 )
1181 requires
1182 self.inv(),
1183 self.in_locked_range(),
1184 level == self.level,
1185 new_subtree.inv(),
1186 new_subtree.value().is_frame(),
1187 new_subtree.value().path == self.continuations[self.level - 1].path().push_tail(
1188 self.continuations[self.level - 1].idx as int,
1189 ),
1190 new_subtree.value().frame().mapped_pa == pa,
1191 new_subtree.value().frame().prop == prop,
1192 ensures
1193 PageTableOwner(new_subtree)@.mappings
1194 == set![Mapping {
1195 va_range: self@.cur_slot_range(page_size(level)),
1196 pa_range: pa..(pa + page_size(level)) as usize,
1197 page_size: page_size(level),
1198 property: prop,
1199 }],
1200 {
1201 let path = new_subtree.value().path;
1202 let ps = page_size(level);
1203 let cont = self.continuations[self.level - 1];
1204
1205 self.cur_va_in_subtree_range();
1210 assert(vaddr_of::<C>(path) == nat_align_down(self@.cur_va as nat, ps as nat) as Vaddr) by {
1211 self.va.to_path_vaddr_concrete(self.level - 1);
1212 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
1213 let va_path = self.va.to_path(self.level - 1);
1214 self.va.to_path_len(self.level - 1);
1215 self.va.to_path_inv(self.level - 1);
1216 self.cur_subtree_inv();
1217 assert forall|i: int| 0 <= i < path.len() implies path[i] == va_path[i] by {
1218 self.va.to_path_index(self.level - 1, i);
1219 };
1220 AbstractVaddr::rec_vaddr_eq_if_indices_eq(path, va_path, 0);
1221 };
1222 let target = Mapping {
1227 va_range: self@.cur_slot_range(page_size(level)),
1228 pa_range: pa..(pa + page_size(level)) as usize,
1229 page_size: page_size(level),
1230 property: prop,
1231 };
1232 let from_view = Mapping {
1233 va_range: Range { start: vaddr_of::<C>(path) as int, end: vaddr_of::<C>(path) + ps },
1234 pa_range: pa..(pa + ps) as usize,
1235 page_size: ps,
1236 property: prop,
1237 };
1238 let nad = nat_align_down(self@.cur_va as nat, ps as nat);
1241 assert(nad <= self@.cur_va as nat) by {
1242 vstd_extra::arithmetic::lemma_nat_align_down_sound(self@.cur_va as nat, ps as nat);
1243 };
1244 }
1245
1246 pub open spec fn locked_range(self) -> Range<Vaddr> {
1247 let start = self.prefix.align_down(self.guard_level as int).to_vaddr();
1248 let end = self.prefix.align_up(self.guard_level as int).to_vaddr();
1249 Range { start, end }
1250 }
1251
1252 pub open spec fn in_locked_range(self) -> bool {
1253 self.locked_range().start <= self.va.to_vaddr() < self.locked_range().end
1254 }
1255
1256 pub open spec fn above_locked_range(self) -> bool {
1257 self.va.to_vaddr() >= self.locked_range().end
1258 }
1259
1260 pub proof fn inc_at_guard_level_above_locked_range(
1262 old_va: AbstractVaddr,
1263 prefix: AbstractVaddr,
1264 guard_level: u8,
1265 level: u8,
1266 new_va_val: Vaddr,
1267 )
1268 requires
1269 old_va.inv(),
1270 prefix.inv(),
1271 1 <= guard_level <= NR_LEVELS,
1272 level == guard_level,
1273 new_va_val == old_va.to_vaddr() + page_size(level as PagingLevel),
1274 prefix.align_down(guard_level as int).to_vaddr() <= old_va.to_vaddr(),
1275 old_va.to_vaddr() < prefix.align_up(guard_level as int).to_vaddr(),
1276 prefix.align_down(guard_level as int).to_vaddr() + page_size(guard_level as PagingLevel)
1278 <= usize::MAX,
1279 ensures
1280 new_va_val >= prefix.align_up(guard_level as int).to_vaddr(),
1281 {
1282 let ps_gl = page_size(guard_level as PagingLevel);
1283 lemma_page_size_ge_page_size(guard_level as PagingLevel);
1284 let aligned = prefix.align_down(guard_level as int);
1285 prefix.align_down_concrete(guard_level as int);
1286 prefix.align_down_shape(guard_level as int);
1287
1288 assert(aligned.to_vaddr() as nat % ps_gl as nat == 0) by {
1294 vstd_extra::arithmetic::lemma_nat_align_down_sound(
1295 prefix.to_vaddr() as nat,
1296 ps_gl as nat,
1297 );
1298 prefix.to_vaddr_bounded();
1299 aligned.reflect_prop(nat_align_down(prefix.to_vaddr() as nat, ps_gl as nat) as Vaddr);
1300 };
1301 aligned.aligned_align_up_advances(guard_level as int);
1303 aligned.aligned_align_down_is_self(guard_level as int);
1308 }
1309
1310 pub proof fn prefix_in_locked_range(self)
1311 requires
1312 self.inv(),
1313 !self.popped_too_high,
1314 self.level < self.guard_level,
1315 ensures
1316 self.in_locked_range(),
1317 {
1318 let gl = self.guard_level;
1319 if gl >= 1 && gl <= NR_LEVELS {
1320 self.va.align_down_to_vaddr_eq_if_upper_indices_eq(self.prefix, gl as int);
1324 self.va.align_down_concrete(gl as int);
1325 self.prefix.align_down_concrete(gl as int);
1326 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1327 nat_align_down(
1328 self.va.to_vaddr() as nat,
1329 page_size(gl as PagingLevel) as nat,
1330 ) as Vaddr,
1331 );
1332 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1333 nat_align_down(
1334 self.prefix.to_vaddr() as nat,
1335 page_size(gl as PagingLevel) as nat,
1336 ) as Vaddr,
1337 );
1338 lemma_page_size_ge_page_size(gl as PagingLevel);
1339
1340 self.prefix_aligned_to_guard_level();
1342 self.prefix_plus_ps_no_overflow();
1343 self.prefix.aligned_align_up_advances(gl as int);
1344 }
1345 }
1346
1347 pub proof fn in_locked_range_prefix_match(self)
1350 requires
1351 self.inv(),
1352 self.prefix.inv(),
1353 1 <= self.guard_level <= NR_LEVELS,
1354 self.in_locked_range(),
1355 ensures
1356 forall|i: int|
1357 self.guard_level <= i < NR_LEVELS ==> self.va.index[i] == self.prefix.index[i],
1358 {
1359 let gl = self.guard_level;
1360 let start = self.prefix.align_down(gl as int).to_vaddr();
1361
1362 let prefix_ad = self.prefix.align_down(gl as int);
1364
1365 self.prefix.align_down_concrete(gl as int);
1367 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1368 nat_align_down(
1369 self.prefix.to_vaddr() as nat,
1370 page_size(gl as PagingLevel) as nat,
1371 ) as Vaddr,
1372 );
1373 lemma_page_size_ge_page_size(gl as PagingLevel);
1374 lemma_nat_align_down_sound(
1375 self.prefix.to_vaddr() as nat,
1376 page_size(gl as PagingLevel) as nat,
1377 );
1378
1379 self.prefix_aligned_to_guard_level();
1381 self.prefix_plus_ps_no_overflow();
1382 self.prefix.aligned_align_up_advances(gl as int);
1383
1384 if gl >= 2 && gl < NR_LEVELS {
1385 AbstractVaddr::same_node_indices_match(
1388 self.va.to_vaddr(),
1389 self.prefix.to_vaddr(),
1390 start,
1391 (gl - 1) as PagingLevel,
1392 );
1393 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1395 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1396 } else if gl == 1 {
1397 let ps1 = page_size(1 as PagingLevel) as nat;
1401 let ps2 = page_size(2 as PagingLevel) as nat;
1402 let pv = self.prefix.to_vaddr() as nat;
1403 let cv = self.va.to_vaddr() as nat;
1404 let node_start = nat_align_down(pv, ps2) as usize;
1405
1406 lemma_page_size_ge_page_size(1 as PagingLevel);
1407 page_size_monotonic(1 as PagingLevel, 2 as PagingLevel);
1408 lemma_page_size_divides(1 as PagingLevel, 2 as PagingLevel);
1409 lemma_nat_align_down_sound(pv, ps2);
1410
1411 lemma_nat_align_down_within_block(pv, ps1, ps2);
1412
1413 AbstractVaddr::same_node_indices_match(
1414 self.va.to_vaddr(),
1415 self.prefix.to_vaddr(),
1416 node_start,
1417 1 as PagingLevel,
1418 );
1419 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1420 }
1421 }
1422
1423 #[verifier::rlimit(2000)]
1427 pub proof fn in_locked_range_guard_index_eq_prefix(self)
1428 requires
1429 self.inv(),
1430 self.prefix.inv(),
1431 1 <= self.guard_level <= NR_LEVELS,
1432 self.in_locked_range(),
1433 ensures
1434 self.va.index[self.guard_level - 1] == self.prefix.index[self.guard_level - 1],
1435 {
1436 let gl = self.guard_level;
1437 let start = self.prefix.align_down(gl as int).to_vaddr();
1438
1439 self.prefix.align_down_concrete(gl as int);
1440 self.prefix_aligned_to_guard_level();
1443 self.prefix_plus_ps_no_overflow();
1444 self.prefix.aligned_align_up_advances(gl as int);
1445 lemma_page_size_ge_page_size(gl as PagingLevel);
1446
1447 self.prefix.align_down(gl as int).reflect_prop(
1448 nat_align_down(
1449 self.prefix.to_vaddr() as nat,
1450 page_size(gl as PagingLevel) as nat,
1451 ) as Vaddr,
1452 );
1453
1454 let ps = page_size(gl as PagingLevel);
1462 let va_val = self.va.to_vaddr();
1463 let k = start as int / ps as int;
1464 assert(start == k * ps) by {
1465 lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps as nat);
1466 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps as int);
1467 };
1468 assert(va_val as int / ps as int == k) by {
1470 let r = va_val - start;
1471 vstd::arithmetic::div_mod::lemma_fundamental_div_mod_converse(
1472 va_val as int,
1473 ps as int,
1474 k,
1475 r,
1476 );
1477 };
1478 use crate::specs::mm::page_table::cursor::page_size_lemmas::*;
1497 lemma_page_size_spec_values();
1498 vstd::arithmetic::power2::lemma2_to64();
1501 vstd::arithmetic::power2::lemma2_to64_rest();
1502 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1505 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1506 }
1507
1508 pub proof fn in_locked_range_level_le_nr_levels(self)
1509 requires
1510 self.inv(),
1511 self.in_locked_range(),
1512 !self.popped_too_high,
1513 ensures
1514 self.level <= NR_LEVELS,
1515 {
1516 }
1517
1518 pub proof fn in_locked_range_top_index_lt_top_end(self)
1522 requires
1523 self.inv(),
1524 self.in_locked_range(),
1525 !self.popped_too_high,
1526 ensures
1527 self.va.index[NR_LEVELS - 1] < C::TOP_LEVEL_INDEX_RANGE().end,
1528 {
1529 if self.guard_level == NR_LEVELS {
1530 if self.level < self.guard_level {
1531 } else {
1533 self.in_locked_range_guard_index_eq_prefix();
1544 }
1545 }
1546 }
1547
1548 pub proof fn in_locked_range_level_le_guard_level(self)
1549 requires
1550 self.inv(),
1551 self.in_locked_range(),
1552 !self.popped_too_high,
1553 ensures
1554 self.level <= self.guard_level,
1555 {
1556 }
1557
1558 pub proof fn cursor_top_idx_strict_lt_nr_entries(self)
1574 requires
1575 self.inv(),
1576 self.in_locked_range(),
1577 !self.popped_too_high,
1578 self.level == NR_LEVELS,
1579 self.guard_level == NR_LEVELS,
1580 ensures
1581 self.continuations[self.level - 1].idx + 1 < NR_ENTRIES,
1582 {
1583 self.in_locked_range_guard_index_eq_prefix();
1584 }
1585
1586 pub proof fn locked_range_span(self)
1594 requires
1595 self.inv(),
1596 ensures
1597 self.locked_range().start as nat == nat_align_down(
1598 self.prefix.to_vaddr() as nat,
1599 page_size(self.guard_level as PagingLevel) as nat,
1600 ),
1601 self.locked_range().start as nat % page_size(self.guard_level as PagingLevel) as nat
1602 == 0,
1603 self.locked_range().end - self.locked_range().start == page_size(
1604 self.guard_level as PagingLevel,
1605 ),
1606 {
1607 let gl = self.guard_level;
1608 let ps_gl = page_size(gl as PagingLevel) as nat;
1609 let pv = self.prefix.to_vaddr() as nat;
1610
1611 lemma_page_size_ge_page_size(gl as PagingLevel);
1612 self.prefix.align_down_concrete(gl as int);
1613 self.prefix_aligned_to_guard_level();
1614 self.prefix_plus_ps_no_overflow();
1615 self.prefix.aligned_align_up_advances(gl as int);
1616 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(pv, ps_gl) as Vaddr);
1617 }
1618
1619 pub proof fn in_node_holds_at_guard(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1627 requires
1628 self.inv(),
1629 self.in_locked_range(),
1630 self.va.reflect(self_va),
1631 node_size == page_size((self.guard_level + 1) as PagingLevel),
1632 self.locked_range().start <= va < self.locked_range().end,
1633 ensures
1634 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1635 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1636 {
1637 let gl = self.guard_level;
1638 let pg = page_size(gl as PagingLevel) as nat;
1639 let pg1 = node_size as nat;
1640 let ls = self.locked_range().start as nat;
1641
1642 lemma_page_size_ge_page_size((gl + 1) as PagingLevel);
1644
1645 self.locked_range_span();
1646 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(
1647 gl as PagingLevel,
1648 (gl + 1) as PagingLevel,
1649 );
1650 self.va.reflect_prop(self_va);
1651 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg1);
1657 assert(nat_align_down(self_va as nat, pg) == ls) by {
1660 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg);
1661 let nad = nat_align_down(self_va as nat, pg) as int;
1662 let lsi = ls as int;
1663 let pgi = pg as int;
1664 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(nad, pgi);
1668 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(lsi, pgi);
1669 let kn = nad / pgi;
1670 let kl = lsi / pgi;
1671 assert(nad - lsi == pgi * (kn - kl)) by (nonlinear_arith)
1672 requires
1673 nad == pgi * kn,
1674 lsi == pgi * kl,
1675 ;
1676 assert(kn - kl == 0) by (nonlinear_arith)
1677 requires
1678 0 <= pgi * (kn - kl) < pgi,
1679 pgi > 0,
1680 ;
1681 };
1682 vstd_extra::arithmetic::lemma_nat_align_down_monotone(self_va as nat, pg, pg1);
1683 vstd_extra::arithmetic::lemma_nat_align_down_within_block(self_va as nat, pg, pg1);
1684 }
1691
1692 #[verifier::rlimit(20000)]
1694 pub proof fn node_within_locked_range(self, level: PagingLevel)
1695 requires
1696 self.inv(),
1697 self.in_locked_range(),
1698 1 <= level < self.guard_level,
1699 ensures
1700 self.locked_range().start <= nat_align_down(
1701 self.va.to_vaddr() as nat,
1702 page_size((level + 1) as PagingLevel) as nat,
1703 ) as usize,
1704 nat_align_down(
1705 self.va.to_vaddr() as nat,
1706 page_size((level + 1) as PagingLevel) as nat,
1707 ) as usize + page_size((level + 1) as PagingLevel) <= self.locked_range().end,
1708 {
1709 let gl = self.guard_level;
1710 let ps_gl = page_size(gl as PagingLevel) as nat;
1711 let ps = page_size((level + 1) as PagingLevel) as nat;
1712 let va = self.va.to_vaddr() as nat;
1713 let start = self.locked_range().start as nat;
1714
1715 lemma_page_size_ge_page_size(gl as PagingLevel);
1716 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1717 lemma_page_size_divides((level + 1) as PagingLevel, gl as PagingLevel);
1718 self.locked_range_span();
1719
1720 vstd::arithmetic::div_mod::lemma_indistinguishable_quotients(
1721 start as int,
1722 va as int,
1723 ps_gl as int,
1724 );
1725 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps_gl as int);
1726 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(va as int, ps_gl as int);
1727
1728 lemma_nat_align_down_sound(va, ps);
1729 lemma_nat_align_down_monotone(va, ps, ps_gl);
1730 lemma_nat_align_down_within_block(va, ps, ps_gl);
1731 }
1732
1733 pub proof fn prefix_aligned_to_guard_level(self)
1737 requires
1738 self.inv(),
1739 ensures
1740 self.prefix.to_vaddr() as nat % page_size(self.guard_level as PagingLevel) as nat == 0,
1741 {
1742 let gl = self.guard_level;
1743 let ps = page_size(gl as PagingLevel) as nat;
1744 lemma_page_size_ge_page_size(gl as PagingLevel);
1745
1746 self.prefix.align_down_shape(gl as int);
1749 self.prefix.align_down_leading_bits(gl as int);
1750 let aligned = self.prefix.align_down(gl as int);
1751
1752 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] aligned.index[i]
1753 == self.prefix.index[i] by {};
1754 assert(aligned.index == self.prefix.index);
1755
1756 self.prefix.align_down_concrete(gl as int);
1758 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps);
1759 aligned.reflect_prop(nat_align_down(self.prefix.to_vaddr() as nat, ps) as Vaddr);
1760 }
1761
1762 pub proof fn in_node_holds_at_top(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1775 requires
1776 self.inv(),
1777 self.va.reflect(self_va),
1778 self.guard_level == NR_LEVELS,
1779 node_size == page_size((NR_LEVELS + 1) as PagingLevel),
1780 self.locked_range().start <= va < self.locked_range().end,
1781 ensures
1782 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1783 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1784 {
1785 let gl = self.guard_level;
1786
1787 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
1788 self.prefix.to_vaddr_indices_drop_zero_range(0, NR_LEVELS as int);
1793
1794 self.prefix_aligned_to_guard_level();
1796 self.prefix.aligned_align_up_advances(gl as int);
1797 self.prefix.align_down_shape(gl as int);
1799 self.prefix.align_down_leading_bits(gl as int);
1800 let aligned = self.prefix.align_down(gl as int);
1801 assert(aligned.index == self.prefix.index);
1802
1803 self.va.reflect_prop(self_va); }
1810
1811 pub proof fn prefix_plus_ps_no_overflow(self)
1817 requires
1818 self.inv(),
1819 ensures
1820 self.prefix.to_vaddr() + page_size(self.guard_level as PagingLevel) <= usize::MAX,
1821 {
1822 let gl = self.guard_level;
1823 self.prefix.to_vaddr_bounded();
1824 self.prefix.to_vaddr_indices_gap_bound(0);
1825 vstd::arithmetic::power2::lemma2_to64();
1826 vstd::arithmetic::power2::lemma2_to64_rest();
1827 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
1828
1829 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
1830 self.prefix.to_vaddr_indices_gap_bound(gl as int);
1831 }
1832
1833 pub proof fn va_plus_page_size_no_overflow(self, level: PagingLevel)
1843 requires
1844 self.inv(),
1845 self.in_locked_range(),
1846 1 <= level <= self.guard_level,
1847 ensures
1848 self.va.to_vaddr() + page_size(level) <= usize::MAX,
1849 {
1850 let gl = self.guard_level;
1851 lemma_page_size_ge_page_size(gl as PagingLevel);
1852 lemma_page_size_ge_page_size(level as PagingLevel);
1853 page_size_monotonic(level as PagingLevel, gl as PagingLevel);
1854
1855 self.prefix_aligned_to_guard_level();
1857 self.prefix_plus_ps_no_overflow();
1858 self.prefix.aligned_align_up_advances(gl as int);
1859
1860 self.prefix.to_vaddr_indices_gap_bound(0);
1863 vstd::arithmetic::power2::lemma2_to64();
1864 vstd::arithmetic::power2::lemma2_to64_rest();
1865 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
1866
1867 assert forall|i: int| 0 <= i < gl implies self.prefix.index[i] == 0 by {
1868 assert(self.prefix.index.contains_key(i));
1869 };
1870 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
1871 self.prefix.to_vaddr_indices_gap_bound(gl as int);
1872 }
1873
1874 pub proof fn locked_range_page_aligned(self)
1875 requires
1876 self.inv(),
1877 ensures
1878 self.locked_range().end % PAGE_SIZE == 0,
1879 self.locked_range().start % PAGE_SIZE == 0,
1880 {
1881 let gl = self.guard_level;
1882 let pv = self.prefix.to_vaddr() as nat;
1883 let ps = page_size(gl as PagingLevel) as nat;
1884 lemma_page_size_ge_page_size(gl as PagingLevel);
1885 lemma_page_size_divides(1u8, gl as PagingLevel);
1886 let start_va = nat_align_down(pv, ps);
1887 let end_va = nat_align_up(pv, ps);
1888 vstd::arithmetic::div_mod::lemma_mod_mod(
1889 start_va as int,
1890 PAGE_SIZE as int,
1891 ps as int / PAGE_SIZE as int,
1892 );
1893 self.prefix.align_down_concrete(gl as int);
1894 self.prefix_aligned_to_guard_level();
1895 self.prefix_plus_ps_no_overflow();
1896 self.prefix.aligned_align_up_advances(gl as int);
1897
1898 vstd::arithmetic::power2::lemma2_to64();
1899 vstd_extra::external::ilog2::lemma_pow2_increases(49nat, 64nat);
1900
1901 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(start_va as Vaddr);
1902 }
1903
1904 pub proof fn cur_subtree_inv(self)
1905 requires
1906 self.inv(),
1907 ensures
1908 self.cur_subtree().inv(),
1909 {
1910 let cont = self.continuations[self.level - 1];
1911 cont.inv_children_unroll(cont.idx as int)
1912 }
1913
1914 pub proof fn cur_entry_absent_not_present(self)
1916 requires
1917 self.inv(),
1918 self.in_locked_range(),
1919 self.cur_entry_owner().is_absent(),
1920 ensures
1921 !self@.present(),
1922 {
1923 self.cur_subtree_inv();
1924 let cur_va = self.cur_va();
1925 let cur_subtree = self.cur_subtree();
1926 let cur_path = cur_subtree.value().path;
1927 PageTableOwner(cur_subtree).view_rec_absent_empty(cur_path);
1928
1929 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1930 <= cur_va < m.va_range.end) by {
1931 if m.va_range.start <= cur_va < m.va_range.end {
1932 self.mapping_covering_cur_va_from_cur_subtree(m);
1933 }
1934 };
1935
1936 let filtered = self@.mappings.filter(
1937 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1938 );
1939 assert(filtered == set![]) by {};
1940 }
1941
1942 pub proof fn cur_subtree_empty_not_present(self)
1944 requires
1945 self.inv(),
1946 self.in_locked_range(),
1947 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value().path) =~= set![],
1948 ensures
1949 !self@.present(),
1950 {
1951 let cur_va = self.cur_va();
1952
1953 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
1954 <= cur_va < m.va_range.end) by {
1955 if m.va_range.start <= cur_va < m.va_range.end {
1956 self.mapping_covering_cur_va_from_cur_subtree(m);
1957 }
1958 };
1959
1960 let filtered = self@.mappings.filter(
1961 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
1962 );
1963 assert(filtered == set![]) by {};
1964 }
1965
1966 pub proof fn cur_entry_frame_present(self)
1967 requires
1968 self.inv(),
1969 self.in_locked_range(),
1970 self.cur_entry_owner().is_frame(),
1971 ensures
1972 self@.present(),
1973 self@.query(
1974 self.cur_entry_owner().frame().mapped_pa,
1975 page_size(self.cur_entry_owner().parent_level),
1976 self.cur_entry_owner().frame().prop,
1977 ),
1978 {
1979 self.cur_subtree_inv();
1980 self.cur_va_in_subtree_range();
1981 self.view_preserves_inv();
1982 let subtree = self.cur_subtree();
1983 let path = subtree.value().path;
1984 let frame = self.cur_entry_owner().frame();
1985 let pt_level = INC_LEVELS - path.len();
1986 let cont = self.continuations[self.level - 1];
1987
1988 let m = Mapping {
1989 va_range: Range {
1990 start: vaddr_of::<C>(path) as int,
1991 end: vaddr_of::<C>(path) + page_size(pt_level as PagingLevel),
1992 },
1993 pa_range: Range {
1994 start: frame.mapped_pa,
1995 end: (frame.mapped_pa + page_size(pt_level as PagingLevel)) as Paddr,
1996 },
1997 page_size: page_size(pt_level as PagingLevel),
1998 property: frame.prop,
1999 };
2000 assert(PageTableOwner(subtree).view_rec(path) == set![m]);
2001 cont.lemma_view_mappings_intro(m, cont.idx as int);
2002 self.lemma_view_mappings_intro(m, self.level - 1);
2003 assert(m.va_range.start <= self@.cur_va < m.va_range.end) by {
2004 self.cur_va_in_subtree_range();
2005 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
2006 };
2007
2008 let filtered = self@.mappings.filter(
2009 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
2010 );
2011 assert(filtered.contains(m));
2012 lemma_set_contains_len(filtered, m);
2013 }
2014
2015 pub open spec fn path_metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2017 forall|i: int|
2018 #![trigger self.continuations[i]]
2019 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].entry_own.metaregion_sound(
2020 regions,
2021 )
2022 }
2023
2024 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2025 &&& self.map_full_tree(
2026 |entry_owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2027 entry_owner.metaregion_sound(regions),
2028 )
2029 &&& self.path_metaregion_sound(regions)
2030 }
2031
2032 pub proof fn metaregion_preserved(
2033 self,
2034 other: Self,
2035 regions0: MetaRegionOwners,
2036 regions1: MetaRegionOwners,
2037 )
2038 requires
2039 self.inv(),
2040 self.metaregion_sound(regions0),
2041 self.level == other.level,
2042 self.continuations =~= other.continuations,
2043 OwnerSubtree::implies(
2044 PageTableOwner::<C>::metaregion_sound_pred(regions0),
2045 PageTableOwner::<C>::metaregion_sound_pred(regions1),
2046 ),
2047 ensures
2048 other.metaregion_sound(regions1),
2049 {
2050 let f = PageTableOwner::metaregion_sound_pred(regions0);
2051 let g = PageTableOwner::metaregion_sound_pred(regions1);
2052
2053 assert forall|i: int| #![auto] self.level - 1 <= i < NR_LEVELS implies {
2054 other.continuations[i].map_children(g)
2055 } by {
2056 let cont = self.continuations[i];
2057 assert forall|j: int|
2058 0 <= j < NR_ENTRIES
2059 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
2060 cont.path().push_tail(j), g) by {
2061 cont.inv_children_unroll(j);
2062 cont.children[j].unwrap().lemma_subtree_satisfies_implies(
2063 cont.path().push_tail(j),
2064 f,
2065 g,
2066 );
2067 };
2068 };
2069 assert(other.path_metaregion_sound(regions1)) by {
2070 assert forall|i: int|
2071 #![trigger other.continuations[i]]
2072 self.level - 1 <= i
2073 < NR_LEVELS implies other.continuations[i].entry_own.metaregion_sound(
2074 regions1,
2075 ) by {
2076 let eo = self.continuations[i].entry_own;
2077 assert(g(eo, self.continuations[i].path()));
2078 };
2079 };
2080 }
2081
2082 pub proof fn metaregion_slot_owners_preserved(
2084 self,
2085 regions0: MetaRegionOwners,
2086 regions1: MetaRegionOwners,
2087 )
2088 requires
2089 self.inv(),
2090 self.metaregion_sound(regions0),
2091 regions0.slot_owners =~= regions1.slot_owners,
2092 forall|k: int|
2093 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2094 forall|k: int|
2095 regions0.slots.contains_key(k) ==> regions0.slots[k]
2096 == #[trigger] regions1.slots[k],
2097 ensures
2098 self.metaregion_sound(regions1),
2099 {
2100 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2101 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2102 self.metaregion_preserved(self, regions0, regions1);
2103 }
2104
2105 pub proof fn metaregion_slot_owners_rc_increment(
2106 self,
2107 regions0: MetaRegionOwners,
2108 regions1: MetaRegionOwners,
2109 idx: int,
2110 )
2111 requires
2112 self.inv(),
2113 self.metaregion_sound(regions0),
2114 regions0.inv(),
2115 regions1.slots == regions0.slots,
2116 regions1.slot_owners.dom() == regions0.slot_owners.dom(),
2117 regions1.slot_owners[idx].inner_perms.ref_count.value()
2118 == regions0.slot_owners[idx].inner_perms.ref_count.value() + 1,
2119 regions1.slot_owners[idx].inner_perms.ref_count.id()
2120 == regions0.slot_owners[idx].inner_perms.ref_count.id(),
2121 regions1.slot_owners[idx].inner_perms.storage
2122 == regions0.slot_owners[idx].inner_perms.storage,
2123 regions1.slot_owners[idx].inner_perms.vtable_ptr
2124 == regions0.slot_owners[idx].inner_perms.vtable_ptr,
2125 regions1.slot_owners[idx].inner_perms.in_list
2126 == regions0.slot_owners[idx].inner_perms.in_list,
2127 regions1.slot_owners[idx].paths_in_pt == regions0.slot_owners[idx].paths_in_pt,
2128 regions1.slot_owners[idx].slot_vaddr == regions0.slot_owners[idx].slot_vaddr,
2129 regions1.slot_owners[idx].usage == regions0.slot_owners[idx].usage,
2130 regions1.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
2131 regions1.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX,
2133 forall|i: int|
2134 #![trigger regions1.slot_owners[i]]
2135 i != idx && regions0.slot_owners.contains_key(i) ==> regions1.slot_owners[i]
2136 == regions0.slot_owners[i],
2137 ensures
2138 self.metaregion_sound(regions1),
2139 {
2140 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2141 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2142 self.metaregion_preserved(self, regions0, regions1);
2143 }
2144
2145 pub proof fn metaregion_borrow_slot(
2148 self,
2149 regions0: MetaRegionOwners,
2150 regions1: MetaRegionOwners,
2151 changed_idx: int,
2152 )
2153 requires
2154 self.inv(),
2155 self.metaregion_sound(regions0),
2156 regions1.inv(),
2157 forall|k: int|
2158 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2159 forall|k: int|
2166 regions0.slots.contains_key(k) ==> regions0.slots[k]
2167 == #[trigger] regions1.slots[k],
2168 regions1.slot_owners[changed_idx].inner_perms
2170 == regions0.slot_owners[changed_idx].inner_perms,
2171 regions1.slot_owners[changed_idx].slot_vaddr
2172 == regions0.slot_owners[changed_idx].slot_vaddr,
2173 regions1.slot_owners[changed_idx].usage == regions0.slot_owners[changed_idx].usage,
2174 regions1.slot_owners[changed_idx].paths_in_pt
2175 == regions0.slot_owners[changed_idx].paths_in_pt,
2176 forall|i: int|
2178 #![trigger regions1.slot_owners[i]]
2179 i != changed_idx ==> regions0.slot_owners[i] == regions1.slot_owners[i],
2180 regions0.slot_owners.dom() =~= regions1.slot_owners.dom(),
2181 ensures
2182 self.metaregion_sound(regions1),
2183 {
2184 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2185 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2186 let nsp = PageTableOwner::<C>::not_in_scope_pred();
2187
2188 assert forall|i: int|
2189 #![trigger self.continuations[i]]
2190 self.level - 1 <= i < NR_LEVELS implies { self.continuations[i].map_children(g) } by {
2191 let cont = self.continuations[i];
2192 assert forall|j: int|
2193 0 <= j < NR_ENTRIES
2194 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
2195 cont.path().push_tail(j), nsp) by {
2196 PageTableOwner::tree_not_in_scope(
2197 cont.children[j].unwrap(),
2198 cont.path().push_tail(j),
2199 );
2200 };
2201 assert forall|j: int|
2202 0 <= j < NR_ENTRIES
2203 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
2204 cont.path().push_tail(j), g) by {
2205 cont.children[j].unwrap().lemma_subtree_satisfies_implies_and(
2206 cont.path().push_tail(j),
2207 f,
2208 nsp,
2209 g,
2210 );
2211 };
2212 };
2213
2214 }
2215
2216 pub proof fn cont_entries_metaregion(self, regions: MetaRegionOwners)
2226 requires
2227 self.inv(),
2228 self.metaregion_sound(regions),
2229 ensures
2230 forall|i: int|
2231 #![trigger self.continuations[i]]
2232 self.level - 1 <= i < NR_LEVELS
2233 ==> self.continuations[i].entry_own.metaregion_sound(regions),
2234 {
2235 }
2238
2239 pub open spec fn new(
2240 owner_subtree: OwnerSubtree<C>,
2241 idx: usize,
2242 guard: PageTableGuard<'rcu, C>,
2243 ) -> Self {
2244 let va = AbstractVaddr {
2245 offset: 0,
2246 index: Map::new(Set::<int>::range(0, NR_LEVELS as int), |i: int| 0).insert(
2247 NR_LEVELS - 1,
2248 idx as int,
2249 ),
2250 leading_bits: C::LEADING_BITS_spec() as int,
2256 };
2257 Self {
2258 level: NR_LEVELS as PagingLevel,
2259 continuations: Map::empty().insert(
2260 NR_LEVELS - 1,
2261 CursorContinuation::new(owner_subtree, idx, guard),
2262 ),
2263 va,
2264 guard_level: NR_LEVELS as PagingLevel,
2265 prefix: va,
2266 popped_too_high: false,
2267 }
2268 }
2269
2270 pub proof fn tracked_new(
2271 tracked owner_subtree: OwnerSubtree<C>,
2272 idx: usize,
2273 guard: PageTableGuard<'rcu, C>,
2274 ) -> tracked Self
2275 returns
2276 Self::new(owner_subtree, idx, guard),
2277 {
2278 let ghost va = AbstractVaddr {
2279 offset: 0,
2280 index: Map::new(Set::<int>::range(0, NR_LEVELS as int), |i: int| 0).insert(
2281 NR_LEVELS - 1,
2282 idx as int,
2283 ),
2284 leading_bits: C::LEADING_BITS_spec() as int,
2285 };
2286 let tracked continuation = CursorContinuation::tracked_new(owner_subtree, idx, guard);
2287 let tracked mut continuations = Map::tracked_empty();
2288 continuations.tracked_insert(NR_LEVELS - 1, continuation);
2289 Self {
2290 level: NR_LEVELS as PagingLevel,
2291 continuations,
2292 va,
2293 guard_level: NR_LEVELS as PagingLevel,
2294 prefix: va,
2295 popped_too_high: false,
2296 }
2297 }
2298
2299 pub broadcast group group_lemmas {
2300 CursorOwner::lemma_view_mappings_contains,
2301 CursorOwner::lemma_view_mappings_intro,
2302 }
2303}
2304
2305pub ghost struct CursorView<C: PageTableConfig> {
2306 pub cur_va: Vaddr,
2307 pub mappings: Set<Mapping>,
2308 pub phantom: PhantomData<C>,
2309}
2310
2311impl<'rcu, C: PageTableConfig> View for CursorOwner<'rcu, C> {
2312 type V = CursorView<C>;
2313
2314 open spec fn view(&self) -> Self::V {
2315 CursorView { cur_va: self.cur_va(), mappings: self.view_mappings(), phantom: PhantomData }
2316 }
2317}
2318
2319impl<C: PageTableConfig> Inv for CursorView<C> {
2320 open spec fn inv(self) -> bool {
2321 &&& forall|m: Mapping|
2322 #![auto]
2323 self.mappings.contains(m)
2324 ==> m.inv()
2325 &&& forall|m: Mapping|
2331 #![auto]
2332 self.mappings.contains(m) ==> {
2333 &&& vaddr_range_spec::<C>()@.start <= m.va_range.start
2334 &&& m.va_range.end <= vaddr_range_spec::<C>()@.end + 1
2335 }
2336 &&& self.non_overlapping()
2337 }
2338}
2339
2340impl<C: PageTableConfig> CursorView<C> {
2341 pub open spec fn non_overlapping(self) -> bool {
2344 forall|m: Mapping, n: Mapping|
2345 #![auto]
2346 self.mappings.contains(m) ==> self.mappings.contains(n) ==> m != n ==> m.va_range.end
2347 <= n.va_range.start || n.va_range.end <= m.va_range.start
2348 }
2349}
2350
2351pub proof fn lemma_view_in_vaddr_range<'rcu, C: PageTableConfig>(owner: &CursorOwner<'rcu, C>)
2354 requires
2355 owner.inv(),
2356 ensures
2357 forall|m: Mapping|
2358 #![auto]
2359 owner.view_mappings().contains(m) ==> {
2360 &&& vaddr_range_spec::<C>()@.start <= m.va_range.start
2361 &&& m.va_range.end <= vaddr_range_spec::<C>()@.end + 1
2362 },
2363{
2364 C::lemma_paging_consts_properties();
2365 C::lemma_page_table_config_constant_properties();
2366 lemma_arch_specific_consts_properties::<C>();
2367
2368 let idx = C::TOP_LEVEL_INDEX_RANGE();
2369 let start = idx.start as int;
2370 let end = idx.end as int;
2371 let lb = C::LEADING_BITS_spec() as int;
2372 let base = lb * 0x1_0000_0000_0000int;
2373 let cell = 0x80_0000_0000int;
2374 let bounds = vaddr_range_spec::<C>();
2375
2376 let end_exclusive = base + end * cell;
2377 let end_pre = end_exclusive - 1;
2378
2379 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2380 &&& vaddr_range_spec::<C>()@.start <= m.va_range.start
2381 &&& m.va_range.end <= vaddr_range_spec::<C>()@.end + 1
2382 } by {
2383 let i = choose|i: int|
2384 owner.level - 1 <= i < NR_LEVELS && (
2385 #[trigger] owner.continuations[i]).view_mappings().contains(m);
2386 owner.inv_continuation(i);
2387 let cont = owner.continuations[i];
2388 let j = choose|j: int|
2389 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
2390 cont.children[j].unwrap(),
2391 ).view_rec(cont.path().push_tail(j)).contains(m);
2392 cont.pt_inv_children_unroll(j);
2393 let child = PageTableOwner(cont.children[j].unwrap());
2394 let p = cont.path().push_tail(j);
2395 let pidx = p[0] as int;
2396 child.view_rec_top_index_va_bound(p, m, end);
2397 }
2398}
2399
2400pub proof fn lemma_view_in_vaddr_range_user<'rcu>(
2409 owner: &CursorOwner<'rcu, crate::mm::vm_space::UserPtConfig>,
2410)
2411 requires
2412 owner.inv(),
2413 ensures
2414 forall|m: Mapping|
2415 #![auto]
2416 owner.view_mappings().contains(m) ==> {
2417 &&& 0 <= m.va_range.start
2418 &&& m.va_range.end <= 0x8000_0000_0000int
2419 },
2420{
2421 let end = crate::mm::vm_space::UserPtConfig::TOP_LEVEL_INDEX_RANGE().end as int;
2422 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2423 &&& 0 <= m.va_range.start
2424 &&& m.va_range.end <= 0x8000_0000_0000int
2425 } by {
2426 let i = choose|i: int|
2427 owner.level - 1 <= i < NR_LEVELS && (
2428 #[trigger] owner.continuations[i]).view_mappings().contains(m);
2429 let cont = owner.continuations[i];
2430 let j = choose|j: int|
2431 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
2432 cont.children[j].unwrap(),
2433 ).view_rec(cont.path().push_tail(j)).contains(m);
2434 let child = PageTableOwner(cont.children[j].unwrap());
2435 let p = cont.path().push_tail(j);
2436 child.view_rec_top_index_va_bound(p, m, end);
2437 }
2438}
2439
2440pub proof fn lemma_view_in_vaddr_range_kernel<'rcu>(owner: CursorOwner<'rcu, KernelPtConfig>)
2445 requires
2446 owner.inv(),
2447 ensures
2448 forall|m: Mapping|
2449 #![auto]
2450 owner.view_mappings().contains(m) ==> {
2451 &&& vaddr_range_spec::<KernelPtConfig>()@.start <= m.va_range.start
2452 &&& m.va_range.end <= vaddr_range_spec::<KernelPtConfig>()@.end + 1
2453 },
2454{
2455 lemma_vaddr_range_spec_kernel();
2456 let start = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start as int;
2457 let end = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end as int;
2458 let lb = KernelPtConfig::LEADING_BITS_spec() as int;
2459 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2460 &&& vaddr_range_spec::<KernelPtConfig>()@.start <= m.va_range.start
2461 &&& m.va_range.end <= vaddr_range_spec::<KernelPtConfig>()@.end + 1
2462 } by {
2463 let i = choose|i: int|
2464 owner.level - 1 <= i < NR_LEVELS && (
2465 #[trigger] owner.continuations[i]).view_mappings().contains(m);
2466 let cont = owner.continuations[i];
2467 cont.lemma_view_mappings_contains();
2468 let j = choose|j: int|
2469 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
2470 cont.children[j].unwrap(),
2471 ).view_rec(cont.path().push_tail(j)).contains(m);
2472 let child = PageTableOwner(cont.children[j].unwrap());
2473 let p = cont.path().push_tail(j);
2474 child.view_rec_top_index_va_bound(p, m, end);
2475 }
2477}
2478
2479impl<'rcu, C: PageTableConfig> InvView for CursorOwner<'rcu, C> {
2480 proof fn view_preserves_inv(self) {
2481 self.view_non_overlapping();
2483 self.view_mapping_inv();
2486 lemma_view_in_vaddr_range::<C>(&self);
2489 }
2490}
2491
2492impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
2493 pub proof fn view_non_overlapping(self)
2499 requires
2500 self.inv(),
2501 ensures
2502 self@.non_overlapping(),
2503 {
2504 self.as_page_table_owner_view_non_overlapping();
2505 }
2506}
2507
2508impl<'rcu, C: PageTableConfig, A: InAtomicMode> Inv for Cursor<'rcu, C, A> {
2509 open spec fn inv(self) -> bool {
2510 &&& 1 <= self.level <= NR_LEVELS
2518 + 1
2519 &&& self.level <= self.guard_level + 1
2527 &&& self.guard_level
2528 <= NR_LEVELS
2529 &&& self.va >= self.barrier_va.start
2531 &&& self.va % PAGE_SIZE == 0
2532 }
2533}
2534
2535impl<'rcu, C: PageTableConfig, A: InAtomicMode> OwnerOf for Cursor<'rcu, C, A> {
2536 type Owner = CursorOwner<'rcu, C>;
2537
2538 open spec fn wf(self, owner: Self::Owner) -> bool {
2539 &&& owner.va.reflect(self.va)
2540 &&& self.level == owner.level
2541 &&& owner.guard_level
2542 == self.guard_level
2543 &&& self.level <= 4 ==> {
2552 &&& 4 <= self.guard_level ==> {
2553 &&& self.path[3] is Some
2554 &&& owner.continuations.contains_key(3)
2555 &&& owner.continuations[3].guard == self.path[3]->0
2556 }
2557 &&& 4 > self.guard_level ==> self.path[3] is None
2558 }
2559 &&& self.level <= 3 ==> {
2560 &&& 3 <= self.guard_level ==> {
2561 &&& self.path[2] is Some
2562 &&& owner.continuations.contains_key(2)
2563 &&& owner.continuations[2].guard == self.path[2]->0
2564 }
2565 &&& 3 > self.guard_level ==> self.path[2] is None
2566 }
2567 &&& self.level <= 2 ==> {
2568 &&& 2 <= self.guard_level ==> {
2569 &&& self.path[1] is Some
2570 &&& owner.continuations.contains_key(1)
2571 &&& owner.continuations[1].guard == self.path[1]->0
2572 }
2573 &&& 2 > self.guard_level ==> self.path[1] is None
2574 }
2575 &&& self.level == 1 ==> {
2576 &&& 1 <= self.guard_level ==> {
2580 &&& self.path[0] is Some
2581 &&& owner.continuations.contains_key(0)
2582 &&& owner.continuations[0].guard == self.path[0]->0
2583 }
2584 &&& 1 > self.guard_level ==> self.path[0] is None
2585 }
2586 &&& self.barrier_va.start == owner.locked_range().start
2587 &&& self.barrier_va.end == owner.locked_range().end
2588 }
2589}
2590
2591}