1use vstd::arithmetic::power2::pow2;
2use vstd::prelude::*;
3use vstd::seq_lib::*;
4use vstd::set::{axiom_set_choose_len, axiom_set_contains_len, axiom_set_intersect_finite};
5
6use vstd_extra::arithmetic::{
7 lemma_nat_align_down_monotone, lemma_nat_align_down_sound, lemma_nat_align_down_within_block,
8 lemma_nat_align_up_sound,
9};
10use vstd_extra::drop_tracking::*;
11use vstd_extra::ghost_tree::*;
12use vstd_extra::ownership::*;
13use vstd_extra::panic::may_panic;
14use vstd_extra::seq_extra::{forall_seq, lemma_forall_seq_index};
15
16use core::marker::PhantomData;
17use core::ops::Range;
18
19use crate::mm::frame::meta::mapping::frame_to_index;
20use crate::mm::page_prop::PageProperty;
21use crate::mm::page_table::*;
22use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr, nr_subpage_per_huge};
23use crate::specs::arch::mm::{MAX_PADDR, MAX_USERSPACE_VADDR, NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
24use crate::specs::arch::paging_consts::PagingConsts;
25use crate::specs::mm::frame::meta_owners::{REF_COUNT_MAX, REF_COUNT_UNUSED};
26use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
27use crate::specs::mm::page_table::AbstractVaddr;
28use crate::specs::mm::page_table::Guards;
29use crate::specs::mm::page_table::Mapping;
30use crate::specs::mm::page_table::cursor::page_size_lemmas::{
31 lemma_page_size_divides, lemma_page_size_ge_page_size, lemma_page_size_spec_level1,
32};
33use crate::specs::mm::page_table::owners::*;
34use crate::specs::mm::page_table::view::PageTableView;
35use crate::specs::mm::page_table::{nat_align_down, nat_align_up};
36use crate::specs::task::InAtomicMode;
37
38verus! {
39
40pub tracked struct CursorContinuation<'rcu, C: PageTableConfig> {
41 pub entry_own: EntryOwner<C>,
42 pub idx: usize,
43 pub tree_level: nat,
44 pub children: Seq<Option<OwnerSubtree<C>>>,
45 pub path: TreePath<NR_ENTRIES>,
46 pub guard: PageTableGuard<'rcu, C>,
47}
48
49impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
50 pub open spec fn path(self) -> TreePath<NR_ENTRIES> {
51 self.entry_own.path
52 }
53
54 pub open spec fn child(self) -> OwnerSubtree<C> {
55 self.children[self.idx as int].unwrap()
56 }
57
58 pub open spec fn take_child(self) -> (OwnerSubtree<C>, Self) {
59 let child = self.children[self.idx as int].unwrap();
60 let cont = Self {
61 children: self.children.remove(self.idx as int).insert(self.idx as int, None),
62 ..self
63 };
64 (child, cont)
65 }
66
67 pub proof fn tracked_take_child(tracked &mut self) -> (tracked res: OwnerSubtree<C>)
68 requires
69 old(self).inv(),
70 old(self).idx < old(self).children.len(),
71 old(self).children[old(self).idx as int] is Some,
72 ensures
73 res == old(self).take_child().0,
74 *final(self) == old(self).take_child().1,
75 res.inv(),
76 {
77 self.inv_children_unroll(self.idx as int);
78 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
79 self.children.tracked_insert(old(self).idx as int, None);
80 child
81 }
82
83 pub open spec fn put_child(self, child: OwnerSubtree<C>) -> Self {
84 Self {
85 children: self.children.remove(self.idx as int).insert(self.idx as int, Some(child)),
86 ..self
87 }
88 }
89
90 pub proof fn tracked_put_child(tracked &mut self, tracked child: OwnerSubtree<C>)
91 requires
92 old(self).idx < old(self).children.len(),
93 old(self).children[old(self).idx as int] is None,
94 ensures
95 *final(self) == old(self).put_child(child),
96 {
97 let _ = self.children.tracked_remove(old(self).idx as int);
98 self.children.tracked_insert(old(self).idx as int, Some(child));
99 }
100
101 pub proof fn take_put_child(self)
102 requires
103 self.idx < self.children.len(),
104 self.children[self.idx as int] is Some,
105 ensures
106 self.take_child().1.put_child(self.take_child().0) == self,
107 {
108 let child = self.take_child().0;
109 let cont = self.take_child().1;
110 assert(cont.put_child(child).children == self.children);
111 }
112
113 pub open spec fn make_cont(self, idx: usize, guard: PageTableGuard<'rcu, C>) -> (Self, Self) {
114 let child = Self {
115 entry_own: self.children[self.idx as int].unwrap().value,
116 tree_level: (self.tree_level + 1) as nat,
117 idx: idx,
118 children: self.children[self.idx as int].unwrap().children,
119 path: self.path.push_tail(self.idx as usize),
120 guard: guard,
121 };
122 let cont = Self { children: self.children.update(self.idx as int, None), ..self };
123 (child, cont)
124 }
125
126 pub axiom fn tracked_make_cont(
127 tracked &mut self,
128 idx: usize,
129 guard: PageTableGuard<'rcu, C>,
130 ) -> (tracked res: Self)
131 requires
132 old(self).all_some(),
133 old(self).idx < NR_ENTRIES,
134 idx < NR_ENTRIES,
135 ensures
136 res == old(self).make_cont(idx, guard).0,
137 *final(self) == old(self).make_cont(idx, guard).1,
138 ;
139
140 pub open spec fn restore(self, child: Self) -> (Self, PageTableGuard<'rcu, C>) {
141 let child_node = OwnerSubtree {
142 value: child.entry_own,
143 level: child.tree_level,
144 children: child.children,
145 };
146 (
147 Self { children: self.children.update(self.idx as int, Some(child_node)), ..self },
148 child.guard,
149 )
150 }
151
152 pub axiom fn tracked_restore(tracked &mut self, tracked child: Self) -> (tracked guard:
153 PageTableGuard<'rcu, C>)
154 ensures
155 *final(self) == old(self).restore(child).0,
156 guard == old(self).restore(child).1,
157 ;
158
159 pub open spec fn new(
160 owner_subtree: OwnerSubtree<C>,
161 idx: usize,
162 guard: PageTableGuard<'rcu, C>,
163 ) -> Self {
164 Self {
165 entry_own: owner_subtree.value,
166 idx: idx,
167 tree_level: owner_subtree.level,
168 children: owner_subtree.children,
169 path: TreePath::new(Seq::empty()),
170 guard: guard,
171 }
172 }
173
174 pub axiom fn tracked_new(
175 tracked owner_subtree: OwnerSubtree<C>,
176 idx: usize,
177 guard: PageTableGuard<'rcu, C>,
178 ) -> (tracked res: Self)
179 ensures
180 res == Self::new(owner_subtree, idx, guard),
181 ;
182
183 pub open spec fn map_children(
184 self,
185 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
186 ) -> bool {
187 forall|i: int|
188 #![trigger(self.children[i])]
189 0 <= i < self.children.len() ==> self.children[i] is Some
190 ==> self.children[i].unwrap().tree_predicate_map(
191 self.path().push_tail(i as usize),
192 f,
193 )
194 }
195
196 pub open spec fn level(self) -> PagingLevel {
199 self.entry_own.node.unwrap().level
200 }
201
202 pub open spec fn inv_children(self) -> bool {
203 self.children.all(|child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv())
204 }
205
206 pub proof fn inv_children_unroll(self, i: int)
207 requires
208 self.inv_children(),
209 0 <= i < self.children.len(),
210 self.children[i] is Some,
211 ensures
212 self.children[i].unwrap().inv(),
213 {
214 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
215 assert(pred(self.children[i]));
216 }
217
218 pub proof fn inv_children_unroll_all(self)
219 requires
220 self.inv_children(),
221 ensures
222 forall|i: int|
223 #![auto]
224 0 <= i < self.children.len() ==> self.children[i] is Some
225 ==> self.children[i].unwrap().inv(),
226 {
227 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
228 assert forall|i: int|
229 0 <= i < self.children.len()
230 && #[trigger] self.children[i] is Some implies self.children[i].unwrap().inv() by {
231 self.inv_children_unroll(i)
232 }
233 }
234
235 pub open spec fn inv_children_rel_pred(self) -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
236 |i: int, child: Option<OwnerSubtree<C>>|
237 {
238 child is Some ==> {
239 &&& child.unwrap().value.parent_level == self.level()
240 &&& child.unwrap().level == self.tree_level + 1
241 &&& !child.unwrap().value.in_scope
242 &&& child.unwrap().value.path.len() == self.entry_own.node.unwrap().tree_level
243 + 1
244 &&& child.unwrap().value.match_pte(
245 self.entry_own.node.unwrap().children_perm.value()[i],
246 self.entry_own.node.unwrap().level,
247 )
248 &&& child.unwrap().value.path == self.path().push_tail(i as usize)
249 }
250 }
251 }
252
253 pub open spec fn inv_children_rel(self) -> bool {
254 forall_seq(self.children, self.inv_children_rel_pred())
255 }
256
257 pub open spec fn pt_inv_children_pred() -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
258 |i: int, child: Option<OwnerSubtree<C>>|
259 child is Some ==> PageTableOwner(child.unwrap()).pt_inv()
260 }
261
262 pub open spec fn pt_inv_children(self) -> bool {
263 forall_seq(self.children, Self::pt_inv_children_pred())
264 }
265
266 pub proof fn pt_inv_children_unroll(self, i: int)
267 requires
268 self.pt_inv_children(),
269 0 <= i < self.children.len(),
270 self.children[i] is Some,
271 ensures
272 PageTableOwner(self.children[i].unwrap()).pt_inv(),
273 {
274 lemma_forall_seq_index(self.children, Self::pt_inv_children_pred(), i);
275 }
276
277 pub proof fn inv_children_rel_unroll(self, i: int)
278 requires
279 self.inv_children_rel(),
280 0 <= i < self.children.len(),
281 self.children[i] is Some,
282 ensures
283 self.children[i].unwrap().value.parent_level == self.level(),
284 self.children[i].unwrap().level == self.tree_level + 1,
285 !self.children[i].unwrap().value.in_scope,
286 self.children[i].unwrap().value.path.len() == self.entry_own.node.unwrap().tree_level
287 + 1,
288 self.children[i].unwrap().value.match_pte(
289 self.entry_own.node.unwrap().children_perm.value()[i],
290 self.entry_own.node.unwrap().level,
291 ),
292 self.children[i].unwrap().value.path == self.path().push_tail(i as usize),
293 {
294 lemma_forall_seq_index(self.children, self.inv_children_rel_pred(), i);
295 }
296
297 pub open spec fn inv(self) -> bool {
298 &&& self.children.len() == NR_ENTRIES
299 &&& 0 <= self.idx < NR_ENTRIES
300 &&& self.inv_children()
301 &&& self.inv_children_rel()
302 &&& self.pt_inv_children()
303 &&& self.entry_own.is_node()
304 &&& self.entry_own.inv()
305 &&& !self.entry_own.in_scope
306 &&& self.entry_own.node.unwrap().relate_guard(self.guard)
307 &&& self.tree_level == INC_LEVELS - self.level() - 1
308 &&& self.tree_level < INC_LEVELS - 1
309 &&& self.path().len() == self.tree_level
310 }
311
312 pub open spec fn all_some(self) -> bool {
313 forall|i: int| 0 <= i < NR_ENTRIES ==> self.children[i] is Some
314 }
315
316 pub open spec fn all_but_index_some(self) -> bool {
317 &&& forall|i: int| 0 <= i < self.idx ==> self.children[i] is Some
318 &&& forall|i: int| self.idx < i < NR_ENTRIES ==> self.children[i] is Some
319 &&& self.children[self.idx as int] is None
320 }
321
322 pub open spec fn inc_index(self) -> Self {
323 Self { idx: (self.idx + 1) as usize, ..self }
324 }
325
326 pub proof fn do_inc_index(tracked &mut self)
327 requires
328 old(self).idx + 1 < NR_ENTRIES,
329 ensures
330 *final(self) == old(self).inc_index(),
331 {
332 self.idx = (self.idx + 1) as usize;
333 }
334
335 pub open spec fn node_locked(self, guards: Guards<'rcu>) -> bool {
336 guards.lock_held(self.guard.inner.inner@.ptr.addr())
337 }
338
339 pub open spec fn view_mappings(self) -> Set<Mapping> {
340 Set::new(
341 |m: Mapping|
342 exists|i: int|
343 #![auto]
344 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
345 self.children[i].unwrap(),
346 ).view_rec(self.path().push_tail(i as usize)).contains(m),
347 )
348 }
349
350 pub open spec fn as_subtree(self) -> OwnerSubtree<C> {
351 OwnerSubtree { value: self.entry_own, level: self.tree_level, children: self.children }
352 }
353
354 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
355 PageTableOwner(self.as_subtree())
356 }
357
358 pub open spec fn view_mappings_take_child_spec(self) -> Set<Mapping> {
359 PageTableOwner(self.children[self.idx as int].unwrap()).view_rec(
360 self.path().push_tail(self.idx as usize),
361 )
362 }
363
364 pub proof fn rel_children_from_node_matching(
376 entry: &Entry<'_, 'rcu, C>,
377 child_value: EntryOwner<C>,
378 parent_owner: NodeOwner<C>,
379 guard: PageTableGuard<'rcu, C>,
380 entry_own: EntryOwner<C>,
381 idx: usize,
382 )
383 requires
384 entry.node_matching(child_value, parent_owner, guard),
385 entry.idx == idx,
386 entry_own.node == Some(parent_owner),
387 child_value.path == entry_own.path.push_tail(idx),
388 child_value.path.len() == parent_owner.tree_level + 1,
389 ensures
390 child_value.path.len() == parent_owner.tree_level + 1,
391 child_value.match_pte(
392 parent_owner.children_perm.value()[idx as int],
393 parent_owner.level,
394 ),
395 child_value.path == entry_own.path.push_tail(idx),
396 child_value.parent_level == parent_owner.level,
397 {
398 }
399
400 pub proof fn continuation_inv_holds_after_child_restore(
410 self,
411 cont_old: Self,
412 parent_old: NodeOwner<C>,
413 )
414 requires
415 cont_old.inv(),
418 cont_old.entry_own.node == Some(parent_old),
419 self.children.len() == cont_old.children.len(),
421 self.idx == cont_old.idx,
422 self.tree_level == cont_old.tree_level,
423 self.guard == cont_old.guard,
424 self.path == cont_old.path,
425 self.entry_own.frame == cont_old.entry_own.frame,
427 self.entry_own.locked == cont_old.entry_own.locked,
428 self.entry_own.absent == cont_old.entry_own.absent,
429 self.entry_own.in_scope == cont_old.entry_own.in_scope,
430 self.entry_own.path == cont_old.entry_own.path,
431 self.entry_own.parent_level == cont_old.entry_own.parent_level,
432 self.entry_own.is_node(),
434 self.entry_own.inv(),
435 self.entry_own.node.unwrap().relate_guard(self.guard),
436 self.entry_own.node.unwrap().level == parent_old.level,
437 self.entry_own.node.unwrap().tree_level == parent_old.tree_level,
438 forall|j: int|
440 0 <= j < NR_ENTRIES && j != self.idx as int
441 ==> #[trigger] self.entry_own.node.unwrap().children_perm.value()[j]
442 == parent_old.children_perm.value()[j],
443 forall|j: int|
445 0 <= j < NR_ENTRIES && j != self.idx as int ==> #[trigger] self.children[j]
446 == cont_old.children[j],
447 self.children.len() == NR_ENTRIES,
450 0 <= self.idx < NR_ENTRIES,
451 self.tree_level == INC_LEVELS - self.level() - 1,
452 self.tree_level < INC_LEVELS - 1,
453 self.path().len() == self.tree_level,
454 self.children[self.idx as int] is Some,
456 self.children[self.idx as int].unwrap().inv(),
457 self.children[self.idx as int].unwrap().value.parent_level == self.level(),
458 self.children[self.idx as int].unwrap().value.path == self.path().push_tail(
459 self.idx as usize,
460 ),
461 self.children[self.idx as int].unwrap().level == self.tree_level + 1,
462 self.children[self.idx as int].unwrap().value.path.len()
463 == self.entry_own.node.unwrap().tree_level + 1,
464 self.children[self.idx as int].unwrap().value.match_pte(
465 self.entry_own.node.unwrap().children_perm.value()[self.idx as int],
466 self.entry_own.node.unwrap().level,
467 ),
468 !self.children[self.idx as int].unwrap().value.in_scope,
469 PageTableOwner(self.children[self.idx as int].unwrap()).pt_inv(),
474 ensures
475 self.inv(),
476 {
477 let cont_idx = self.idx as int;
478 let new_parent = self.entry_own.node.unwrap();
479 let new_child = self.children[cont_idx].unwrap();
480
481 assert(self.inv_children()) by {
483 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
484 assert forall|i: int| 0 <= i < self.children.len() implies #[trigger] pred(
485 self.children[i],
486 ) by {
487 if i != cont_idx {
488 if self.children[i] is Some {
489 assert(self.children[i] == cont_old.children[i]);
490 cont_old.inv_children_unroll(i);
491 }
492 }
493 };
494 assert(self.children.all(pred));
495 };
496
497 assert(self.inv_children_rel()) by {
500 let pred = self.inv_children_rel_pred();
501 assert forall|i: int| 0 <= i < self.children.len() implies #[trigger] pred(
502 i,
503 self.children[i],
504 ) by {
505 if i != cont_idx {
506 if self.children[i] is Some {
507 cont_old.inv_children_rel_unroll(i);
508 assert(self.children[i] == cont_old.children[i]);
509 }
510 }
511 };
512 };
513
514 assert(self.pt_inv_children()) by {
519 let pred = Self::pt_inv_children_pred();
520 assert forall|i: int| 0 <= i < self.children.len() implies #[trigger] pred(
521 i,
522 self.children[i],
523 ) by {
524 if i == cont_idx {
525 assert(PageTableOwner(self.children[cont_idx].unwrap()).pt_inv());
526 } else {
527 if self.children[i] is Some {
528 cont_old.pt_inv_children_unroll(i);
529 assert(self.children[i] == cont_old.children[i]);
530 }
531 }
532 };
533 };
534
535 assert(!self.entry_own.in_scope);
536 }
537
538 pub proof fn new_child(
539 tracked &self,
540 paddr: Paddr,
541 prop: PageProperty,
542 is_tracked: bool,
543 tracked regions: &mut MetaRegionOwners,
544 ) -> (tracked res: OwnerSubtree<C>)
545 requires
546 self.inv(),
547 self.level() < NR_LEVELS,
548 old(regions).slots.contains_key(frame_to_index(paddr)),
549 paddr % PAGE_SIZE == 0,
550 paddr < MAX_PADDR,
551 paddr % page_size(self.level()) == 0,
552 paddr + page_size(self.level()) <= MAX_PADDR,
553 self.path().push_tail(self.idx as usize).inv(),
554 ensures
555 final(regions).slot_owners == old(regions).slot_owners,
556 final(regions).slots == old(regions).slots,
557 res.value == EntryOwner::<C>::new_frame(
559 paddr,
560 self.path().push_tail(self.idx as usize),
561 self.level(),
562 prop,
563 is_tracked,
564 ).set_in_scope(false),
565 res.inv(),
566 res.level == self.tree_level + 1,
567 res == OwnerSubtree::new_val(res.value, res.level as nat),
568 {
569 let tracked mut owner = EntryOwner::<C>::tracked_new_frame(
570 paddr,
571 self.path().push_tail(self.idx as usize),
572 self.level(),
573 prop,
574 is_tracked,
575 );
576 owner.in_scope = false;
577 OwnerSubtree::new_val_tracked(owner, self.tree_level + 1)
578 }
579}
580
581pub tracked struct CursorOwner<'rcu, C: PageTableConfig> {
582 pub level: PagingLevel,
583 pub continuations: Map<int, CursorContinuation<'rcu, C>>,
584 pub va: AbstractVaddr,
585 pub guard_level: PagingLevel,
586 pub prefix: AbstractVaddr,
587 pub popped_too_high: bool,
588}
589
590impl<'rcu, C: PageTableConfig> Inv for CursorOwner<'rcu, C> {
591 open spec fn inv(self) -> bool {
592 &&& self.va.inv()
593 &&& self.va.offset == 0
594 &&& 1 <= self.level <= NR_LEVELS
595 &&& 1 <= self.guard_level
596 <= NR_LEVELS
597 &&& C::TOP_LEVEL_INDEX_RANGE_spec().start <= self.va.index[NR_LEVELS
601 - 1]
602 &&& self.va.index[NR_LEVELS - 1]
606 <= C::TOP_LEVEL_INDEX_RANGE_spec().end
607 &&& self.in_locked_range()
609 || self.above_locked_range()
610 &&& self.popped_too_high ==> self.level >= self.guard_level
613 &&& !self.popped_too_high ==> self.level <= self.guard_level || self.above_locked_range()
614 &&& self.continuations[self.level - 1].all_some()
615 &&& forall|i: int|
616 self.level <= i < NR_LEVELS ==> {
617 (#[trigger] self.continuations[i]).all_but_index_some()
618 }
619 &&& self.prefix.inv()
620 &&& self.prefix.offset == 0
621 &&& forall|i: int|
622 i < self.guard_level ==> self.prefix.index[i]
623 == 0
624 &&& self.prefix.index[NR_LEVELS - 1]
628 < C::TOP_LEVEL_INDEX_RANGE_spec().end
629 &&& self.prefix.index[NR_LEVELS - 1] + 1
632 < NR_ENTRIES
633 &&& self.locked_range().end as int <= crate::mm::page_table::vaddr_range_bounds_spec::<
637 C,
638 >().1 as int
639 + 1
640 &&& self.locked_range().end as int
645 <= C::LOCKED_END_BOUND_spec()
646 &&& self.va.leading_bits
649 == self.prefix.leading_bits
650 &&& self.prefix.leading_bits
653 == C::LEADING_BITS_spec() as int
654 &&& !self.popped_too_high && (self.in_locked_range() || self.level < self.guard_level)
662 ==> forall|i: int|
663 self.guard_level <= i < NR_LEVELS ==> self.va.index[i] == self.prefix.index[i]
664 &&& !self.popped_too_high && self.guard_level >= 1 && self.level < self.guard_level
665 ==> self.va.index[self.guard_level - 1] == self.prefix.index[self.guard_level - 1]
666 &&& self.level <= 4 ==> {
667 &&& self.continuations.contains_key(3)
668 &&& self.continuations[3].inv()
669 &&& self.continuations[3].level()
670 == 4
671 &&& self.continuations[3].entry_own.parent_level
673 == 5
674 &&& self.in_locked_range() ==> self.va.index[3] == self.continuations[3].idx
679 }
680 &&& self.level <= 3 ==> {
681 &&& self.continuations.contains_key(2)
682 &&& self.continuations[2].inv()
683 &&& self.continuations[2].level() == 3
684 &&& self.continuations[2].entry_own.parent_level == 4
685 &&& self.in_locked_range() ==> self.va.index[2] == self.continuations[2].idx
686 &&& self.continuations[2].guard.inner.inner@.ptr.addr()
687 != self.continuations[3].guard.inner.inner@.ptr.addr()
688 &&& self.continuations[2].path() == self.continuations[3].path().push_tail(
690 self.continuations[3].idx as usize,
691 )
692 &&& self.continuations[2].entry_own.path.len()
694 == self.continuations[3].entry_own.node.unwrap().tree_level + 1
695 &&& self.continuations[2].entry_own.match_pte(
696 self.continuations[3].entry_own.node.unwrap().children_perm.value()[self.continuations[3].idx as int],
697 self.continuations[3].entry_own.node.unwrap().level,
698 )
699 &&& self.continuations[2].entry_own.parent_level
700 == self.continuations[3].entry_own.node.unwrap().level
701 }
702 &&& self.level <= 2 ==> {
703 &&& self.continuations.contains_key(1)
704 &&& self.continuations[1].inv()
705 &&& self.continuations[1].level() == 2
706 &&& self.continuations[1].entry_own.parent_level == 3
707 &&& self.in_locked_range() ==> self.va.index[1] == self.continuations[1].idx
708 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
709 != self.continuations[2].guard.inner.inner@.ptr.addr()
710 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
711 != self.continuations[3].guard.inner.inner@.ptr.addr()
712 &&& self.continuations[1].path() == self.continuations[2].path().push_tail(
714 self.continuations[2].idx as usize,
715 )
716 &&& self.continuations[1].entry_own.path.len()
718 == self.continuations[2].entry_own.node.unwrap().tree_level + 1
719 &&& self.continuations[1].entry_own.match_pte(
720 self.continuations[2].entry_own.node.unwrap().children_perm.value()[self.continuations[2].idx as int],
721 self.continuations[2].entry_own.node.unwrap().level,
722 )
723 &&& self.continuations[1].entry_own.parent_level
724 == self.continuations[2].entry_own.node.unwrap().level
725 }
726 &&& self.level == 1 ==> {
727 &&& self.continuations.contains_key(0)
728 &&& self.continuations[0].inv()
729 &&& self.continuations[0].level() == 1
730 &&& self.continuations[0].entry_own.parent_level == 2
731 &&& self.in_locked_range() ==> self.va.index[0] == self.continuations[0].idx
732 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
733 != self.continuations[1].guard.inner.inner@.ptr.addr()
734 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
735 != self.continuations[2].guard.inner.inner@.ptr.addr()
736 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
737 != self.continuations[3].guard.inner.inner@.ptr.addr()
738 &&& self.continuations[0].path() == self.continuations[1].path().push_tail(
740 self.continuations[1].idx as usize,
741 )
742 &&& self.continuations[0].entry_own.path.len()
744 == self.continuations[1].entry_own.node.unwrap().tree_level + 1
745 &&& self.continuations[0].entry_own.match_pte(
746 self.continuations[1].entry_own.node.unwrap().children_perm.value()[self.continuations[1].idx as int],
747 self.continuations[1].entry_own.node.unwrap().level,
748 )
749 &&& self.continuations[0].entry_own.parent_level
750 == self.continuations[1].entry_own.node.unwrap().level
751 }
752 }
753}
754
755impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
756 pub open spec fn node_unlocked(guards: Guards<'rcu>) -> (spec_fn(
757 EntryOwner<C>,
758 TreePath<NR_ENTRIES>,
759 ) -> bool) {
760 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
761 owner.is_node() ==> guards.unlocked(owner.node.unwrap().meta_addr_self())
762 }
763
764 pub open spec fn node_unlocked_except(guards: Guards<'rcu>, addr: usize) -> (spec_fn(
765 EntryOwner<C>,
766 TreePath<NR_ENTRIES>,
767 ) -> bool) {
768 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
769 owner.is_node() ==> owner.node.unwrap().meta_addr_self() != addr ==> guards.unlocked(
770 owner.node.unwrap().meta_addr_self(),
771 )
772 }
773
774 pub open spec fn map_full_tree(
775 self,
776 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
777 ) -> bool {
778 forall|i: int|
779 #![trigger self.continuations[i]]
780 self.level - 1 <= i < NR_LEVELS ==> { self.continuations[i].map_children(f) }
781 }
782
783 pub open spec fn map_only_children(
784 self,
785 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
786 ) -> bool {
787 forall|i: int|
788 #![trigger self.continuations[i]]
789 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(f)
790 }
791
792 pub open spec fn children_not_locked(self, guards: Guards<'rcu>) -> bool {
793 self.map_only_children(Self::node_unlocked(guards))
794 }
795
796 pub open spec fn only_current_locked(self, guards: Guards<'rcu>) -> bool {
797 self.map_only_children(
798 Self::node_unlocked_except(
799 guards,
800 self.cur_entry_owner().node.unwrap().meta_addr_self(),
801 ),
802 )
803 }
804
805 pub proof fn never_drop_restores_children_not_locked(
806 self,
807 guard: PageTableGuard<'rcu, C>,
808 guards0: Guards<'rcu>,
809 guards1: Guards<'rcu>,
810 obl_key: usize,
811 )
812 requires
813 self.inv(),
814 self.only_current_locked(guards0),
815 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_requires(guard, guards0),
816 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_ensures(
817 guard,
818 guards0,
819 guards1,
820 obl_key,
821 ),
822 self.cur_entry_owner().is_node(),
824 guard.inner.inner@.ptr.addr() == self.cur_entry_owner().node.unwrap().meta_addr_self(),
825 ensures
826 self.children_not_locked(guards1),
827 {
828 let current_addr = self.cur_entry_owner().node.unwrap().meta_addr_self();
829 let f = Self::node_unlocked_except(guards0, current_addr);
830 let g = Self::node_unlocked(guards1);
831 assert(OwnerSubtree::implies(f, g));
832 self.map_children_implies(f, g);
833 }
834
835 pub axiom fn never_drop_restores_nodes_locked(
839 self,
840 guard: PageTableGuard<'rcu, C>,
841 guards0: Guards<'rcu>,
842 guards1: Guards<'rcu>,
843 obl_key: usize,
844 )
845 requires
846 self.inv(),
847 self.nodes_locked(guards0),
848 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_requires(guard, guards0),
849 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_ensures(
850 guard,
851 guards0,
852 guards1,
853 obl_key,
854 ),
855 forall|i: int|
856 #![trigger self.continuations[i]]
857 self.level - 1 <= i < NR_LEVELS
858 ==> self.continuations[i].guard.inner.inner@.ptr.addr()
859 != guard.inner.inner@.ptr.addr(),
860 ensures
861 self.nodes_locked(guards1),
862 ;
863
864 pub open spec fn nodes_locked(self, guards: Guards<'rcu>) -> bool {
878 forall|i: int|
884 #![trigger self.continuations[i]]
885 self.level - 1 <= i < self.guard_level ==> { self.continuations[i].node_locked(guards) }
886 }
887
888 pub open spec fn index(self) -> usize {
889 self.continuations[self.level - 1].idx
890 }
891
892 pub open spec fn inc_index(self) -> Self {
893 Self {
894 continuations: self.continuations.insert(
895 self.level - 1,
896 self.continuations[self.level - 1].inc_index(),
897 ),
898 va: AbstractVaddr {
899 index: self.va.index.insert(
900 self.level - 1,
901 self.continuations[self.level - 1].inc_index().idx as int,
902 ),
903 ..self.va
904 },
905 popped_too_high: false,
906 ..self
907 }
908 }
909
910 #[verifier::spinoff_prover]
911 pub proof fn do_inc_index(tracked &mut self)
912 requires
913 old(self).inv(),
914 old(self).level <= old(self).guard_level,
915 old(self).in_locked_range(),
916 old(self).continuations[old(self).level - 1].idx + 1 < NR_ENTRIES,
917 old(self).level == NR_LEVELS ==> (old(self).continuations[old(self).level - 1].idx + 1)
918 <= C::TOP_LEVEL_INDEX_RANGE_spec().end,
919 ensures
920 final(self).inv(),
921 *final(self) == old(self).inc_index(),
922 {
923 reveal(CursorContinuation::inv_children);
924 self.popped_too_high = false;
925 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
926 cont.do_inc_index();
927 self.va.index.tracked_insert(self.level - 1, cont.idx as int);
928 self.continuations.tracked_insert(self.level - 1, cont);
929 assert(self.continuations == old(self).continuations.insert(self.level - 1, cont));
930 assert(self.va.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
931
932 old(self).va.index_increment_adds_page_size(old(self).level as int);
933 lemma_page_size_ge_page_size(old(self).level as PagingLevel);
934
935 if self.level >= self.guard_level {
936 if !old(self).above_locked_range() {
937 Self::inc_at_guard_level_above_locked_range(
938 old(self).va,
939 old(self).prefix,
940 old(self).guard_level,
941 old(self).level,
942 self.va.to_vaddr(),
943 );
944 }
945 }
946 if old(self).popped_too_high {
947 old(self).in_locked_range_prefix_match();
948 }
949 assert(self.va.index[self.level as int - 1] == self.continuations[self.level as int
950 - 1].idx);
951 assert(self.prefix == old(self).prefix);
952 assert(self.prefix.index[NR_LEVELS - 1] < C::TOP_LEVEL_INDEX_RANGE_spec().end);
953 assert(cont.children == old(self).continuations[self.level - 1].children);
955 assert(cont.pt_inv_children());
956 assert(self.va.inv()) by {
957 assert(0 <= self.va.offset < PAGE_SIZE);
958 assert(self.va.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
959 assert forall|i: int| 0 <= i < NR_LEVELS implies self.va.index.contains_key(i) && 0
960 <= self.va.index[i] < NR_ENTRIES by {
961 assert(self.va.index.contains_key(i));
962 };
963 assert(0 <= self.va.leading_bits < 0x1_0000int);
964 };
965 assert(self.inv());
966 }
967
968 pub proof fn inv_continuation(self, i: int)
969 requires
970 self.inv(),
971 self.level - 1 <= i <= NR_LEVELS - 1,
972 ensures
973 self.continuations.contains_key(i),
974 self.continuations[i].inv(),
975 self.continuations[i].children.len() == NR_ENTRIES,
976 {
977 assert(self.continuations.contains_key(i));
978 }
979
980 pub open spec fn view_mappings(self) -> Set<Mapping> {
981 Set::new(
982 |m: Mapping|
983 exists|i: int|
984 #![trigger self.continuations[i]]
985 self.level - 1 <= i < NR_LEVELS
986 && self.continuations[i].view_mappings().contains(m),
987 )
988 }
989
990 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
991 if self.level == 1 {
992 let l1 = self.continuations[0];
993 let l2 = self.continuations[1].restore(l1).0;
994 let l3 = self.continuations[2].restore(l2).0;
995 let l4 = self.continuations[3].restore(l3).0;
996 l4.as_page_table_owner()
997 } else if self.level == 2 {
998 let l2 = self.continuations[1];
999 let l3 = self.continuations[2].restore(l2).0;
1000 let l4 = self.continuations[3].restore(l3).0;
1001 l4.as_page_table_owner()
1002 } else if self.level == 3 {
1003 let l3 = self.continuations[2];
1004 let l4 = self.continuations[3].restore(l3).0;
1005 l4.as_page_table_owner()
1006 } else {
1007 let l4 = self.continuations[3];
1008 l4.as_page_table_owner()
1009 }
1010 }
1011
1012 pub open spec fn cur_entry_owner(self) -> EntryOwner<C> {
1013 self.cur_subtree().value
1014 }
1015
1016 pub open spec fn cur_subtree(self) -> OwnerSubtree<C> {
1017 self.continuations[self.level - 1].children[self.index() as int].unwrap()
1018 }
1019
1020 pub proof fn cur_frame_clone_requires(
1035 self,
1036 item: C::Item,
1037 pa: Paddr,
1038 level: PagingLevel,
1039 prop: PageProperty,
1040 regions: MetaRegionOwners,
1041 )
1042 requires
1043 self.inv(),
1044 regions.inv(),
1045 self.metaregion_sound(regions),
1046 self.cur_entry_owner().is_frame(),
1047 pa == self.cur_entry_owner().frame.unwrap().mapped_pa,
1048 C::item_from_raw_spec(pa, level, prop) == item,
1049 crate::mm::frame::meta::has_safe_slot(pa),
1050 C::tracked(item) == self.cur_entry_owner().frame.unwrap().is_tracked,
1052 C::tracked(item) ==> (regions.slot_owners[frame_to_index(
1054 pa,
1055 )].inner_perms.ref_count.value() < REF_COUNT_MAX || may_panic()),
1056 ensures
1057 item.clone_requires(regions),
1058 {
1059 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1060 assert(self.path_metaregion_sound(regions));
1063 assert(self.cur_entry_owner().metaregion_sound(regions));
1064 let entry = self.cur_entry_owner();
1065 let idx = frame_to_index(pa);
1066 EntryOwner::<C>::axiom_frame_is_tracked_iff_not_mmio(entry);
1070 assert(regions.slot_owners[idx].self_addr == crate::mm::frame::meta::mapping::meta_addr(
1071 idx,
1072 ));
1073 if C::tracked(item) {
1074 assert(!crate::specs::mm::frame::meta_owners::is_mmio_paddr(pa));
1075 assert(regions.slot_owners[idx].usage
1076 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO);
1077 assert(regions.slot_owners[idx].inner_perms.ref_count.value() > 0);
1078 assert(regions.slot_owners[idx].inner_perms.ref_count.value()
1079 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED);
1080 }
1081 C::clone_requires_concrete(item, pa, level, prop, regions);
1084 }
1085
1086 pub proof fn clone_item_preserves_invariants(
1089 self,
1090 old_regions: MetaRegionOwners,
1091 new_regions: MetaRegionOwners,
1092 idx: usize,
1093 )
1094 requires
1095 self.inv(),
1096 self.metaregion_sound(old_regions),
1097 old_regions.inv(),
1098 self.cur_entry_owner().is_frame(),
1099 idx == frame_to_index(self.cur_entry_owner().frame.unwrap().mapped_pa),
1100 old_regions.slot_owners.contains_key(idx),
1101 new_regions.slot_owners.contains_key(idx),
1102 new_regions.slot_owners[idx].inner_perms.ref_count.value()
1104 == old_regions.slot_owners[idx].inner_perms.ref_count.value() + 1,
1105 new_regions.slot_owners[idx].inner_perms.ref_count.id()
1107 == old_regions.slot_owners[idx].inner_perms.ref_count.id(),
1108 new_regions.slot_owners[idx].inner_perms.storage
1109 == old_regions.slot_owners[idx].inner_perms.storage,
1110 new_regions.slot_owners[idx].inner_perms.vtable_ptr
1111 == old_regions.slot_owners[idx].inner_perms.vtable_ptr,
1112 new_regions.slot_owners[idx].inner_perms.in_list
1113 == old_regions.slot_owners[idx].inner_perms.in_list,
1114 new_regions.slot_owners[idx].paths_in_pt == old_regions.slot_owners[idx].paths_in_pt,
1116 new_regions.slot_owners[idx].self_addr == old_regions.slot_owners[idx].self_addr,
1117 new_regions.slot_owners[idx].usage == old_regions.slot_owners[idx].usage,
1118 new_regions.slot_owners.dom() == old_regions.slot_owners.dom(),
1120 forall|i: usize|
1121 #![trigger new_regions.slot_owners[i]]
1122 i != idx && old_regions.slot_owners.contains_key(i) ==> new_regions.slot_owners[i]
1123 == old_regions.slot_owners[i],
1124 new_regions.slots == old_regions.slots,
1126 0 < old_regions.slot_owners[idx].inner_perms.ref_count.value(),
1132 old_regions.slot_owners[idx].inner_perms.ref_count.value() + 1 <= REF_COUNT_MAX,
1133 ensures
1134 new_regions.inv(),
1135 self.metaregion_sound(new_regions),
1136 {
1137 self.cont_entries_metaregion(old_regions);
1138 assert(new_regions.slot_owners[idx].inv());
1139 assert(new_regions.inv()) by {
1140 assert forall|i: usize| #[trigger] new_regions.slots.contains_key(i) implies {
1141 &&& new_regions.slot_owners.contains_key(i)
1142 &&& new_regions.slot_owners[i].inv()
1143 &&& new_regions.slots[i].is_init()
1144 &&& new_regions.slots[i].value().wf(new_regions.slot_owners[i])
1145 &&& new_regions.slot_owners[i].self_addr == new_regions.slots[i].addr()
1146 } by {
1147 assert(old_regions.slots.contains_key(i));
1148 };
1149 assert forall|i: usize| #[trigger]
1150 new_regions.slot_owners.contains_key(
1151 i,
1152 ) implies new_regions.slot_owners[i].inv() by {};
1153 };
1154 self.metaregion_slot_owners_rc_increment(old_regions, new_regions, idx);
1155 }
1156
1157 pub proof fn new_child_mappings_eq_target(
1160 self,
1161 new_subtree: OwnerSubtree<C>,
1162 pa: Paddr,
1163 level: PagingLevel,
1164 prop: PageProperty,
1165 )
1166 requires
1167 self.inv(),
1168 self.in_locked_range(),
1169 level == self.level,
1170 new_subtree.inv(),
1171 new_subtree.value.is_frame(),
1172 new_subtree.value.path == self.continuations[self.level as int - 1].path().push_tail(
1173 self.continuations[self.level as int - 1].idx as usize,
1174 ),
1175 new_subtree.value.frame.unwrap().mapped_pa == pa,
1176 new_subtree.value.frame.unwrap().prop == prop,
1177 ensures
1178 PageTableOwner(new_subtree)@.mappings
1179 == set![Mapping {
1180 va_range: self@.cur_slot_range(page_size(level)),
1181 pa_range: pa..(pa + page_size(level)) as usize,
1182 page_size: page_size(level),
1183 property: prop,
1184 }],
1185 {
1186 let path = new_subtree.value.path;
1187 let ps = page_size(level);
1188 let pt_level = INC_LEVELS - path.len();
1189 let cont = self.continuations[self.level as int - 1];
1190
1191 cont.path().push_tail_property_len(cont.idx as usize);
1192 assert(cont.level() == self.level) by {
1193 if self.level == 1 {
1194 } else if self.level == 2 {
1195 } else if self.level == 3 {
1196 } else {
1197 }
1198 };
1199 assert(pt_level == self.level);
1200
1201 self.cur_va_in_subtree_range();
1206 assert(vaddr_of::<C>(path) == nat_align_down(self@.cur_va as nat, ps as nat) as Vaddr) by {
1207 self.va.to_path_vaddr_concrete(self.level as int - 1);
1208 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
1209 let va_path = self.va.to_path(self.level as int - 1);
1210 self.va.to_path_len(self.level as int - 1);
1211 self.va.to_path_inv(self.level as int - 1);
1212 self.cur_subtree_inv();
1213 assert forall|i: int| 0 <= i < path.len() implies path.index(i) == va_path.index(i) by {
1214 self.va.to_path_index(self.level as int - 1, i);
1215 if self.level == 4 {
1216 cont.path().push_tail_property_index(cont.idx as usize);
1217 } else if self.level == 3 {
1218 cont.path().push_tail_property_index(cont.idx as usize);
1219 self.continuations[3].path().push_tail_property_index(
1220 self.continuations[3].idx as usize,
1221 );
1222 } else if self.level == 2 {
1223 cont.path().push_tail_property_index(cont.idx as usize);
1224 self.continuations[2].path().push_tail_property_index(
1225 self.continuations[2].idx as usize,
1226 );
1227 self.continuations[3].path().push_tail_property_index(
1228 self.continuations[3].idx as usize,
1229 );
1230 } else {
1231 cont.path().push_tail_property_index(cont.idx as usize);
1232 self.continuations[1].path().push_tail_property_index(
1233 self.continuations[1].idx as usize,
1234 );
1235 self.continuations[2].path().push_tail_property_index(
1236 self.continuations[2].idx as usize,
1237 );
1238 self.continuations[3].path().push_tail_property_index(
1239 self.continuations[3].idx as usize,
1240 );
1241 }
1242 };
1243 AbstractVaddr::rec_vaddr_eq_if_indices_eq(path, va_path, 0);
1244 };
1245 let target = Mapping {
1250 va_range: self@.cur_slot_range(page_size(level)),
1251 pa_range: pa..(pa + page_size(level)) as usize,
1252 page_size: page_size(level),
1253 property: prop,
1254 };
1255 let from_view = Mapping {
1256 va_range: Range {
1257 start: vaddr_of::<C>(path) as int,
1258 end: vaddr_of::<C>(path) as int + ps as int,
1259 },
1260 pa_range: pa..(pa + ps) as usize,
1261 page_size: ps,
1262 property: prop,
1263 };
1264 let nad = nat_align_down(self@.cur_va as nat, ps as nat);
1267 assert(nad <= self@.cur_va as nat) by {
1268 vstd_extra::arithmetic::lemma_nat_align_down_sound(self@.cur_va as nat, ps as nat);
1269 };
1270 assert(nad <= usize::MAX);
1271 assert(nad as int == nad as usize as int);
1272 assert(vaddr_of::<C>(path) as int == nad as int);
1273 assert(target.va_range.start == nad as int);
1274 assert(from_view.va_range.start == vaddr_of::<C>(path) as int);
1275 assert(target.va_range.start == from_view.va_range.start);
1276 assert(target.va_range.end == from_view.va_range.end);
1277 assert(target.va_range =~= from_view.va_range);
1278 assert(target =~= from_view);
1279 assert(PageTableOwner(new_subtree).view_rec(path) == set![from_view]);
1280 assert(PageTableOwner(new_subtree)@.mappings == set![target]);
1281 }
1282
1283 pub open spec fn locked_range(self) -> Range<Vaddr> {
1284 let start = self.prefix.align_down(self.guard_level as int).to_vaddr();
1285 let end = self.prefix.align_up(self.guard_level as int).to_vaddr();
1286 Range { start, end }
1287 }
1288
1289 pub open spec fn in_locked_range(self) -> bool {
1290 self.locked_range().start <= self.va.to_vaddr() < self.locked_range().end
1291 }
1292
1293 pub open spec fn above_locked_range(self) -> bool {
1294 self.va.to_vaddr() >= self.locked_range().end
1295 }
1296
1297 pub proof fn inc_at_guard_level_above_locked_range(
1299 old_va: AbstractVaddr,
1300 prefix: AbstractVaddr,
1301 guard_level: u8,
1302 level: u8,
1303 new_va_val: Vaddr,
1304 )
1305 requires
1306 old_va.inv(),
1307 prefix.inv(),
1308 1 <= guard_level <= NR_LEVELS,
1309 level == guard_level,
1310 new_va_val == old_va.to_vaddr() + page_size(level as PagingLevel),
1311 prefix.align_down(guard_level as int).to_vaddr() <= old_va.to_vaddr(),
1312 old_va.to_vaddr() < prefix.align_up(guard_level as int).to_vaddr(),
1313 prefix.align_down(guard_level as int).to_vaddr() + page_size(guard_level as PagingLevel)
1315 <= usize::MAX,
1316 ensures
1317 new_va_val >= prefix.align_up(guard_level as int).to_vaddr(),
1318 {
1319 let ps_gl = page_size(guard_level as PagingLevel);
1320 lemma_page_size_ge_page_size(guard_level as PagingLevel);
1321 let aligned = prefix.align_down(guard_level as int);
1322 prefix.align_down_concrete(guard_level as int);
1323 prefix.align_down_shape(guard_level as int);
1324
1325 assert(aligned.to_vaddr() as nat % ps_gl as nat == 0) by {
1331 vstd_extra::arithmetic::lemma_nat_align_down_sound(
1332 prefix.to_vaddr() as nat,
1333 ps_gl as nat,
1334 );
1335 prefix.to_vaddr_bounded();
1336 aligned.to_vaddr_bounded();
1337 aligned.reflect_prop(nat_align_down(prefix.to_vaddr() as nat, ps_gl as nat) as Vaddr);
1338 };
1339 aligned.aligned_align_up_advances(guard_level as int);
1341 aligned.aligned_align_down_is_self(guard_level as int);
1346 }
1347
1348 pub proof fn prefix_in_locked_range(self)
1349 requires
1350 self.inv(),
1351 !self.popped_too_high,
1352 self.level < self.guard_level,
1353 ensures
1354 self.in_locked_range(),
1355 {
1356 let gl = self.guard_level;
1357 if gl >= 1 && gl <= NR_LEVELS {
1358 self.va.align_down_to_vaddr_eq_if_upper_indices_eq(self.prefix, gl as int);
1362 self.va.align_down_concrete(gl as int);
1363 self.prefix.align_down_concrete(gl as int);
1364 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1365 nat_align_down(
1366 self.va.to_vaddr() as nat,
1367 page_size(gl as PagingLevel) as nat,
1368 ) as Vaddr,
1369 );
1370 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1371 nat_align_down(
1372 self.prefix.to_vaddr() as nat,
1373 page_size(gl as PagingLevel) as nat,
1374 ) as Vaddr,
1375 );
1376 lemma_page_size_ge_page_size(gl as PagingLevel);
1377 lemma_nat_align_down_sound(
1378 self.va.to_vaddr() as nat,
1379 page_size(gl as PagingLevel) as nat,
1380 );
1381
1382 let ps = page_size(gl as PagingLevel) as nat;
1383 let prefix_val = self.prefix.to_vaddr() as nat;
1384
1385 self.prefix.align_down_shape(gl as int);
1386 self.prefix.align_down(gl as int).reflect_prop(nat_align_down(prefix_val, ps) as Vaddr);
1387 self.prefix_aligned_to_guard_level();
1389 self.prefix_plus_ps_no_overflow();
1390 self.prefix.aligned_align_up_advances(gl as int);
1391 }
1392 }
1393
1394 pub proof fn in_locked_range_prefix_match(self)
1397 requires
1398 self.inv(),
1399 self.prefix.inv(),
1400 1 <= self.guard_level <= NR_LEVELS,
1401 self.in_locked_range(),
1402 ensures
1403 forall|i: int|
1404 self.guard_level <= i < NR_LEVELS ==> self.va.index[i] == self.prefix.index[i],
1405 {
1406 let gl = self.guard_level;
1407 let start = self.prefix.align_down(gl as int).to_vaddr();
1408
1409 self.prefix.align_down_shape(gl as int);
1411 let prefix_ad = self.prefix.align_down(gl as int);
1412
1413 self.prefix.align_down_concrete(gl as int);
1415 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1416 nat_align_down(
1417 self.prefix.to_vaddr() as nat,
1418 page_size(gl as PagingLevel) as nat,
1419 ) as Vaddr,
1420 );
1421 lemma_page_size_ge_page_size(gl as PagingLevel);
1422 lemma_nat_align_down_sound(
1423 self.prefix.to_vaddr() as nat,
1424 page_size(gl as PagingLevel) as nat,
1425 );
1426
1427 self.prefix_aligned_to_guard_level();
1429 self.prefix_plus_ps_no_overflow();
1430 self.prefix.aligned_align_up_advances(gl as int);
1431
1432 if gl as int >= 2 && (gl as int) < NR_LEVELS as int {
1433 AbstractVaddr::same_node_indices_match(
1436 self.va.to_vaddr(),
1437 self.prefix.to_vaddr(),
1438 start,
1439 (gl - 1) as PagingLevel,
1440 );
1441 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1443 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1444 } else if gl as int == 1 {
1445 let ps1 = page_size(1 as PagingLevel) as nat;
1449 let ps2 = page_size(2 as PagingLevel) as nat;
1450 let pv = self.prefix.to_vaddr() as nat;
1451 let cv = self.va.to_vaddr() as nat;
1452 let node_start = nat_align_down(pv, ps2) as usize;
1453
1454 lemma_page_size_ge_page_size(1 as PagingLevel);
1455 lemma_page_size_ge_page_size(2 as PagingLevel);
1456 page_size_monotonic(1 as PagingLevel, 2 as PagingLevel);
1457 lemma_page_size_divides(1 as PagingLevel, 2 as PagingLevel);
1458 lemma_nat_align_down_sound(pv, ps2);
1459 lemma_nat_align_down_sound(pv, ps1);
1460
1461 lemma_nat_align_down_monotone(pv, ps1, ps2);
1462 lemma_nat_align_down_within_block(pv, ps1, ps2);
1463
1464 AbstractVaddr::same_node_indices_match(
1465 self.va.to_vaddr(),
1466 self.prefix.to_vaddr(),
1467 node_start,
1468 1 as PagingLevel,
1469 );
1470 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1471 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1472 }
1473 }
1474
1475 #[verifier::rlimit(2000)]
1479 pub proof fn in_locked_range_guard_index_eq_prefix(self)
1480 requires
1481 self.inv(),
1482 self.prefix.inv(),
1483 1 <= self.guard_level <= NR_LEVELS,
1484 self.in_locked_range(),
1485 ensures
1486 self.va.index[self.guard_level - 1] == self.prefix.index[self.guard_level - 1],
1487 {
1488 let gl = self.guard_level;
1489 let start = self.prefix.align_down(gl as int).to_vaddr();
1490
1491 self.prefix.align_down_shape(gl as int);
1492 self.prefix.align_down_concrete(gl as int);
1493 self.prefix_aligned_to_guard_level();
1496 self.prefix_plus_ps_no_overflow();
1497 self.prefix.aligned_align_up_advances(gl as int);
1498 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1499 nat_align_down(
1500 self.prefix.to_vaddr() as nat,
1501 page_size(gl as PagingLevel) as nat,
1502 ) as Vaddr,
1503 );
1504 lemma_page_size_ge_page_size(gl as PagingLevel);
1505 lemma_nat_align_down_sound(
1506 self.prefix.to_vaddr() as nat,
1507 page_size(gl as PagingLevel) as nat,
1508 );
1509
1510 self.prefix.align_down(gl as int).reflect_prop(
1511 nat_align_down(
1512 self.prefix.to_vaddr() as nat,
1513 page_size(gl as PagingLevel) as nat,
1514 ) as Vaddr,
1515 );
1516
1517 let ps = page_size(gl as PagingLevel);
1525 let va_val = self.va.to_vaddr();
1526 let pf_val = self.prefix.to_vaddr();
1527 let k = start as int / ps as int;
1530 assert(start as int == k * ps as int) by {
1531 lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps as nat);
1532 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps as int);
1533 };
1534 assert(va_val as int / ps as int == k) by {
1536 let r = va_val as int - start as int;
1537 assert(0 <= r);
1538 assert(r < ps as int);
1539 assert(va_val as int == k * ps as int + r) by (nonlinear_arith)
1540 requires
1541 va_val as int == start as int + r,
1542 start as int == k * ps as int,
1543 ;
1544 vstd::arithmetic::div_mod::lemma_fundamental_div_mod_converse(
1545 va_val as int,
1546 ps as int,
1547 k,
1548 r,
1549 );
1550 };
1551 assert(pf_val as int / ps as int == k) by {
1552 let r = pf_val as int - start as int;
1553 assert(0 <= r);
1554 assert(r < ps as int);
1555 assert(pf_val as int == k * ps as int + r) by (nonlinear_arith)
1556 requires
1557 pf_val as int == start as int + r,
1558 start as int == k * ps as int,
1559 ;
1560 vstd::arithmetic::div_mod::lemma_fundamental_div_mod_converse(
1561 pf_val as int,
1562 ps as int,
1563 k,
1564 r,
1565 );
1566 };
1567 use crate::specs::mm::page_table::cursor::page_size_lemmas::*;
1586 lemma_page_size_spec_values();
1587 vstd::arithmetic::power2::lemma2_to64();
1590 vstd::arithmetic::power2::lemma2_to64_rest();
1591 assert(ps as int == pow2((12 + 9 * (gl - 1)) as nat) as int);
1592 assert(AbstractVaddr::from_vaddr(va_val).index[gl - 1] == ((va_val as usize / ps)
1594 % NR_ENTRIES) as int);
1595 assert(AbstractVaddr::from_vaddr(pf_val).index[gl - 1] == ((pf_val as usize / ps)
1596 % NR_ENTRIES) as int);
1597 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1599 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1600 }
1601
1602 pub proof fn in_locked_range_level_le_nr_levels(self)
1603 requires
1604 self.inv(),
1605 self.in_locked_range(),
1606 !self.popped_too_high,
1607 ensures
1608 self.level <= NR_LEVELS,
1609 {
1610 self.in_locked_range_level_le_guard_level();
1611 }
1612
1613 pub proof fn in_locked_range_top_index_lt_top_end(self)
1617 requires
1618 self.inv(),
1619 self.in_locked_range(),
1620 !self.popped_too_high,
1621 ensures
1622 self.va.index[NR_LEVELS - 1] < C::TOP_LEVEL_INDEX_RANGE_spec().end,
1623 {
1624 self.in_locked_range_level_le_guard_level();
1625 if self.guard_level as int == NR_LEVELS as int {
1626 if self.level < self.guard_level {
1627 assert(self.va.index[NR_LEVELS - 1] == self.prefix.index[NR_LEVELS - 1]);
1629 } else {
1630 self.in_locked_range_guard_index_eq_prefix();
1641 assert(self.va.index[NR_LEVELS - 1] == self.prefix.index[NR_LEVELS - 1]);
1642 }
1643 } else {
1644 assert(self.va.index[NR_LEVELS - 1] == self.prefix.index[NR_LEVELS - 1]);
1645 }
1646 }
1647
1648 pub proof fn in_locked_range_level_le_guard_level(self)
1649 requires
1650 self.inv(),
1651 self.in_locked_range(),
1652 !self.popped_too_high,
1653 ensures
1654 self.level <= self.guard_level,
1655 {
1656 assert(self.in_locked_range() ==> !self.above_locked_range());
1657 }
1658
1659 pub proof fn cursor_top_idx_strict_lt_nr_entries(self)
1675 requires
1676 self.inv(),
1677 self.in_locked_range(),
1678 !self.popped_too_high,
1679 self.level == NR_LEVELS,
1680 self.guard_level == NR_LEVELS,
1681 ensures
1682 self.continuations[self.level - 1].idx + 1 < NR_ENTRIES,
1683 {
1684 self.in_locked_range_top_index_lt_top_end();
1685 self.in_locked_range_guard_index_eq_prefix();
1686 let top_end = C::TOP_LEVEL_INDEX_RANGE_spec().end as int;
1687 if top_end >= NR_ENTRIES as int {
1688 assert(self.continuations[self.level - 1].idx + 1 < NR_ENTRIES);
1689 }
1690 }
1691
1692 pub proof fn locked_range_span(self)
1700 requires
1701 self.inv(),
1702 ensures
1703 self.locked_range().start as nat == nat_align_down(
1704 self.prefix.to_vaddr() as nat,
1705 page_size(self.guard_level as PagingLevel) as nat,
1706 ),
1707 self.locked_range().start as nat % page_size(self.guard_level as PagingLevel) as nat
1708 == 0,
1709 self.locked_range().end - self.locked_range().start == page_size(
1710 self.guard_level as PagingLevel,
1711 ),
1712 {
1713 let gl = self.guard_level;
1714 let ps_gl = page_size(gl as PagingLevel) as nat;
1715 let pv = self.prefix.to_vaddr() as nat;
1716
1717 lemma_page_size_ge_page_size(gl as PagingLevel);
1718 self.prefix.align_down_concrete(gl as int);
1719 self.prefix_aligned_to_guard_level();
1720 self.prefix_plus_ps_no_overflow();
1721 self.prefix.aligned_align_up_advances(gl as int);
1722 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(pv, ps_gl) as Vaddr);
1723 vstd_extra::arithmetic::lemma_nat_align_down_sound(pv, ps_gl);
1724 }
1725
1726 pub proof fn in_node_holds_at_guard(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1734 requires
1735 self.inv(),
1736 self.in_locked_range(),
1737 self.va.reflect(self_va),
1738 node_size == page_size_spec((self.guard_level + 1) as PagingLevel),
1739 self.locked_range().start <= va < self.locked_range().end,
1740 ensures
1741 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1742 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1743 {
1744 let gl = self.guard_level;
1745 let pg = page_size(gl as PagingLevel) as nat;
1746 let pg1 = node_size as nat;
1747 let ls = self.locked_range().start as nat;
1748
1749 lemma_page_size_ge_page_size(gl as PagingLevel);
1751 lemma_page_size_ge_page_size((gl + 1) as PagingLevel);
1752 assert(pg > 0 && pg1 > 0);
1753
1754 self.locked_range_span();
1755 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(
1756 gl as PagingLevel,
1757 (gl + 1) as PagingLevel,
1758 );
1759 self.va.reflect_prop(self_va);
1760 assert(ls <= self_va < ls + pg);
1765 assert(ls <= va < ls + pg);
1766
1767 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg);
1768 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg1);
1769 vstd_extra::arithmetic::lemma_nat_align_down_sound(va as nat, pg1);
1770 assert(nat_align_down(self_va as nat, pg) == ls) by {
1773 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg);
1774 let nad = nat_align_down(self_va as nat, pg) as int;
1775 let lsi = ls as int;
1776 let pgi = pg as int;
1777 assert(lsi <= nad);
1780 assert(0 <= nad - lsi && nad - lsi < pgi);
1782 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(nad, pgi);
1783 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(lsi, pgi);
1784 let kn = nad / pgi;
1785 let kl = lsi / pgi;
1786 assert(nad == pgi * kn); assert(lsi == pgi * kl); assert(nad - lsi == pgi * (kn - kl)) by (nonlinear_arith)
1789 requires
1790 nad == pgi * kn,
1791 lsi == pgi * kl,
1792 ;
1793 assert(kn - kl == 0) by (nonlinear_arith)
1794 requires
1795 0 <= pgi * (kn - kl) < pgi,
1796 pgi > 0,
1797 ;
1798 };
1799 vstd_extra::arithmetic::lemma_nat_align_down_monotone(self_va as nat, pg, pg1);
1800 vstd_extra::arithmetic::lemma_nat_align_down_within_block(self_va as nat, pg, pg1);
1801 }
1808
1809 #[verifier::rlimit(20000)]
1811 pub proof fn node_within_locked_range(self, level: PagingLevel)
1812 requires
1813 self.inv(),
1814 self.in_locked_range(),
1815 1 <= level < self.guard_level,
1816 ensures
1817 self.locked_range().start <= nat_align_down(
1818 self.va.to_vaddr() as nat,
1819 page_size((level + 1) as PagingLevel) as nat,
1820 ) as usize,
1821 nat_align_down(
1822 self.va.to_vaddr() as nat,
1823 page_size((level + 1) as PagingLevel) as nat,
1824 ) as usize + page_size((level + 1) as PagingLevel) <= self.locked_range().end,
1825 {
1826 let gl = self.guard_level;
1827 let ps_gl = page_size(gl as PagingLevel) as nat;
1828 let ps = page_size((level + 1) as PagingLevel) as nat;
1829 let pv = self.prefix.to_vaddr() as nat;
1830 let va = self.va.to_vaddr() as nat;
1831
1832 lemma_page_size_ge_page_size(gl as PagingLevel);
1833 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1834 lemma_page_size_divides((level + 1) as PagingLevel, gl as PagingLevel);
1835
1836 self.prefix.align_down_concrete(gl as int);
1837 self.prefix_aligned_to_guard_level();
1838 self.prefix_plus_ps_no_overflow();
1839 self.prefix.aligned_align_up_advances(gl as int);
1840 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(pv, ps_gl) as Vaddr);
1841
1842 let start = nat_align_down(pv, ps_gl);
1843 let end = nat_align_down(pv, ps_gl) + ps_gl;
1845
1846 lemma_nat_align_down_sound(pv, ps_gl);
1847 lemma_nat_align_down_sound(va, ps);
1848 let ad = nat_align_down(va, ps);
1849
1850 let q = (ps_gl / ps) as int;
1852 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ps_gl as int, ps as int);
1853 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps_gl as int);
1854 assert(end as int % ps_gl as int == 0) by {
1856 vstd::arithmetic::div_mod::lemma_add_mod_noop(start as int, ps_gl as int, ps_gl as int);
1857 vstd::arithmetic::div_mod::lemma_mod_self_0(ps_gl as int);
1858 };
1859 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(end as int, ps_gl as int);
1860 let ks = start as int / ps_gl as int;
1861 let ke = end as int / ps_gl as int;
1862 vstd::arithmetic::mul::lemma_mul_is_associative(ps as int, q, ks);
1863 vstd::arithmetic::mul::lemma_mul_is_associative(ps as int, q, ke);
1864 vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(q * ks, 0int, ps as int);
1865 vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(q * ke, 0int, ps as int);
1866 vstd::arithmetic::div_mod::lemma_small_mod(0nat, ps);
1867 assert(start as int % ps as int == 0int);
1868 assert(end as int % ps as int == 0int);
1869
1870 assert(ad >= start) by {
1871 vstd::arithmetic::div_mod::lemma_div_is_ordered(start as int, va as int, ps as int);
1872 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps as int);
1873 vstd::arithmetic::mul::lemma_mul_inequality(
1874 start as int / ps as int,
1875 va as int / ps as int,
1876 ps as int,
1877 );
1878 };
1879
1880 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ad as int, ps as int);
1881 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(end as int, ps as int);
1882 vstd::arithmetic::div_mod::lemma_div_is_ordered(ad as int, end as int, ps as int);
1883 if ad as int / ps as int == end as int / ps as int {
1884 assert(false);
1885 }
1886 assert(ad as int / ps as int + 1 <= end as int / ps as int);
1887 let ad_q = ad as int / ps as int;
1888 let end_q = end as int / ps as int;
1889 let ps_i = ps as int;
1890 vstd_extra::arithmetic::lemma_nat_align_down_sound(va, ps);
1891 vstd_extra::arithmetic::lemma_nat_align_up_sound(pv, ps_gl);
1892 assert(ad as int % ps as int == 0);
1893 assert(end as int % ps as int == 0);
1894 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ad as int, ps as int);
1895 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(end as int, ps as int);
1896 assert(ad as int == (ps as int) * (ad as int / ps as int) + ad as int % ps as int);
1898 assert(end as int == (ps as int) * (end as int / ps as int) + end as int % ps as int);
1899 vstd::arithmetic::mul::lemma_mul_is_commutative(ps as int, ad as int / ps as int);
1900 vstd::arithmetic::mul::lemma_mul_is_commutative(ps as int, end as int / ps as int);
1901 assert(ad as int == ad_q * ps_i + (ad as int % ps as int));
1902 assert(ad as int % ps as int == 0);
1903 assert(ad as int == ad_q * ps_i);
1904 assert(end as int % ps as int == 0);
1905 assert(end as int == end_q * ps_i) by (nonlinear_arith)
1906 requires
1907 end as int == (ps as int) * (end as int / ps as int) + end as int % ps as int,
1908 end as int % ps as int == 0,
1909 end_q == end as int / ps as int,
1910 ps_i == ps as int,
1911 ;
1912 assert((ad_q + 1) * ps_i <= end_q * ps_i) by (nonlinear_arith)
1913 requires
1914 ad_q + 1 <= end_q,
1915 ps_i >= 0,
1916 ;
1917 assert((ad_q + 1) * ps_i == ad_q * ps_i + ps_i) by (nonlinear_arith);
1918 }
1919
1920 pub proof fn prefix_aligned_to_guard_level(self)
1924 requires
1925 self.inv(),
1926 ensures
1927 self.prefix.to_vaddr() as nat % page_size(self.guard_level as PagingLevel) as nat == 0,
1928 {
1929 let gl = self.guard_level;
1930 let ps = page_size(gl as PagingLevel) as nat;
1931 lemma_page_size_ge_page_size(gl as PagingLevel);
1932
1933 self.prefix.align_down_shape(gl as int);
1936 self.prefix.align_down_leading_bits(gl as int);
1937 let aligned = self.prefix.align_down(gl as int);
1938
1939 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] aligned.index[i]
1940 == self.prefix.index[i] by {
1941 assert(self.prefix.index.contains_key(i));
1942 assert(aligned.index.contains_key(i));
1943 if i < gl - 1 {
1944 assert(self.prefix.index[i] == 0);
1945 }
1946 };
1947 assert(aligned.index =~= self.prefix.index);
1948 assert(aligned == self.prefix);
1949
1950 self.prefix.align_down_concrete(gl as int);
1952 self.prefix.to_vaddr_bounded();
1953 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps);
1954 aligned.reflect_prop(nat_align_down(self.prefix.to_vaddr() as nat, ps) as Vaddr);
1955 }
1956
1957 pub proof fn in_node_holds_at_top(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1970 requires
1971 self.inv(),
1972 self.va.reflect(self_va),
1973 self.guard_level == NR_LEVELS,
1974 node_size == page_size_spec((NR_LEVELS + 1) as PagingLevel),
1975 self.locked_range().start <= va < self.locked_range().end,
1976 ensures
1977 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1978 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1979 {
1980 let gl = self.guard_level;
1981 let lb = self.prefix.leading_bits;
1982 let big = 0x1_0000_0000_0000int; let ps_nr = page_size(NR_LEVELS as PagingLevel) as int;
1984
1985 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
1986 assert forall|i: int| 0 <= i < NR_LEVELS implies self.prefix.index[i] == 0 by {
1991 assert(self.prefix.index.contains_key(i));
1992 };
1993 self.prefix.to_vaddr_indices_drop_zero_range(0, NR_LEVELS as int);
1994 assert(self.prefix.to_vaddr_indices(NR_LEVELS as int) == 0);
1995 assert(self.prefix.to_vaddr() as int == lb * big);
1996
1997 self.prefix_aligned_to_guard_level();
1999 self.prefix_plus_ps_no_overflow();
2000 self.prefix.aligned_align_up_advances(gl as int);
2001 self.prefix.align_down_shape(gl as int);
2003 self.prefix.align_down_leading_bits(gl as int);
2004 let aligned = self.prefix.align_down(gl as int);
2005 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] aligned.index[i]
2006 == self.prefix.index[i] by {
2007 assert(self.prefix.index.contains_key(i));
2008 assert(aligned.index.contains_key(i));
2009 };
2010 assert(aligned.index =~= self.prefix.index);
2011 assert(aligned == self.prefix);
2012 assert(self.locked_range().start as int == lb * big);
2013 assert(self.locked_range().end as int == lb * big + ps_nr);
2014
2015 self.va.reflect_prop(self_va); self.va.to_vaddr_bounded(); assert(self.va.leading_bits == lb); let pv = (self.va.offset + self.va.to_vaddr_indices(0)) as int;
2020 assert(0 <= pv < big);
2021 assert(self_va as int == pv + lb * big);
2022 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, big as nat);
2023 assert(0 <= lb < 0x1_0000int);
2024 assert(nat_align_down(self_va as nat, big as nat) == (lb * big) as nat) by (nonlinear_arith)
2025 requires
2026 self_va as nat == (pv + lb * big) as nat,
2027 0 <= pv < big,
2028 0 <= lb < 0x1_0000int,
2029 big == 0x1_0000_0000_0000int,
2030 nat_align_down(self_va as nat, big as nat) <= self_va as nat,
2031 nat_align_down(self_va as nat, big as nat) % (big as nat) == 0,
2032 (self_va as nat) - nat_align_down(self_va as nat, big as nat) < big as nat,
2033 forall|n: nat|
2034 n <= self_va as nat && #[trigger] (n % (big as nat)) == 0 ==> n
2035 <= nat_align_down(self_va as nat, big as nat),
2036 ;
2037
2038 assert(ps_nr < big);
2042 }
2043
2044 pub proof fn prefix_plus_ps_no_overflow(self)
2050 requires
2051 self.inv(),
2052 ensures
2053 self.prefix.to_vaddr() + page_size(self.guard_level as PagingLevel) <= usize::MAX,
2054 {
2055 let gl = self.guard_level;
2056 lemma_page_size_ge_page_size(gl as PagingLevel);
2057 self.prefix.to_vaddr_bounded();
2058 self.prefix.to_vaddr_indices_gap_bound(0);
2059 vstd::arithmetic::power2::lemma2_to64();
2060 vstd::arithmetic::power2::lemma2_to64_rest();
2061 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
2062
2063 assert forall|i: int| 0 <= i < gl implies self.prefix.index[i] == 0 by {
2066 assert(self.prefix.index.contains_key(i));
2067 };
2068 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
2069 self.prefix.to_vaddr_indices_gap_bound(gl as int);
2070
2071 let ps = page_size(gl as PagingLevel) as int;
2075 let pv = self.prefix.to_vaddr() as int;
2076 let lb = self.prefix.leading_bits;
2077 assert(pv == self.prefix.to_vaddr_indices(gl as int) + lb * 0x1_0000_0000_0000int);
2078 assert(self.prefix.to_vaddr_indices(gl as int) + pow2((12 + 9 * gl) as nat) as int <= pow2(
2079 (12 + 9 * NR_LEVELS) as nat,
2080 ) as int);
2081 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
2082 assert(pow2((12 + 9 * gl) as nat) >= ps) by {
2083 if gl == 1 {
2085 assert(ps == 0x1000);
2086 } else if gl == 2 {
2087 assert(ps == 0x20_0000);
2088 } else if gl == 3 {
2089 assert(ps == 0x4000_0000);
2090 } else {
2091 assert(ps == 0x80_0000_0000);
2092 }
2093 };
2094 let tvi = self.prefix.to_vaddr_indices(gl as int) as int;
2102 assert(pow2((12 + 9 * gl) as nat) as int == NR_ENTRIES * ps) by {
2103 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
2104 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
2105 (gl + 1) as PagingLevel);
2106 };
2107 assert(tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int);
2108 assert(ps >= 0x1000);
2109
2110 assert(pv + ps <= usize::MAX as int) by (nonlinear_arith)
2111 requires
2112 pv == tvi + lb * 0x1_0000_0000_0000int,
2113 tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int,
2114 0 <= lb < 0x1_0000int,
2115 ps >= 0x1000,
2116 NR_ENTRIES == 512,
2117 usize::MAX == 0xffff_ffff_ffff_ffffusize,
2118 ;
2119 }
2120
2121 pub proof fn va_plus_page_size_no_overflow(self, level: PagingLevel)
2131 requires
2132 self.inv(),
2133 self.in_locked_range(),
2134 1 <= level <= self.guard_level,
2135 ensures
2136 self.va.to_vaddr() + page_size(level) <= usize::MAX,
2137 {
2138 let gl = self.guard_level;
2139 lemma_page_size_ge_page_size(gl as PagingLevel);
2140 lemma_page_size_ge_page_size(level as PagingLevel);
2141 page_size_monotonic(level as PagingLevel, gl as PagingLevel);
2142
2143 self.prefix_aligned_to_guard_level();
2145 self.prefix_plus_ps_no_overflow();
2146 self.prefix.aligned_align_up_advances(gl as int);
2147
2148 self.prefix.to_vaddr_bounded();
2151 self.prefix.to_vaddr_indices_gap_bound(0);
2152 vstd::arithmetic::power2::lemma2_to64();
2153 vstd::arithmetic::power2::lemma2_to64_rest();
2154 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
2155
2156 assert forall|i: int| 0 <= i < gl implies self.prefix.index[i] == 0 by {
2157 assert(self.prefix.index.contains_key(i));
2158 };
2159 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
2160 self.prefix.to_vaddr_indices_gap_bound(gl as int);
2161
2162 let ps = page_size(gl as PagingLevel) as int;
2163 let psl = page_size(level as PagingLevel) as int;
2164 let pv = self.prefix.to_vaddr() as int;
2165 let lb = self.prefix.leading_bits;
2166 let tvi = self.prefix.to_vaddr_indices(gl as int) as int;
2167 let va_val = self.va.to_vaddr() as int;
2168 assert(pv == tvi + lb * 0x1_0000_0000_0000int);
2169 assert(self.prefix.to_vaddr_indices(gl as int) + pow2((12 + 9 * gl) as nat) as int <= pow2(
2170 (12 + 9 * NR_LEVELS) as nat,
2171 ) as int);
2172 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
2173 assert(pow2((12 + 9 * gl) as nat) >= ps) by {
2174 if gl == 1 {
2175 assert(ps == 0x1000);
2176 } else if gl == 2 {
2177 assert(ps == 0x20_0000);
2178 } else if gl == 3 {
2179 assert(ps == 0x4000_0000);
2180 } else {
2181 assert(ps == 0x80_0000_0000);
2182 }
2183 };
2184 assert(pow2((12 + 9 * gl) as nat) as int == NR_ENTRIES * ps) by {
2185 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
2186 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
2187 (gl + 1) as PagingLevel);
2188 };
2189 assert(tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int);
2190 assert(ps >= 0x1000);
2191 assert(psl >= 0x1000);
2192 assert(psl <= ps);
2193 assert(va_val < pv + ps);
2194
2195 assert(va_val + psl <= usize::MAX as int) by (nonlinear_arith)
2196 requires
2197 va_val < pv + ps,
2198 pv == tvi + lb * 0x1_0000_0000_0000int,
2199 tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int,
2200 0 <= lb < 0x1_0000int,
2201 ps >= 0x1000,
2202 psl >= 0x1000,
2203 psl <= ps,
2204 NR_ENTRIES == 512,
2205 usize::MAX == 0xffff_ffff_ffff_ffffusize,
2206 ;
2207 }
2208
2209 pub proof fn locked_range_page_aligned(self)
2210 requires
2211 self.inv(),
2212 ensures
2213 self.locked_range().end % PAGE_SIZE == 0,
2214 self.locked_range().start % PAGE_SIZE == 0,
2215 {
2216 let gl = self.guard_level;
2217 let pv = self.prefix.to_vaddr() as nat;
2218 let ps = page_size(gl as PagingLevel) as nat;
2219 lemma_page_size_ge_page_size(gl as PagingLevel);
2220 lemma_page_size_divides(1u8, gl as PagingLevel);
2221 lemma_page_size_spec_level1();
2222 lemma_nat_align_down_sound(pv, ps);
2223 lemma_nat_align_up_sound(pv, ps);
2224 let start_va = nat_align_down(pv, ps);
2225 let end_va = nat_align_up(pv, ps);
2226 vstd::arithmetic::div_mod::lemma_mod_mod(
2227 start_va as int,
2228 PAGE_SIZE as int,
2229 ps as int / PAGE_SIZE as int,
2230 );
2231 vstd::arithmetic::div_mod::lemma_mod_mod(
2232 end_va as int,
2233 PAGE_SIZE as int,
2234 ps as int / PAGE_SIZE as int,
2235 );
2236 self.prefix.align_down_concrete(gl as int);
2237 self.prefix_aligned_to_guard_level();
2238 self.prefix_plus_ps_no_overflow();
2239 self.prefix.aligned_align_up_advances(gl as int);
2240
2241 self.prefix.to_vaddr_bounded();
2242 self.prefix.to_vaddr_indices_gap_bound(0);
2243 vstd::arithmetic::power2::lemma2_to64();
2244 vstd::arithmetic::power2::lemma2_to64_rest();
2245 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
2246 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
2247 page_size_monotonic(gl as PagingLevel, NR_LEVELS as PagingLevel);
2248 vstd::arithmetic::power2::lemma_pow2_adds(12nat, 27nat);
2249 assert(page_size(NR_LEVELS as PagingLevel) == pow2(39nat));
2250 vstd::arithmetic::power2::lemma_pow2_adds(1nat, 48nat);
2251 vstd_extra::external::ilog2::lemma_pow2_increases(49nat, 64nat);
2252
2253 self.prefix.align_down_shape(gl as int);
2254 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(start_va as Vaddr);
2255 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(end_va as Vaddr);
2256 }
2257
2258 pub proof fn cur_subtree_inv(self)
2259 requires
2260 self.inv(),
2261 ensures
2262 self.cur_subtree().inv(),
2263 {
2264 let cont = self.continuations[self.level - 1];
2265 cont.inv_children_unroll(cont.idx as int)
2266 }
2267
2268 pub proof fn cur_entry_absent_not_present(self)
2270 requires
2271 self.inv(),
2272 self.in_locked_range(),
2273 self.cur_entry_owner().is_absent(),
2274 ensures
2275 !self@.present(),
2276 {
2277 self.cur_subtree_inv();
2278 let cur_va = self.cur_va();
2279 let cur_subtree = self.cur_subtree();
2280 let cur_path = cur_subtree.value.path;
2281 PageTableOwner(cur_subtree).view_rec_absent_empty(cur_path);
2282
2283 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
2284 <= cur_va < m.va_range.end) by {
2285 if m.va_range.start <= cur_va < m.va_range.end {
2286 self.mapping_covering_cur_va_from_cur_subtree(m);
2287 }
2288 };
2289
2290 let filtered = self@.mappings.filter(
2291 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
2292 );
2293 assert(filtered =~= set![]) by {
2294 assert forall|m: Mapping| !filtered.contains(m) by {
2295 if self@.mappings.contains(m) && m.va_range.start <= self@.cur_va < m.va_range.end {
2296 assert(self.view_mappings().contains(m));
2297 }
2298 };
2299 };
2300 }
2301
2302 pub proof fn cur_subtree_empty_not_present(self)
2304 requires
2305 self.inv(),
2306 self.in_locked_range(),
2307 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value.path) =~= set![],
2308 ensures
2309 !self@.present(),
2310 {
2311 let cur_va = self.cur_va();
2312
2313 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
2314 <= cur_va < m.va_range.end) by {
2315 if m.va_range.start <= cur_va < m.va_range.end {
2316 self.mapping_covering_cur_va_from_cur_subtree(m);
2317 }
2318 };
2319
2320 let filtered = self@.mappings.filter(
2321 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
2322 );
2323 assert(filtered =~= set![]) by {
2324 assert forall|m: Mapping| !filtered.contains(m) by {
2325 if self@.mappings.contains(m) && m.va_range.start <= self@.cur_va < m.va_range.end {
2326 assert(self.view_mappings().contains(m));
2327 }
2328 };
2329 };
2330 assert(filtered.len() == 0);
2331 }
2332
2333 pub proof fn cur_entry_frame_present(self)
2334 requires
2335 self.inv(),
2336 self.in_locked_range(),
2337 self.cur_entry_owner().is_frame(),
2338 ensures
2339 self@.present(),
2340 self@.query(
2341 self.cur_entry_owner().frame.unwrap().mapped_pa,
2342 self.cur_entry_owner().frame.unwrap().size,
2343 self.cur_entry_owner().frame.unwrap().prop,
2344 ),
2345 {
2346 self.cur_subtree_inv();
2347 self.cur_va_in_subtree_range();
2348 self.view_preserves_inv();
2349 let subtree = self.cur_subtree();
2350 let path = subtree.value.path;
2351 let frame = self.cur_entry_owner().frame.unwrap();
2352 let pt_level = INC_LEVELS - path.len();
2353 let cont = self.continuations[self.level - 1];
2354
2355 cont.path().push_tail_property_len(cont.idx as usize);
2356 assert(cont.level() == self.level) by {
2357 if self.level == 1 {
2358 } else if self.level == 2 {
2359 } else if self.level == 3 {
2360 } else {
2361 }
2362 };
2363 assert(pt_level == self.level);
2364
2365 let m = Mapping {
2366 va_range: Range {
2367 start: vaddr_of::<C>(path) as int,
2368 end: vaddr_of::<C>(path) as int + page_size(pt_level as PagingLevel) as int,
2369 },
2370 pa_range: Range {
2371 start: frame.mapped_pa,
2372 end: (frame.mapped_pa + page_size(pt_level as PagingLevel)) as Paddr,
2373 },
2374 page_size: page_size(pt_level as PagingLevel),
2375 property: frame.prop,
2376 };
2377 assert(PageTableOwner(subtree).view_rec(path) =~= set![m]);
2378 assert(self.view_mappings().contains(m));
2379 assert(m.inv());
2380 assert(m.va_range.start <= self@.cur_va < m.va_range.end) by {
2381 self.cur_va_in_subtree_range();
2382 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
2383 };
2384
2385 let filtered = self@.mappings.filter(
2386 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
2387 );
2388 assert(filtered.contains(m));
2389 axiom_set_intersect_finite::<Mapping>(
2390 self@.mappings,
2391 Set::new(|m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end),
2392 );
2393 axiom_set_contains_len(filtered, m);
2394 }
2395
2396 pub open spec fn path_metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2398 forall|i: int|
2399 #![trigger self.continuations[i]]
2400 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].entry_own.metaregion_sound(
2401 regions,
2402 )
2403 }
2404
2405 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2406 &&& self.map_full_tree(
2407 |entry_owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2408 entry_owner.metaregion_sound(regions),
2409 )
2410 &&& self.path_metaregion_sound(regions)
2411 }
2412
2413 pub proof fn metaregion_preserved(
2414 self,
2415 other: Self,
2416 regions0: MetaRegionOwners,
2417 regions1: MetaRegionOwners,
2418 )
2419 requires
2420 self.inv(),
2421 self.metaregion_sound(regions0),
2422 self.level == other.level,
2423 self.continuations =~= other.continuations,
2424 OwnerSubtree::implies(
2425 PageTableOwner::<C>::metaregion_sound_pred(regions0),
2426 PageTableOwner::<C>::metaregion_sound_pred(regions1),
2427 ),
2428 ensures
2429 other.metaregion_sound(regions1),
2430 {
2431 let f = PageTableOwner::metaregion_sound_pred(regions0);
2432 let g = PageTableOwner::metaregion_sound_pred(regions1);
2433
2434 assert forall|i: int| #![auto] self.level - 1 <= i < NR_LEVELS implies {
2435 other.continuations[i].map_children(g)
2436 } by {
2437 let cont = self.continuations[i];
2438 assert(cont.inv());
2439 assert(cont.map_children(f));
2440 reveal(CursorContinuation::inv_children);
2441 assert forall|j: int|
2442 0 <= j < NR_ENTRIES
2443 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().tree_predicate_map(
2444 cont.path().push_tail(j as usize), g) by {
2445 cont.inv_children_unroll(j);
2446 cont.children[j].unwrap().map_implies(cont.path().push_tail(j as usize), f, g);
2447 };
2448 };
2449 assert(other.path_metaregion_sound(regions1)) by {
2450 assert forall|i: int|
2451 #![trigger other.continuations[i]]
2452 self.level - 1 <= i
2453 < NR_LEVELS implies other.continuations[i].entry_own.metaregion_sound(
2454 regions1,
2455 ) by {
2456 self.inv_continuation(i);
2457 let eo = self.continuations[i].entry_own;
2458 assert(eo.metaregion_sound(regions0));
2459 assert(g(eo, self.continuations[i].path()));
2460 };
2461 };
2462 }
2463
2464 pub proof fn metaregion_slot_owners_preserved(
2466 self,
2467 regions0: MetaRegionOwners,
2468 regions1: MetaRegionOwners,
2469 )
2470 requires
2471 self.inv(),
2472 self.metaregion_sound(regions0),
2473 regions0.slot_owners =~= regions1.slot_owners,
2474 forall|k: usize|
2475 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2476 forall|k: usize|
2477 regions0.slots.contains_key(k) ==> regions0.slots[k]
2478 == #[trigger] regions1.slots[k],
2479 ensures
2480 self.metaregion_sound(regions1),
2481 {
2482 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2483 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2484 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2485 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
2486 entry.metaregion_sound_slot_owners_only(regions0, regions1);
2487 };
2488 self.metaregion_preserved(self, regions0, regions1);
2489 }
2490
2491 pub proof fn metaregion_slot_owners_rc_increment(
2492 self,
2493 regions0: MetaRegionOwners,
2494 regions1: MetaRegionOwners,
2495 idx: usize,
2496 )
2497 requires
2498 self.inv(),
2499 self.metaregion_sound(regions0),
2500 regions0.inv(),
2501 regions1.slots == regions0.slots,
2502 regions1.slot_owners.dom() == regions0.slot_owners.dom(),
2503 regions1.slot_owners[idx].inner_perms.ref_count.value()
2504 == regions0.slot_owners[idx].inner_perms.ref_count.value() + 1,
2505 regions1.slot_owners[idx].inner_perms.ref_count.id()
2506 == regions0.slot_owners[idx].inner_perms.ref_count.id(),
2507 regions1.slot_owners[idx].inner_perms.storage
2508 == regions0.slot_owners[idx].inner_perms.storage,
2509 regions1.slot_owners[idx].inner_perms.vtable_ptr
2510 == regions0.slot_owners[idx].inner_perms.vtable_ptr,
2511 regions1.slot_owners[idx].inner_perms.in_list
2512 == regions0.slot_owners[idx].inner_perms.in_list,
2513 regions1.slot_owners[idx].paths_in_pt == regions0.slot_owners[idx].paths_in_pt,
2514 regions1.slot_owners[idx].self_addr == regions0.slot_owners[idx].self_addr,
2515 regions1.slot_owners[idx].usage == regions0.slot_owners[idx].usage,
2516 regions1.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
2517 regions1.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX,
2519 forall|i: usize|
2520 #![trigger regions1.slot_owners[i]]
2521 i != idx && regions0.slot_owners.contains_key(i) ==> regions1.slot_owners[i]
2522 == regions0.slot_owners[i],
2523 ensures
2524 self.metaregion_sound(regions1),
2525 {
2526 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2527 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2528 assert(OwnerSubtree::implies(f, g)) by {
2529 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2530 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
2531 if entry.meta_slot_paddr() is Some {
2532 let eidx = frame_to_index(entry.meta_slot_paddr().unwrap());
2533 if eidx != idx {
2534 } else {
2535 entry.metaregion_sound_rc_value_changed(regions0, regions1);
2536 }
2537 }
2538 };
2539 };
2540 self.metaregion_preserved(self, regions0, regions1);
2541 }
2542
2543 pub proof fn metaregion_borrow_slot(
2546 self,
2547 regions0: MetaRegionOwners,
2548 regions1: MetaRegionOwners,
2549 changed_idx: usize,
2550 )
2551 requires
2552 self.inv(),
2553 self.metaregion_sound(regions0),
2554 regions1.inv(),
2555 forall|k: usize|
2556 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2557 forall|k: usize|
2564 regions0.slots.contains_key(k) ==> regions0.slots[k]
2565 == #[trigger] regions1.slots[k],
2566 regions1.slot_owners[changed_idx].inner_perms
2568 == regions0.slot_owners[changed_idx].inner_perms,
2569 regions1.slot_owners[changed_idx].self_addr
2570 == regions0.slot_owners[changed_idx].self_addr,
2571 regions1.slot_owners[changed_idx].usage == regions0.slot_owners[changed_idx].usage,
2572 regions1.slot_owners[changed_idx].paths_in_pt
2573 == regions0.slot_owners[changed_idx].paths_in_pt,
2574 forall|i: usize|
2576 #![trigger regions1.slot_owners[i]]
2577 i != changed_idx ==> regions0.slot_owners[i] == regions1.slot_owners[i],
2578 regions0.slot_owners.dom() =~= regions1.slot_owners.dom(),
2579 ensures
2580 self.metaregion_sound(regions1),
2581 {
2582 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2583 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2584 let nsp = PageTableOwner::<C>::not_in_scope_pred();
2585
2586 assert(OwnerSubtree::implies(
2587 |v: EntryOwner<C>, p: TreePath<NR_ENTRIES>| f(v, p) && nsp(v, p),
2588 g,
2589 )) by {
2590 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2591 entry.inv() && f(entry, path) && nsp(entry, path) implies #[trigger] g(
2592 entry,
2593 path,
2594 ) by {
2595 if entry.meta_slot_paddr() is Some {
2596 let eidx = frame_to_index(entry.meta_slot_paddr().unwrap());
2597 if eidx != changed_idx {
2598 } else if entry.is_frame() {
2599 assert(regions1.slots.contains_key(eidx));
2600 }
2601 }
2602 };
2603 };
2604
2605 assert forall|i: int|
2606 #![trigger self.continuations[i]]
2607 self.level - 1 <= i < NR_LEVELS implies { self.continuations[i].map_children(g) } by {
2608 let cont = self.continuations[i];
2609 reveal(CursorContinuation::inv_children);
2610 assert forall|j: int|
2611 0 <= j < NR_ENTRIES
2612 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().tree_predicate_map(
2613 cont.path().push_tail(j as usize), nsp) by {
2614 cont.inv_children_unroll(j);
2615 PageTableOwner::tree_not_in_scope(
2616 cont.children[j].unwrap(),
2617 cont.path().push_tail(j as usize),
2618 );
2619 };
2620 assert forall|j: int|
2621 0 <= j < NR_ENTRIES
2622 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().tree_predicate_map(
2623 cont.path().push_tail(j as usize), g) by {
2624 cont.inv_children_unroll(j);
2625 cont.children[j].unwrap().map_implies_and(
2626 cont.path().push_tail(j as usize),
2627 f,
2628 nsp,
2629 g,
2630 );
2631 };
2632 };
2633
2634 assert(self.path_metaregion_sound(regions1)) by {
2635 assert forall|i: int|
2636 #![trigger self.continuations[i]]
2637 self.level - 1 <= i
2638 < NR_LEVELS implies self.continuations[i].entry_own.metaregion_sound(
2639 regions1,
2640 ) by {
2641 self.inv_continuation(i);
2642 let eo = self.continuations[i].entry_own;
2643 if eo.meta_slot_paddr() is Some {
2644 let eidx = frame_to_index(eo.meta_slot_paddr().unwrap());
2645 if eidx != changed_idx {
2646 }
2647 }
2648 };
2649 };
2650 }
2651
2652 pub proof fn cont_entries_metaregion(self, regions: MetaRegionOwners)
2662 requires
2663 self.inv(),
2664 self.metaregion_sound(regions),
2665 ensures
2666 forall|i: int|
2667 #![trigger self.continuations[i]]
2668 self.level - 1 <= i < NR_LEVELS
2669 ==> self.continuations[i].entry_own.metaregion_sound(regions),
2670 {
2671 }
2674
2675 pub open spec fn new(
2676 owner_subtree: OwnerSubtree<C>,
2677 idx: usize,
2678 guard: PageTableGuard<'rcu, C>,
2679 ) -> Self {
2680 let va = AbstractVaddr {
2681 offset: 0,
2682 index: Map::new(|i: int| 0 <= i < NR_LEVELS, |i: int| 0).insert(
2683 NR_LEVELS - 1,
2684 idx as int,
2685 ),
2686 leading_bits: C::LEADING_BITS_spec() as int,
2692 };
2693 Self {
2694 level: NR_LEVELS as PagingLevel,
2695 continuations: Map::empty().insert(
2696 NR_LEVELS - 1 as int,
2697 CursorContinuation::new(owner_subtree, idx, guard),
2698 ),
2699 va,
2700 guard_level: NR_LEVELS as PagingLevel,
2701 prefix: va,
2702 popped_too_high: false,
2703 }
2704 }
2705
2706 pub axiom fn tracked_new(
2707 tracked owner_subtree: OwnerSubtree<C>,
2708 idx: usize,
2709 guard: PageTableGuard<'rcu, C>,
2710 ) -> (tracked res: Self)
2711 ensures
2712 res == Self::new(owner_subtree, idx, guard),
2713 ;
2714}
2715
2716pub ghost struct CursorView<C: PageTableConfig> {
2717 pub cur_va: Vaddr,
2718 pub mappings: Set<Mapping>,
2719 pub phantom: PhantomData<C>,
2720}
2721
2722impl<'rcu, C: PageTableConfig> View for CursorOwner<'rcu, C> {
2723 type V = CursorView<C>;
2724
2725 open spec fn view(&self) -> Self::V {
2726 CursorView { cur_va: self.cur_va(), mappings: self.view_mappings(), phantom: PhantomData }
2727 }
2728}
2729
2730impl<C: PageTableConfig> Inv for CursorView<C> {
2731 open spec fn inv(self) -> bool {
2732 &&& self.mappings.finite()
2733 &&& forall|m: Mapping|
2734 #![auto]
2735 self.mappings.contains(m)
2736 ==> m.inv()
2737 &&& forall|m: Mapping|
2743 #![auto]
2744 self.mappings.contains(m) ==> {
2745 &&& vaddr_range_bounds_spec::<C>().0 <= m.va_range.start
2746 &&& m.va_range.end <= vaddr_range_bounds_spec::<C>().1 + 1
2747 }
2748 &&& self.non_overlapping()
2749 }
2750}
2751
2752impl<C: PageTableConfig> CursorView<C> {
2753 pub open spec fn non_overlapping(self) -> bool {
2756 forall|m: Mapping, n: Mapping|
2757 #![auto]
2758 self.mappings.contains(m) ==> self.mappings.contains(n) ==> m != n ==> m.va_range.end
2759 <= n.va_range.start || n.va_range.end <= m.va_range.start
2760 }
2761}
2762
2763pub axiom fn axiom_view_in_vaddr_range<'rcu, C: PageTableConfig>(owner: &CursorOwner<'rcu, C>)
2784 requires
2785 owner.inv(),
2786 ensures
2787 forall|m: Mapping|
2788 #![auto]
2789 owner.view_mappings().contains(m) ==> {
2790 &&& vaddr_range_bounds_spec::<C>().0 <= m.va_range.start
2791 &&& m.va_range.end <= vaddr_range_bounds_spec::<C>().1 + 1
2792 },
2793;
2794
2795impl<'rcu, C: PageTableConfig> InvView for CursorOwner<'rcu, C> {
2796 proof fn view_preserves_inv(self) {
2797 self.view_non_overlapping();
2799 self.view_mappings_finite();
2801 self.view_mapping_inv();
2804 axiom_view_in_vaddr_range::<C>(&self);
2813 }
2814}
2815
2816impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
2817 pub proof fn view_non_overlapping(self)
2823 requires
2824 self.inv(),
2825 ensures
2826 self@.non_overlapping(),
2827 {
2828 self.as_page_table_owner_view_non_overlapping();
2829 }
2830}
2831
2832impl<'rcu, C: PageTableConfig, A: InAtomicMode> Inv for Cursor<'rcu, C, A> {
2833 open spec fn inv(self) -> bool {
2834 &&& 1 <= self.level <= NR_LEVELS
2842 + 1
2843 &&& self.level <= self.guard_level + 1
2851 &&& self.guard_level
2852 <= NR_LEVELS
2853 &&& self.va >= self.barrier_va.start
2855 &&& self.va % PAGE_SIZE == 0
2856 }
2857}
2858
2859impl<'rcu, C: PageTableConfig, A: InAtomicMode> OwnerOf for Cursor<'rcu, C, A> {
2860 type Owner = CursorOwner<'rcu, C>;
2861
2862 open spec fn wf(self, owner: Self::Owner) -> bool {
2863 &&& owner.va.reflect(self.va)
2864 &&& self.level == owner.level
2865 &&& owner.guard_level
2866 == self.guard_level
2867 &&& self.level <= 4 ==> {
2876 &&& 4 <= self.guard_level ==> {
2877 &&& self.path[3] is Some
2878 &&& owner.continuations.contains_key(3)
2879 &&& owner.continuations[3].guard == self.path[3].unwrap()
2880 }
2881 &&& 4 > self.guard_level ==> self.path[3] is None
2882 }
2883 &&& self.level <= 3 ==> {
2884 &&& 3 <= self.guard_level ==> {
2885 &&& self.path[2] is Some
2886 &&& owner.continuations.contains_key(2)
2887 &&& owner.continuations[2].guard == self.path[2].unwrap()
2888 }
2889 &&& 3 > self.guard_level ==> self.path[2] is None
2890 }
2891 &&& self.level <= 2 ==> {
2892 &&& 2 <= self.guard_level ==> {
2893 &&& self.path[1] is Some
2894 &&& owner.continuations.contains_key(1)
2895 &&& owner.continuations[1].guard == self.path[1].unwrap()
2896 }
2897 &&& 2 > self.guard_level ==> self.path[1] is None
2898 }
2899 &&& self.level == 1 ==> {
2900 &&& 1 <= self.guard_level ==> {
2904 &&& self.path[0] is Some
2905 &&& owner.continuations.contains_key(0)
2906 &&& owner.continuations[0].guard == self.path[0].unwrap()
2907 }
2908 &&& 1 > self.guard_level ==> self.path[0] is None
2909 }
2910 &&& self.barrier_va.start == owner.locked_range().start
2911 &&& self.barrier_va.end == owner.locked_range().end
2912 }
2913}
2914
2915impl<'rcu, C: PageTableConfig, A: InAtomicMode> ModelOf for Cursor<'rcu, C, A> {
2916
2917}
2918
2919}