1use vstd::arithmetic::power2::pow2;
2use vstd::prelude::*;
3use vstd::seq_lib::*;
4use vstd::set::lemma_set_contains_len;
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::arch::mm::PagingConsts;
20use crate::mm::frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED};
21use crate::mm::page_prop::PageProperty;
22use crate::mm::page_table::*;
23use crate::mm::{
24 MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr, nr_subpage_per_huge,
25 page_size,
26};
27use crate::specs::arch::{MAX_PADDR, NR_ENTRIES, NR_LEVELS, PAGE_SIZE, has_safe_slot};
28use crate::specs::mm::frame::mapping::frame_to_index;
29use crate::specs::mm::page_table::cursor::page_size_lemmas::{
30 lemma_page_size_divides, lemma_page_size_ge_page_size, lemma_page_size_spec_level1,
31};
32use crate::specs::mm::page_table::owners::*;
33
34use crate::specs::mm::page_table::{nat_align_down, nat_align_up};
35use crate::specs::mm::{
36 frame::{mapping::meta_addr, meta_region_owners::MetaRegionOwners},
37 page_table::{AbstractVaddr, Guards, Mapping},
38};
39use crate::specs::task::InAtomicMode;
40
41verus! {
42
43pub tracked struct CursorContinuation<'rcu, C: PageTableConfig> {
44 pub entry_own: EntryOwner<C>,
45 pub idx: usize,
46 pub tree_level: nat,
47 pub children: Seq<Option<OwnerSubtree<C>>>,
48 pub path: TreePath<NR_ENTRIES>,
49 pub guard: PageTableGuard<'rcu, C>,
50}
51
52impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
53 pub open spec fn path(self) -> TreePath<NR_ENTRIES> {
54 self.entry_own.path
55 }
56
57 pub open spec fn child(self) -> OwnerSubtree<C> {
58 self.children[self.idx as int]->0
59 }
60
61 pub open spec fn take_child(self) -> (OwnerSubtree<C>, Self) {
62 let child = self.children[self.idx as int]->0;
63 let cont = Self {
64 children: self.children.remove(self.idx as int).insert(self.idx as int, None),
65 ..self
66 };
67 (child, cont)
68 }
69
70 pub proof fn tracked_take_child(tracked &mut self) -> (tracked res: OwnerSubtree<C>)
71 requires
72 old(self).inv(),
73 old(self).idx < old(self).children.len(),
74 old(self).children[old(self).idx as int] is Some,
75 ensures
76 res == old(self).take_child().0,
77 *final(self) == old(self).take_child().1,
78 res.inv(),
79 {
80 self.inv_children_unroll(self.idx as int);
81 let tracked child = self.children.tracked_remove(old(self).idx as int).tracked_unwrap();
82 self.children.tracked_insert(old(self).idx as int, None);
83 child
84 }
85
86 pub open spec fn put_child(self, child: OwnerSubtree<C>) -> Self {
87 Self {
88 children: self.children.remove(self.idx as int).insert(self.idx as int, Some(child)),
89 ..self
90 }
91 }
92
93 pub proof fn tracked_put_child(tracked &mut self, tracked child: OwnerSubtree<C>)
94 requires
95 old(self).idx < old(self).children.len(),
96 old(self).children[old(self).idx as int] is None,
97 ensures
98 *final(self) == old(self).put_child(child),
99 {
100 let _ = self.children.tracked_remove(old(self).idx as int);
101 self.children.tracked_insert(old(self).idx as int, Some(child));
102 }
103
104 pub proof fn take_put_child(self)
105 requires
106 self.idx < self.children.len(),
107 self.children[self.idx as int] is Some,
108 ensures
109 self.take_child().1.put_child(self.take_child().0) == self,
110 {
111 let child = self.take_child().0;
112 let cont = self.take_child().1;
113 assert(cont.put_child(child).children == self.children);
114 }
115
116 pub open spec fn make_cont(self, idx: usize, guard: PageTableGuard<'rcu, C>) -> (Self, Self) {
117 let child = Self {
118 entry_own: self.children[self.idx as int]->0.value,
119 tree_level: (self.tree_level + 1) as nat,
120 idx: idx,
121 children: self.children[self.idx as int]->0.children,
122 path: self.path.push_tail(self.idx as usize),
123 guard: guard,
124 };
125 let cont = Self { children: self.children.update(self.idx as int, None), ..self };
126 (child, cont)
127 }
128
129 pub axiom fn tracked_make_cont(
130 tracked &mut self,
131 idx: usize,
132 guard: PageTableGuard<'rcu, C>,
133 ) -> (tracked res: Self)
134 requires
135 old(self).all_some(),
136 old(self).idx < NR_ENTRIES,
137 idx < NR_ENTRIES,
138 ensures
139 res == old(self).make_cont(idx, guard).0,
140 *final(self) == old(self).make_cont(idx, guard).1,
141 ;
142
143 pub open spec fn restore(self, child: Self) -> (Self, PageTableGuard<'rcu, C>) {
144 let child_node = OwnerSubtree {
145 value: child.entry_own,
146 level: child.tree_level,
147 children: child.children,
148 };
149 (
150 Self { children: self.children.update(self.idx as int, Some(child_node)), ..self },
151 child.guard,
152 )
153 }
154
155 pub axiom fn tracked_restore(tracked &mut self, tracked child: Self) -> (tracked guard:
156 PageTableGuard<'rcu, C>)
157 ensures
158 *final(self) == old(self).restore(child).0,
159 guard == old(self).restore(child).1,
160 ;
161
162 pub open spec fn new(
163 owner_subtree: OwnerSubtree<C>,
164 idx: usize,
165 guard: PageTableGuard<'rcu, C>,
166 ) -> Self {
167 Self {
168 entry_own: owner_subtree.value,
169 idx: idx,
170 tree_level: owner_subtree.level,
171 children: owner_subtree.children,
172 path: TreePath::new(Seq::empty()),
173 guard: guard,
174 }
175 }
176
177 pub axiom fn tracked_new(
178 tracked owner_subtree: OwnerSubtree<C>,
179 idx: usize,
180 guard: PageTableGuard<'rcu, C>,
181 ) -> (tracked res: Self)
182 ensures
183 res == Self::new(owner_subtree, idx, guard),
184 ;
185
186 pub open spec fn map_children(
187 self,
188 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
189 ) -> bool {
190 forall|i: int|
191 #![trigger(self.children[i])]
192 0 <= i < self.children.len() ==> self.children[i] is Some
193 ==> self.children[i]->0.tree_predicate_map(self.path().push_tail(i as usize), f)
194 }
195
196 pub open spec fn level(self) -> PagingLevel {
199 self.entry_own.node().level
200 }
201
202 pub open spec fn inv_children(self) -> bool {
203 self.children.all(|child: Option<OwnerSubtree<C>>| child is Some ==> child->0.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]->0.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]->0.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->0.value.parent_level == self.level()
240 &&& child->0.level == self.tree_level + 1
241 &&& child->0.value.path.len() == self.entry_own.node().tree_level + 1
242 &&& child->0.value.match_pte(
243 self.entry_own.node().children_perm.value()[i],
244 self.entry_own.node().level,
245 )
246 &&& child->0.value.path == self.path().push_tail(i as usize)
247 }
248 }
249 }
250
251 pub open spec fn inv_children_rel(self) -> bool {
252 forall_seq(self.children, self.inv_children_rel_pred())
253 }
254
255 pub open spec fn pt_inv_children_pred() -> spec_fn(int, Option<OwnerSubtree<C>>) -> bool {
256 |i: int, child: Option<OwnerSubtree<C>>| child is Some ==> PageTableOwner(child->0).pt_inv()
257 }
258
259 pub open spec fn pt_inv_children(self) -> bool {
260 forall_seq(self.children, Self::pt_inv_children_pred())
261 }
262
263 pub proof fn pt_inv_children_unroll(self, i: int)
264 requires
265 self.pt_inv_children(),
266 0 <= i < self.children.len(),
267 self.children[i] is Some,
268 ensures
269 PageTableOwner(self.children[i]->0).pt_inv(),
270 {
271 lemma_forall_seq_index(self.children, Self::pt_inv_children_pred(), i);
272 }
273
274 pub proof fn inv_children_rel_unroll(self, i: int)
275 requires
276 self.inv_children_rel(),
277 0 <= i < self.children.len(),
278 self.children[i] is Some,
279 ensures
280 self.children[i]->0.value.parent_level == self.level(),
281 self.children[i]->0.level == self.tree_level + 1,
282 self.children[i]->0.value.path.len() == self.entry_own.node().tree_level + 1,
283 self.children[i]->0.value.match_pte(
284 self.entry_own.node().children_perm.value()[i],
285 self.entry_own.node().level,
286 ),
287 self.children[i]->0.value.path == self.path().push_tail(i as usize),
288 {
289 lemma_forall_seq_index(self.children, self.inv_children_rel_pred(), i);
290 }
291
292 pub open spec fn inv(self) -> bool {
293 &&& self.children.len() == NR_ENTRIES
294 &&& 0 <= self.idx < NR_ENTRIES
295 &&& self.inv_children()
296 &&& self.inv_children_rel()
297 &&& self.pt_inv_children()
298 &&& self.entry_own.is_node()
299 &&& self.entry_own.inv()
300 &&& self.entry_own.node().relate_guard(self.guard)
301 &&& self.tree_level == INC_LEVELS - self.level() - 1
302 &&& self.tree_level < INC_LEVELS - 1
303 &&& self.path().len() == self.tree_level
304 }
305
306 pub open spec fn all_some(self) -> bool {
307 forall|i: int| 0 <= i < NR_ENTRIES ==> self.children[i] is Some
308 }
309
310 pub open spec fn all_but_index_some(self) -> bool {
311 &&& forall|i: int| 0 <= i < self.idx ==> self.children[i] is Some
312 &&& forall|i: int| self.idx < i < NR_ENTRIES ==> self.children[i] is Some
313 &&& self.children[self.idx as int] is None
314 }
315
316 pub open spec fn inc_index(self) -> Self {
317 Self { idx: (self.idx + 1) as usize, ..self }
318 }
319
320 pub proof fn do_inc_index(tracked &mut self)
321 requires
322 old(self).idx + 1 < NR_ENTRIES,
323 ensures
324 *final(self) == old(self).inc_index(),
325 {
326 self.idx = (self.idx + 1) as usize;
327 }
328
329 pub open spec fn node_locked(self, guards: Guards<'rcu>) -> bool {
330 guards.lock_held(self.guard.inner.inner@.ptr.addr())
331 }
332
333 pub open spec fn view_mappings(self) -> Set<Mapping> {
334 self.children.map(
335 |i, child: Option<OwnerSubtree<C>>|
336 if child is Some {
337 PageTableOwner(child->0).view_rec(self.path().push_tail(i as usize))
338 } else {
339 Set::empty()
340 },
341 ).to_set().flatten()
342 }
343
344 pub broadcast proof fn lemma_view_mappings_contains(self)
345 ensures
346 #![trigger self.view_mappings()]
347 forall|m: Mapping| #[trigger]
348 self.view_mappings().contains(m) ==> exists|i: int|
349 #![trigger self.children[i]]
350 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
351 self.children[i]->0,
352 ).view_rec(self.path().push_tail(i as usize)).contains(m),
353 {
354 broadcast use vstd::seq_lib::group_seq_properties;
355
356 assert forall|m: Mapping| self.view_mappings().contains(m) implies exists|i: int|
357 #![trigger self.children[i]]
358 0 <= i < self.children.len() && self.children[i] is Some && PageTableOwner(
359 self.children[i]->0,
360 ).view_rec(self.path().push_tail(i as usize)).contains(m) by {
361 let mapped = self.children.map(
362 |i, child: Option<OwnerSubtree<C>>|
363 if child is Some {
364 PageTableOwner(child->0).view_rec(self.path().push_tail(i as usize))
365 } else {
366 Set::empty()
367 },
368 );
369 mapped.to_set().lemma_flatten_contains(m);
370 let elem_s = choose|elem_s: Set<Mapping>| #[trigger]
371 mapped.to_set().contains(elem_s) && elem_s.contains(m);
372 mapped.to_set_ensures();
373 assert(mapped.contains(elem_s));
374 let i = mapped.lemma_contains_to_index(elem_s);
375 if self.children[i] is Some {
376 assert(mapped[i] == PageTableOwner(self.children[i]->0).view_rec(
377 self.path().push_tail(i as usize),
378 ));
379 } else {
380 assert(mapped[i] == Set::<Mapping>::empty());
381 assert(false);
382 }
383 }
384 }
385
386 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
387 requires
388 0 <= i < self.children.len(),
389 self.children[i] is Some,
390 #[trigger] PageTableOwner(self.children[i]->0).view_rec(
391 self.path().push_tail(i as usize),
392 ).contains(m),
393 ensures
394 self.view_mappings().contains(m),
395 {
396 broadcast use vstd::seq_lib::group_seq_properties;
397
398 let mapped = self.children.map(
399 |i, child: Option<OwnerSubtree<C>>|
400 if child is Some {
401 PageTableOwner(child->0).view_rec(self.path().push_tail(i as usize))
402 } else {
403 Set::empty()
404 },
405 );
406 assert(mapped[i].contains(m));
407 mapped.to_set_ensures();
408 assert(mapped.to_set().contains(mapped[i]));
409 mapped.to_set().lemma_flatten_contains(m);
410 }
411
412 pub open spec fn as_subtree(self) -> OwnerSubtree<C> {
413 OwnerSubtree { value: self.entry_own, level: self.tree_level, children: self.children }
414 }
415
416 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
417 PageTableOwner(self.as_subtree())
418 }
419
420 pub open spec fn view_mappings_take_child_spec(self) -> Set<Mapping> {
421 PageTableOwner(self.children[self.idx as int]->0).view_rec(
422 self.path().push_tail(self.idx as usize),
423 )
424 }
425
426 pub proof fn rel_children_from_node_matching(
438 entry: &Entry<'_, 'rcu, C>,
439 child_value: EntryOwner<C>,
440 parent_owner: NodeOwner<C>,
441 guard: PageTableGuard<'rcu, C>,
442 entry_own: EntryOwner<C>,
443 idx: usize,
444 )
445 requires
446 entry.node_matching(child_value, parent_owner, guard),
447 entry.idx == idx,
448 entry_own.is_node(),
449 entry_own.node() == parent_owner,
450 child_value.path == entry_own.path.push_tail(idx),
451 child_value.path.len() == parent_owner.tree_level + 1,
452 ensures
453 child_value.path.len() == parent_owner.tree_level + 1,
454 child_value.match_pte(
455 parent_owner.children_perm.value()[idx as int],
456 parent_owner.level,
457 ),
458 child_value.path == entry_own.path.push_tail(idx),
459 child_value.parent_level == parent_owner.level,
460 {
461 }
462
463 pub proof fn continuation_inv_holds_after_child_restore(
473 self,
474 cont_old: Self,
475 parent_old: NodeOwner<C>,
476 )
477 requires
478 cont_old.inv(),
481 cont_old.entry_own.is_node(),
482 cont_old.entry_own.node() == parent_old,
483 self.children.len() == cont_old.children.len(),
485 self.idx == cont_old.idx,
486 self.tree_level == cont_old.tree_level,
487 self.guard == cont_old.guard,
488 self.path == cont_old.path,
489 self.entry_own.is_absent() == cont_old.entry_own.is_absent(),
492 self.entry_own.path == cont_old.entry_own.path,
493 self.entry_own.parent_level == cont_old.entry_own.parent_level,
494 self.entry_own.is_node(),
496 self.entry_own.inv(),
497 self.entry_own.node().relate_guard(self.guard),
498 self.entry_own.node().level == parent_old.level,
499 self.entry_own.node().tree_level == parent_old.tree_level,
500 forall|j: int|
502 0 <= j < NR_ENTRIES && j != self.idx as int
503 ==> #[trigger] self.entry_own.node().children_perm.value()[j]
504 == parent_old.children_perm.value()[j],
505 forall|j: int|
507 0 <= j < NR_ENTRIES && j != self.idx as int ==> #[trigger] self.children[j]
508 == cont_old.children[j],
509 self.children.len() == NR_ENTRIES,
512 0 <= self.idx < NR_ENTRIES,
513 self.tree_level == INC_LEVELS - self.level() - 1,
514 self.tree_level < INC_LEVELS - 1,
515 self.path().len() == self.tree_level,
516 self.children[self.idx as int] is Some,
518 self.children[self.idx as int]->0.inv(),
519 self.children[self.idx as int]->0.value.parent_level == self.level(),
520 self.children[self.idx as int]->0.value.path == self.path().push_tail(
521 self.idx as usize,
522 ),
523 self.children[self.idx as int]->0.level == self.tree_level + 1,
524 self.children[self.idx as int]->0.value.path.len() == self.entry_own.node().tree_level
525 + 1,
526 self.children[self.idx as int]->0.value.match_pte(
527 self.entry_own.node().children_perm.value()[self.idx as int],
528 self.entry_own.node().level,
529 ),
530 PageTableOwner(self.children[self.idx as int]->0).pt_inv(),
535 ensures
536 self.inv(),
537 {
538 let cont_idx = self.idx as int;
539 let new_parent = self.entry_own.node();
540 let new_child = self.children[cont_idx].unwrap();
541
542 assert(self.inv_children()) by {
544 let pred = |child: Option<OwnerSubtree<C>>| child is Some ==> child.unwrap().inv();
545 assert forall|i: int| 0 <= i < self.children.len() implies #[trigger] pred(
546 self.children[i],
547 ) by {
548 if i != cont_idx {
549 if self.children[i] is Some {
550 assert(self.children[i] == cont_old.children[i]);
551 cont_old.inv_children_unroll(i);
552 }
553 }
554 };
555 assert(self.children.all(pred));
556 };
557
558 assert(self.inv_children_rel()) by {
561 let pred = self.inv_children_rel_pred();
562 assert forall|i: int| 0 <= i < self.children.len() implies #[trigger] pred(
563 i,
564 self.children[i],
565 ) by {
566 if i != cont_idx {
567 if self.children[i] is Some {
568 cont_old.inv_children_rel_unroll(i);
569 assert(self.children[i] == cont_old.children[i]);
570 }
571 }
572 };
573 };
574
575 assert(self.pt_inv_children()) by {
580 let pred = Self::pt_inv_children_pred();
581 assert forall|i: int| 0 <= i < self.children.len() implies #[trigger] pred(
582 i,
583 self.children[i],
584 ) by {
585 if i == cont_idx {
586 assert(PageTableOwner(self.children[cont_idx].unwrap()).pt_inv());
587 } else {
588 if self.children[i] is Some {
589 cont_old.pt_inv_children_unroll(i);
590 assert(self.children[i] == cont_old.children[i]);
591 }
592 }
593 };
594 };
595 }
596
597 pub proof fn new_child(
598 tracked &self,
599 paddr: Paddr,
600 prop: PageProperty,
601 is_tracked: bool,
602 tracked regions: &mut MetaRegionOwners,
603 ) -> (tracked res: OwnerSubtree<C>)
604 requires
605 self.inv(),
606 self.level() < NR_LEVELS,
607 old(regions).slots.contains_key(frame_to_index(paddr)),
608 paddr % PAGE_SIZE == 0,
609 paddr < MAX_PADDR,
610 paddr % page_size(self.level()) == 0,
611 paddr + page_size(self.level()) <= MAX_PADDR,
612 self.path().push_tail(self.idx as usize).inv(),
613 ensures
614 final(regions).slot_owners == old(regions).slot_owners,
615 final(regions).slots == old(regions).slots,
616 res.value == EntryOwner::<C>::new_frame(
618 paddr,
619 self.path().push_tail(self.idx as usize),
620 self.level(),
621 prop,
622 is_tracked,
623 ),
624 res.inv(),
625 res.level == self.tree_level + 1,
626 res == OwnerSubtree::new_val(res.value, res.level as nat),
627 {
628 let tracked mut owner = EntryOwner::<C>::tracked_new_frame(
629 paddr,
630 self.path().push_tail(self.idx as usize),
631 self.level(),
632 prop,
633 is_tracked,
634 );
635 OwnerSubtree::new_val_tracked(owner, self.tree_level + 1)
636 }
637
638 pub broadcast group group_lemmas {
639 CursorContinuation::lemma_view_mappings_contains,
640 CursorContinuation::lemma_view_mappings_intro,
641 }
642}
643
644pub tracked struct CursorOwner<'rcu, C: PageTableConfig> {
645 pub level: PagingLevel,
646 pub continuations: Map<int, CursorContinuation<'rcu, C>>,
647 pub va: AbstractVaddr,
648 pub guard_level: PagingLevel,
649 pub prefix: AbstractVaddr,
650 pub popped_too_high: bool,
651}
652
653impl<'rcu, C: PageTableConfig> Inv for CursorOwner<'rcu, C> {
654 open spec fn inv(self) -> bool {
655 &&& self.va.inv()
656 &&& self.va.offset == 0
657 &&& 1 <= self.level <= NR_LEVELS
658 &&& 1 <= self.guard_level
659 <= NR_LEVELS
660 &&& C::TOP_LEVEL_INDEX_RANGE_spec().start <= self.va.index[NR_LEVELS
664 - 1]
665 &&& self.va.index[NR_LEVELS - 1]
669 <= C::TOP_LEVEL_INDEX_RANGE_spec().end
670 &&& self.in_locked_range()
672 || self.above_locked_range()
673 &&& self.popped_too_high ==> self.level >= self.guard_level
676 &&& !self.popped_too_high ==> self.level <= self.guard_level || self.above_locked_range()
677 &&& self.continuations[self.level - 1].all_some()
678 &&& forall|i: int|
679 self.level <= i < NR_LEVELS ==> {
680 (#[trigger] self.continuations[i]).all_but_index_some()
681 }
682 &&& self.level <= NR_LEVELS - 1 ==> {
691 &&& C::TOP_LEVEL_INDEX_RANGE_spec().start <= self.continuations[NR_LEVELS - 1].idx
692 &&& self.continuations[NR_LEVELS - 1].idx < C::TOP_LEVEL_INDEX_RANGE_spec().end
693 }
694 &&& forall|j: int|
695 #![trigger self.continuations[NR_LEVELS - 1].children[j]]
696 0 <= j < NR_ENTRIES && !(C::TOP_LEVEL_INDEX_RANGE_spec().start <= j
697 < C::TOP_LEVEL_INDEX_RANGE_spec().end) ==> self.continuations[NR_LEVELS
698 - 1].children[j] is Some ==> (self.continuations[NR_LEVELS
699 - 1].children[j].unwrap().value.is_borrowed() || self.continuations[NR_LEVELS
700 - 1].children[j].unwrap().value.is_absent())
701 &&& self.prefix.inv()
702 &&& self.prefix.offset == 0
703 &&& forall|i: int|
704 i < self.guard_level ==> self.prefix.index[i]
705 == 0
706 &&& self.prefix.index[NR_LEVELS - 1]
710 < C::TOP_LEVEL_INDEX_RANGE_spec().end
711 &&& self.prefix.index[NR_LEVELS - 1] + 1
714 < NR_ENTRIES
715 &&& self.locked_range().end <= crate::mm::page_table::vaddr_range_bounds_spec::<C>().1
719 + 1
720 &&& self.locked_range().end
725 <= C::LOCKED_END_BOUND_spec()
726 &&& self.va.leading_bits
729 == self.prefix.leading_bits
730 &&& self.prefix.leading_bits
733 == C::LEADING_BITS_spec()
734 &&& !self.popped_too_high && (self.in_locked_range() || self.level < self.guard_level)
742 ==> forall|i: int|
743 self.guard_level <= i < NR_LEVELS ==> self.va.index[i] == self.prefix.index[i]
744 &&& !self.popped_too_high && self.guard_level >= 1 && self.level < self.guard_level
745 ==> self.va.index[self.guard_level - 1] == self.prefix.index[self.guard_level - 1]
746 &&& self.level <= 4 ==> {
747 &&& self.continuations.contains_key(3)
748 &&& self.continuations[3].inv()
749 &&& self.continuations[3].level()
750 == 4
751 &&& self.continuations[3].entry_own.parent_level
753 == 5
754 &&& self.in_locked_range() ==> self.va.index[3] == self.continuations[3].idx
759 }
760 &&& self.level <= 3 ==> {
761 &&& self.continuations.contains_key(2)
762 &&& self.continuations[2].inv()
763 &&& self.continuations[2].level() == 3
764 &&& self.continuations[2].entry_own.parent_level == 4
765 &&& self.in_locked_range() ==> self.va.index[2] == self.continuations[2].idx
766 &&& self.continuations[2].guard.inner.inner@.ptr.addr()
767 != self.continuations[3].guard.inner.inner@.ptr.addr()
768 &&& self.continuations[2].path() == self.continuations[3].path().push_tail(
770 self.continuations[3].idx as usize,
771 )
772 &&& self.continuations[2].entry_own.path.len()
774 == self.continuations[3].entry_own.node().tree_level + 1
775 &&& self.continuations[2].entry_own.match_pte(
776 self.continuations[3].entry_own.node().children_perm.value()[self.continuations[3].idx as int],
777 self.continuations[3].entry_own.node().level,
778 )
779 &&& self.continuations[2].entry_own.parent_level
780 == self.continuations[3].entry_own.node().level
781 }
782 &&& self.level <= 2 ==> {
783 &&& self.continuations.contains_key(1)
784 &&& self.continuations[1].inv()
785 &&& self.continuations[1].level() == 2
786 &&& self.continuations[1].entry_own.parent_level == 3
787 &&& self.in_locked_range() ==> self.va.index[1] == self.continuations[1].idx
788 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
789 != self.continuations[2].guard.inner.inner@.ptr.addr()
790 &&& self.continuations[1].guard.inner.inner@.ptr.addr()
791 != self.continuations[3].guard.inner.inner@.ptr.addr()
792 &&& self.continuations[1].path() == self.continuations[2].path().push_tail(
794 self.continuations[2].idx as usize,
795 )
796 &&& self.continuations[1].entry_own.path.len()
798 == self.continuations[2].entry_own.node().tree_level + 1
799 &&& self.continuations[1].entry_own.match_pte(
800 self.continuations[2].entry_own.node().children_perm.value()[self.continuations[2].idx as int],
801 self.continuations[2].entry_own.node().level,
802 )
803 &&& self.continuations[1].entry_own.parent_level
804 == self.continuations[2].entry_own.node().level
805 }
806 &&& self.level == 1 ==> {
807 &&& self.continuations.contains_key(0)
808 &&& self.continuations[0].inv()
809 &&& self.continuations[0].level() == 1
810 &&& self.continuations[0].entry_own.parent_level == 2
811 &&& self.in_locked_range() ==> self.va.index[0] == self.continuations[0].idx
812 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
813 != self.continuations[1].guard.inner.inner@.ptr.addr()
814 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
815 != self.continuations[2].guard.inner.inner@.ptr.addr()
816 &&& self.continuations[0].guard.inner.inner@.ptr.addr()
817 != self.continuations[3].guard.inner.inner@.ptr.addr()
818 &&& self.continuations[0].path() == self.continuations[1].path().push_tail(
820 self.continuations[1].idx as usize,
821 )
822 &&& self.continuations[0].entry_own.path.len()
824 == self.continuations[1].entry_own.node().tree_level + 1
825 &&& self.continuations[0].entry_own.match_pte(
826 self.continuations[1].entry_own.node().children_perm.value()[self.continuations[1].idx as int],
827 self.continuations[1].entry_own.node().level,
828 )
829 &&& self.continuations[0].entry_own.parent_level
830 == self.continuations[1].entry_own.node().level
831 }
832 }
833}
834
835impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
836 pub open spec fn node_unlocked(guards: Guards<'rcu>) -> (spec_fn(
837 EntryOwner<C>,
838 TreePath<NR_ENTRIES>,
839 ) -> bool) {
840 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
841 owner.is_node() ==> guards.unlocked(owner.node().meta_addr_self())
842 }
843
844 pub open spec fn node_unlocked_except(guards: Guards<'rcu>, addr: usize) -> (spec_fn(
845 EntryOwner<C>,
846 TreePath<NR_ENTRIES>,
847 ) -> bool) {
848 |owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
849 owner.is_node() ==> owner.node().meta_addr_self() != addr ==> guards.unlocked(
850 owner.node().meta_addr_self(),
851 )
852 }
853
854 pub open spec fn map_full_tree(
855 self,
856 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
857 ) -> bool {
858 forall|i: int|
859 #![trigger self.continuations[i]]
860 self.level - 1 <= i < NR_LEVELS ==> { self.continuations[i].map_children(f) }
861 }
862
863 pub open spec fn map_only_children(
864 self,
865 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
866 ) -> bool {
867 forall|i: int|
868 #![trigger self.continuations[i]]
869 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(f)
870 }
871
872 pub open spec fn children_not_locked(self, guards: Guards<'rcu>) -> bool {
873 self.map_only_children(Self::node_unlocked(guards))
874 }
875
876 pub open spec fn only_current_locked(self, guards: Guards<'rcu>) -> bool {
877 self.map_only_children(
878 Self::node_unlocked_except(guards, self.cur_entry_owner().node().meta_addr_self()),
879 )
880 }
881
882 pub proof fn never_drop_restores_children_not_locked(
883 self,
884 guard: PageTableGuard<'rcu, C>,
885 guards0: Guards<'rcu>,
886 guards1: Guards<'rcu>,
887 obl_key: usize,
888 )
889 requires
890 self.inv(),
891 self.only_current_locked(guards0),
892 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_requires(guard, guards0),
893 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_ensures(
894 guard,
895 guards0,
896 guards1,
897 obl_key,
898 ),
899 self.cur_entry_owner().is_node(),
901 guard.inner.inner@.ptr.addr() == self.cur_entry_owner().node().meta_addr_self(),
902 ensures
903 self.children_not_locked(guards1),
904 {
905 let current_addr = self.cur_entry_owner().node().meta_addr_self();
906 let f = Self::node_unlocked_except(guards0, current_addr);
907 let g = Self::node_unlocked(guards1);
908 assert(OwnerSubtree::implies(f, g));
909 self.map_children_implies(f, g);
910 }
911
912 pub axiom fn never_drop_restores_nodes_locked(
916 self,
917 guard: PageTableGuard<'rcu, C>,
918 guards0: Guards<'rcu>,
919 guards1: Guards<'rcu>,
920 obl_key: usize,
921 )
922 requires
923 self.inv(),
924 self.nodes_locked(guards0),
925 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_requires(guard, guards0),
926 <PageTableGuard<'rcu, C> as TrackDrop>::constructor_ensures(
927 guard,
928 guards0,
929 guards1,
930 obl_key,
931 ),
932 forall|i: int|
933 #![trigger self.continuations[i]]
934 self.level - 1 <= i < NR_LEVELS
935 ==> self.continuations[i].guard.inner.inner@.ptr.addr()
936 != guard.inner.inner@.ptr.addr(),
937 ensures
938 self.nodes_locked(guards1),
939 ;
940
941 pub open spec fn nodes_locked(self, guards: Guards<'rcu>) -> bool {
955 forall|i: int|
961 #![trigger self.continuations[i]]
962 self.level - 1 <= i < self.guard_level ==> { self.continuations[i].node_locked(guards) }
963 }
964
965 pub open spec fn index(self) -> usize {
966 self.continuations[self.level - 1].idx
967 }
968
969 pub open spec fn inc_index(self) -> Self {
970 Self {
971 continuations: self.continuations.insert(
972 self.level - 1,
973 self.continuations[self.level - 1].inc_index(),
974 ),
975 va: AbstractVaddr {
976 index: self.va.index.insert(
977 self.level - 1,
978 self.continuations[self.level - 1].inc_index().idx as int,
979 ),
980 ..self.va
981 },
982 popped_too_high: false,
983 ..self
984 }
985 }
986
987 #[verifier::spinoff_prover]
988 pub proof fn do_inc_index(tracked &mut self)
989 requires
990 old(self).inv(),
991 old(self).level <= old(self).guard_level,
992 old(self).in_locked_range(),
993 old(self).continuations[old(self).level - 1].idx + 1 < NR_ENTRIES,
994 old(self).level == NR_LEVELS ==> (old(self).continuations[old(self).level - 1].idx + 1)
995 <= C::TOP_LEVEL_INDEX_RANGE_spec().end,
996 ensures
997 final(self).inv(),
998 *final(self) == old(self).inc_index(),
999 {
1000 reveal(CursorContinuation::inv_children);
1001 self.popped_too_high = false;
1002 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
1003 cont.do_inc_index();
1004 self.va.index.tracked_insert(self.level - 1, cont.idx as int);
1005 self.continuations.tracked_insert(self.level - 1, cont);
1006 assert(self.continuations == old(self).continuations.insert(self.level - 1, cont));
1007 assert(self.va.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
1008
1009 old(self).va.index_increment_adds_page_size(old(self).level as int);
1010 lemma_page_size_ge_page_size(old(self).level as PagingLevel);
1011
1012 if self.level >= self.guard_level {
1013 if !old(self).above_locked_range() {
1014 Self::inc_at_guard_level_above_locked_range(
1015 old(self).va,
1016 old(self).prefix,
1017 old(self).guard_level,
1018 old(self).level,
1019 self.va.to_vaddr(),
1020 );
1021 }
1022 }
1023 if old(self).popped_too_high {
1024 old(self).in_locked_range_prefix_match();
1025 }
1026 assert(self.va.inv());
1027 }
1028
1029 pub proof fn inv_continuation(self, i: int)
1030 requires
1031 self.inv(),
1032 self.level - 1 <= i <= NR_LEVELS - 1,
1033 ensures
1034 self.continuations.contains_key(i),
1035 self.continuations[i].inv(),
1036 self.continuations[i].children.len() == NR_ENTRIES,
1037 {
1038 assert(self.continuations.contains_key(i));
1039 }
1040
1041 pub open spec fn view_mappings(self) -> Set<Mapping> {
1042 self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS).map_values(
1043 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
1044 ).values().flatten()
1045 }
1046
1047 pub broadcast proof fn lemma_view_mappings_contains(self)
1048 requires
1049 1 <= self.level <= NR_LEVELS,
1050 ensures
1051 #![trigger self.view_mappings()]
1052 forall|m: Mapping| #[trigger]
1053 self.view_mappings().contains(m) ==> exists|i: int|
1054 #![trigger self.continuations[i]]
1055 self.level - 1 <= i < NR_LEVELS
1056 && self.continuations[i].view_mappings().contains(m),
1057 {
1058 broadcast use vstd::map_lib::group_map_properties;
1059
1060 assert forall|m: Mapping| #[trigger] self.view_mappings().contains(m) implies exists|i: int|
1061
1062 #![trigger self.continuations[i]]
1063 self.level - 1 <= i < NR_LEVELS && self.continuations[i].view_mappings().contains(
1064 m,
1065 ) by {
1066 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
1067 let mapped = filtered.map_values(
1068 |cont: CursorContinuation<'rcu, C>| cont.view_mappings(),
1069 );
1070 let values = mapped.values();
1071 values.lemma_flatten_contains(m);
1072 let elem_s = choose|elem_s: Set<Mapping>| #[trigger]
1073 values.contains(elem_s) && elem_s.contains(m);
1074 assert(exists|i: int| #[trigger] mapped.dom().contains(i) && mapped[i] == elem_s);
1075 let i = choose|i: int| #[trigger] mapped.dom().contains(i) && mapped[i] == elem_s;
1076 assert(filtered.dom().contains(i));
1077 assert(self.level - 1 <= i < NR_LEVELS);
1078 assert(filtered[i] == self.continuations[i]);
1079 assert(mapped[i] == self.continuations[i].view_mappings());
1080 }
1081 }
1082
1083 pub broadcast proof fn lemma_view_mappings_intro(self, m: Mapping, i: int)
1084 requires
1085 1 <= self.level <= NR_LEVELS,
1086 self.level - 1 <= i < NR_LEVELS,
1087 self.continuations.contains_key(i),
1088 #[trigger] self.continuations[i].view_mappings().contains(m),
1089 ensures
1090 self.view_mappings().contains(m),
1091 {
1092 broadcast use vstd::map_lib::group_map_properties;
1093
1094 let filtered = self.continuations.filter_keys(|k| self.level - 1 <= k < NR_LEVELS);
1095 let mapped = filtered.map_values(|cont: CursorContinuation<'rcu, C>| cont.view_mappings());
1096 let values = mapped.values();
1097 assert(filtered.dom().contains(i));
1098 assert(filtered[i] == self.continuations[i]);
1099 assert(mapped.dom().contains(i));
1100 assert(mapped[i] == self.continuations[i].view_mappings());
1101 assert(values.contains(mapped[i]));
1102 values.lemma_flatten_contains(m);
1103 }
1104
1105 pub open spec fn as_page_table_owner(self) -> PageTableOwner<C> {
1106 if self.level == 1 {
1107 let l1 = self.continuations[0];
1108 let l2 = self.continuations[1].restore(l1).0;
1109 let l3 = self.continuations[2].restore(l2).0;
1110 let l4 = self.continuations[3].restore(l3).0;
1111 l4.as_page_table_owner()
1112 } else if self.level == 2 {
1113 let l2 = self.continuations[1];
1114 let l3 = self.continuations[2].restore(l2).0;
1115 let l4 = self.continuations[3].restore(l3).0;
1116 l4.as_page_table_owner()
1117 } else if self.level == 3 {
1118 let l3 = self.continuations[2];
1119 let l4 = self.continuations[3].restore(l3).0;
1120 l4.as_page_table_owner()
1121 } else {
1122 let l4 = self.continuations[3];
1123 l4.as_page_table_owner()
1124 }
1125 }
1126
1127 pub open spec fn cur_entry_owner(self) -> EntryOwner<C> {
1128 self.cur_subtree().value
1129 }
1130
1131 pub open spec fn cur_subtree(self) -> OwnerSubtree<C> {
1132 self.continuations[self.level - 1].children[self.index() as int]->0
1133 }
1134
1135 pub proof fn cur_frame_clone_requires(
1150 self,
1151 item: C::Item,
1152 pa: Paddr,
1153 level: PagingLevel,
1154 prop: PageProperty,
1155 regions: MetaRegionOwners,
1156 )
1157 requires
1158 self.inv(),
1159 regions.inv(),
1160 self.metaregion_sound(regions),
1161 self.cur_entry_owner().is_frame(),
1162 pa == self.cur_entry_owner().frame().mapped_pa,
1163 C::item_from_raw_spec(pa, level, prop) == item,
1164 has_safe_slot(pa),
1165 C::tracked(item) == self.cur_entry_owner().frame().is_tracked,
1167 C::tracked(item) ==> (regions.slot_owners[frame_to_index(
1169 pa,
1170 )].inner_perms.ref_count.value() < REF_COUNT_MAX || may_panic()),
1171 ensures
1172 item.clone_requires(regions),
1173 {
1174 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1175 assert(self.path_metaregion_sound(regions));
1178 assert(self.cur_entry_owner().metaregion_sound(regions));
1179 let entry = self.cur_entry_owner();
1180 let idx = frame_to_index(pa);
1181 EntryOwner::<C>::axiom_frame_is_tracked_iff_not_mmio(entry);
1185 assert(regions.slot_owners[idx].slot_vaddr == crate::specs::mm::frame::mapping::meta_addr(
1186 idx,
1187 ));
1188 if C::tracked(item) {
1189 assert(!crate::specs::mm::frame::meta_owners::is_mmio_paddr(pa));
1190 assert(regions.slot_owners[idx].usage !is MMIO);
1191 assert(regions.slot_owners[idx].inner_perms.ref_count.value() > 0);
1192 assert(regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
1193 }
1194 C::clone_requires_concrete(item, pa, level, prop, regions);
1197 }
1198
1199 pub proof fn clone_item_preserves_invariants(
1202 self,
1203 old_regions: MetaRegionOwners,
1204 new_regions: MetaRegionOwners,
1205 idx: usize,
1206 )
1207 requires
1208 self.inv(),
1209 self.metaregion_sound(old_regions),
1210 old_regions.inv(),
1211 self.cur_entry_owner().is_frame(),
1212 idx == frame_to_index(self.cur_entry_owner().frame().mapped_pa),
1213 old_regions.slot_owners.contains_key(idx),
1214 new_regions.slot_owners.contains_key(idx),
1215 new_regions.slot_owners[idx].inner_perms.ref_count.value()
1217 == old_regions.slot_owners[idx].inner_perms.ref_count.value() + 1,
1218 new_regions.slot_owners[idx].inner_perms.ref_count.id()
1220 == old_regions.slot_owners[idx].inner_perms.ref_count.id(),
1221 new_regions.slot_owners[idx].inner_perms.storage
1222 == old_regions.slot_owners[idx].inner_perms.storage,
1223 new_regions.slot_owners[idx].inner_perms.vtable_ptr
1224 == old_regions.slot_owners[idx].inner_perms.vtable_ptr,
1225 new_regions.slot_owners[idx].inner_perms.in_list
1226 == old_regions.slot_owners[idx].inner_perms.in_list,
1227 new_regions.slot_owners[idx].paths_in_pt == old_regions.slot_owners[idx].paths_in_pt,
1229 new_regions.slot_owners[idx].slot_vaddr == old_regions.slot_owners[idx].slot_vaddr,
1230 new_regions.slot_owners[idx].usage == old_regions.slot_owners[idx].usage,
1231 new_regions.slot_owners.dom() == old_regions.slot_owners.dom(),
1233 forall|i: usize|
1234 #![trigger new_regions.slot_owners[i]]
1235 i != idx && old_regions.slot_owners.contains_key(i) ==> new_regions.slot_owners[i]
1236 == old_regions.slot_owners[i],
1237 new_regions.slots == old_regions.slots,
1239 0 < old_regions.slot_owners[idx].inner_perms.ref_count.value(),
1245 old_regions.slot_owners[idx].inner_perms.ref_count.value() + 1 <= REF_COUNT_MAX,
1246 ensures
1247 new_regions.inv(),
1248 self.metaregion_sound(new_regions),
1249 {
1250 self.cont_entries_metaregion(old_regions);
1251 assert(new_regions.slot_owners[idx].inv());
1252 assert(new_regions.inv()) by {
1253 assert forall|i: usize| #[trigger] new_regions.slots.contains_key(i) implies {
1254 &&& new_regions.slot_owners.contains_key(i)
1255 &&& new_regions.slot_owners[i].inv()
1256 &&& new_regions.slots[i].is_init()
1257 &&& new_regions.slots[i].value().wf(new_regions.slot_owners[i])
1258 &&& new_regions.slot_owners[i].slot_vaddr == new_regions.slots[i].addr()
1259 } by {
1260 assert(old_regions.slots.contains_key(i));
1261 };
1262 assert forall|i: usize| #[trigger]
1263 new_regions.slot_owners.contains_key(
1264 i,
1265 ) implies new_regions.slot_owners[i].inv() by {};
1266 };
1267 self.metaregion_slot_owners_rc_increment(old_regions, new_regions, idx);
1268 }
1269
1270 pub proof fn new_child_mappings_eq_target(
1273 self,
1274 new_subtree: OwnerSubtree<C>,
1275 pa: Paddr,
1276 level: PagingLevel,
1277 prop: PageProperty,
1278 )
1279 requires
1280 self.inv(),
1281 self.in_locked_range(),
1282 level == self.level,
1283 new_subtree.inv(),
1284 new_subtree.value.is_frame(),
1285 new_subtree.value.path == self.continuations[self.level - 1].path().push_tail(
1286 self.continuations[self.level - 1].idx as usize,
1287 ),
1288 new_subtree.value.frame().mapped_pa == pa,
1289 new_subtree.value.frame().prop == prop,
1290 ensures
1291 PageTableOwner(new_subtree)@.mappings
1292 == set![Mapping {
1293 va_range: self@.cur_slot_range(page_size(level)),
1294 pa_range: pa..(pa + page_size(level)) as usize,
1295 page_size: page_size(level),
1296 property: prop,
1297 }],
1298 {
1299 let path = new_subtree.value.path;
1300 let ps = page_size(level);
1301 let cont = self.continuations[self.level - 1];
1302
1303 cont.path().push_tail_property_len(cont.idx as usize);
1304
1305 self.cur_va_in_subtree_range();
1310 assert(vaddr_of::<C>(path) == nat_align_down(self@.cur_va as nat, ps as nat) as Vaddr) by {
1311 self.va.to_path_vaddr_concrete(self.level - 1);
1312 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
1313 let va_path = self.va.to_path(self.level - 1);
1314 self.va.to_path_len(self.level - 1);
1315 self.va.to_path_inv(self.level - 1);
1316 self.cur_subtree_inv();
1317 assert forall|i: int| 0 <= i < path.len() implies path.index(i) == va_path.index(i) by {
1318 self.va.to_path_index(self.level - 1, i);
1319 if self.level == 4 {
1320 cont.path().push_tail_property_index(cont.idx as usize);
1321 } else if self.level == 3 {
1322 cont.path().push_tail_property_index(cont.idx as usize);
1323 self.continuations[3].path().push_tail_property_index(
1324 self.continuations[3].idx as usize,
1325 );
1326 } else if self.level == 2 {
1327 cont.path().push_tail_property_index(cont.idx as usize);
1328 self.continuations[2].path().push_tail_property_index(
1329 self.continuations[2].idx as usize,
1330 );
1331 self.continuations[3].path().push_tail_property_index(
1332 self.continuations[3].idx as usize,
1333 );
1334 } else {
1335 cont.path().push_tail_property_index(cont.idx as usize);
1336 self.continuations[1].path().push_tail_property_index(
1337 self.continuations[1].idx as usize,
1338 );
1339 self.continuations[2].path().push_tail_property_index(
1340 self.continuations[2].idx as usize,
1341 );
1342 self.continuations[3].path().push_tail_property_index(
1343 self.continuations[3].idx as usize,
1344 );
1345 }
1346 };
1347 AbstractVaddr::rec_vaddr_eq_if_indices_eq(path, va_path, 0);
1348 };
1349 let target = Mapping {
1354 va_range: self@.cur_slot_range(page_size(level)),
1355 pa_range: pa..(pa + page_size(level)) as usize,
1356 page_size: page_size(level),
1357 property: prop,
1358 };
1359 let from_view = Mapping {
1360 va_range: Range { start: vaddr_of::<C>(path) as int, end: vaddr_of::<C>(path) + ps },
1361 pa_range: pa..(pa + ps) as usize,
1362 page_size: ps,
1363 property: prop,
1364 };
1365 let nad = nat_align_down(self@.cur_va as nat, ps as nat);
1368 assert(nad <= self@.cur_va as nat) by {
1369 vstd_extra::arithmetic::lemma_nat_align_down_sound(self@.cur_va as nat, ps as nat);
1370 };
1371 assert(target.va_range.start == nad);
1372 assert(target == from_view);
1373 assert(PageTableOwner(new_subtree).view_rec(path) == set![from_view]);
1374 assert(PageTableOwner(new_subtree)@.mappings == set![target]);
1375 }
1376
1377 pub open spec fn locked_range(self) -> Range<Vaddr> {
1378 let start = self.prefix.align_down(self.guard_level as int).to_vaddr();
1379 let end = self.prefix.align_up(self.guard_level as int).to_vaddr();
1380 Range { start, end }
1381 }
1382
1383 pub open spec fn in_locked_range(self) -> bool {
1384 self.locked_range().start <= self.va.to_vaddr() < self.locked_range().end
1385 }
1386
1387 pub open spec fn above_locked_range(self) -> bool {
1388 self.va.to_vaddr() >= self.locked_range().end
1389 }
1390
1391 pub proof fn inc_at_guard_level_above_locked_range(
1393 old_va: AbstractVaddr,
1394 prefix: AbstractVaddr,
1395 guard_level: u8,
1396 level: u8,
1397 new_va_val: Vaddr,
1398 )
1399 requires
1400 old_va.inv(),
1401 prefix.inv(),
1402 1 <= guard_level <= NR_LEVELS,
1403 level == guard_level,
1404 new_va_val == old_va.to_vaddr() + page_size(level as PagingLevel),
1405 prefix.align_down(guard_level as int).to_vaddr() <= old_va.to_vaddr(),
1406 old_va.to_vaddr() < prefix.align_up(guard_level as int).to_vaddr(),
1407 prefix.align_down(guard_level as int).to_vaddr() + page_size(guard_level as PagingLevel)
1409 <= usize::MAX,
1410 ensures
1411 new_va_val >= prefix.align_up(guard_level as int).to_vaddr(),
1412 {
1413 let ps_gl = page_size(guard_level as PagingLevel);
1414 lemma_page_size_ge_page_size(guard_level as PagingLevel);
1415 let aligned = prefix.align_down(guard_level as int);
1416 prefix.align_down_concrete(guard_level as int);
1417 prefix.align_down_shape(guard_level as int);
1418
1419 assert(aligned.to_vaddr() as nat % ps_gl as nat == 0) by {
1425 vstd_extra::arithmetic::lemma_nat_align_down_sound(
1426 prefix.to_vaddr() as nat,
1427 ps_gl as nat,
1428 );
1429 prefix.to_vaddr_bounded();
1430 aligned.to_vaddr_bounded();
1431 aligned.reflect_prop(nat_align_down(prefix.to_vaddr() as nat, ps_gl as nat) as Vaddr);
1432 };
1433 aligned.aligned_align_up_advances(guard_level as int);
1435 aligned.aligned_align_down_is_self(guard_level as int);
1440 }
1441
1442 pub proof fn prefix_in_locked_range(self)
1443 requires
1444 self.inv(),
1445 !self.popped_too_high,
1446 self.level < self.guard_level,
1447 ensures
1448 self.in_locked_range(),
1449 {
1450 let gl = self.guard_level;
1451 if gl >= 1 && gl <= NR_LEVELS {
1452 self.va.align_down_to_vaddr_eq_if_upper_indices_eq(self.prefix, gl as int);
1456 self.va.align_down_concrete(gl as int);
1457 self.prefix.align_down_concrete(gl as int);
1458 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1459 nat_align_down(
1460 self.va.to_vaddr() as nat,
1461 page_size(gl as PagingLevel) as nat,
1462 ) as Vaddr,
1463 );
1464 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1465 nat_align_down(
1466 self.prefix.to_vaddr() as nat,
1467 page_size(gl as PagingLevel) as nat,
1468 ) as Vaddr,
1469 );
1470 lemma_page_size_ge_page_size(gl as PagingLevel);
1471 lemma_nat_align_down_sound(
1472 self.va.to_vaddr() as nat,
1473 page_size(gl as PagingLevel) as nat,
1474 );
1475
1476 let ps = page_size(gl as PagingLevel) as nat;
1477 let prefix_val = self.prefix.to_vaddr() as nat;
1478
1479 self.prefix.align_down_shape(gl as int);
1480 self.prefix.align_down(gl as int).reflect_prop(nat_align_down(prefix_val, ps) as Vaddr);
1481 self.prefix_aligned_to_guard_level();
1483 self.prefix_plus_ps_no_overflow();
1484 self.prefix.aligned_align_up_advances(gl as int);
1485 }
1486 }
1487
1488 pub proof fn in_locked_range_prefix_match(self)
1491 requires
1492 self.inv(),
1493 self.prefix.inv(),
1494 1 <= self.guard_level <= NR_LEVELS,
1495 self.in_locked_range(),
1496 ensures
1497 forall|i: int|
1498 self.guard_level <= i < NR_LEVELS ==> self.va.index[i] == self.prefix.index[i],
1499 {
1500 let gl = self.guard_level;
1501 let start = self.prefix.align_down(gl as int).to_vaddr();
1502
1503 self.prefix.align_down_shape(gl as int);
1505 let prefix_ad = self.prefix.align_down(gl as int);
1506
1507 self.prefix.align_down_concrete(gl as int);
1509 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1510 nat_align_down(
1511 self.prefix.to_vaddr() as nat,
1512 page_size(gl as PagingLevel) as nat,
1513 ) as Vaddr,
1514 );
1515 lemma_page_size_ge_page_size(gl as PagingLevel);
1516 lemma_nat_align_down_sound(
1517 self.prefix.to_vaddr() as nat,
1518 page_size(gl as PagingLevel) as nat,
1519 );
1520
1521 self.prefix_aligned_to_guard_level();
1523 self.prefix_plus_ps_no_overflow();
1524 self.prefix.aligned_align_up_advances(gl as int);
1525
1526 if gl >= 2 && gl < NR_LEVELS {
1527 AbstractVaddr::same_node_indices_match(
1530 self.va.to_vaddr(),
1531 self.prefix.to_vaddr(),
1532 start,
1533 (gl - 1) as PagingLevel,
1534 );
1535 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1537 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1538 } else if gl == 1 {
1539 let ps1 = page_size(1 as PagingLevel) as nat;
1543 let ps2 = page_size(2 as PagingLevel) as nat;
1544 let pv = self.prefix.to_vaddr() as nat;
1545 let cv = self.va.to_vaddr() as nat;
1546 let node_start = nat_align_down(pv, ps2) as usize;
1547
1548 lemma_page_size_ge_page_size(1 as PagingLevel);
1549 lemma_page_size_ge_page_size(2 as PagingLevel);
1550 page_size_monotonic(1 as PagingLevel, 2 as PagingLevel);
1551 lemma_page_size_divides(1 as PagingLevel, 2 as PagingLevel);
1552 lemma_nat_align_down_sound(pv, ps2);
1553 lemma_nat_align_down_sound(pv, ps1);
1554
1555 lemma_nat_align_down_monotone(pv, ps1, ps2);
1556 lemma_nat_align_down_within_block(pv, ps1, ps2);
1557
1558 AbstractVaddr::same_node_indices_match(
1559 self.va.to_vaddr(),
1560 self.prefix.to_vaddr(),
1561 node_start,
1562 1 as PagingLevel,
1563 );
1564 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1565 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1566 }
1567 }
1568
1569 #[verifier::rlimit(2000)]
1573 pub proof fn in_locked_range_guard_index_eq_prefix(self)
1574 requires
1575 self.inv(),
1576 self.prefix.inv(),
1577 1 <= self.guard_level <= NR_LEVELS,
1578 self.in_locked_range(),
1579 ensures
1580 self.va.index[self.guard_level - 1] == self.prefix.index[self.guard_level - 1],
1581 {
1582 let gl = self.guard_level;
1583 let start = self.prefix.align_down(gl as int).to_vaddr();
1584
1585 self.prefix.align_down_shape(gl as int);
1586 self.prefix.align_down_concrete(gl as int);
1587 self.prefix_aligned_to_guard_level();
1590 self.prefix_plus_ps_no_overflow();
1591 self.prefix.aligned_align_up_advances(gl as int);
1592 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(
1593 nat_align_down(
1594 self.prefix.to_vaddr() as nat,
1595 page_size(gl as PagingLevel) as nat,
1596 ) as Vaddr,
1597 );
1598 lemma_page_size_ge_page_size(gl as PagingLevel);
1599 lemma_nat_align_down_sound(
1600 self.prefix.to_vaddr() as nat,
1601 page_size(gl as PagingLevel) as nat,
1602 );
1603
1604 self.prefix.align_down(gl as int).reflect_prop(
1605 nat_align_down(
1606 self.prefix.to_vaddr() as nat,
1607 page_size(gl as PagingLevel) as nat,
1608 ) as Vaddr,
1609 );
1610
1611 let ps = page_size(gl as PagingLevel);
1619 let va_val = self.va.to_vaddr();
1620 let pf_val = self.prefix.to_vaddr();
1621 let k = start as int / ps as int;
1624 assert(start == k * ps) by {
1625 lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps as nat);
1626 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps as int);
1627 };
1628 assert(va_val as int / ps as int == k) by {
1630 let r = va_val - start;
1631 assert(va_val == k * ps + r) by (nonlinear_arith)
1632 requires
1633 va_val == start + r,
1634 start == k * ps,
1635 ;
1636 vstd::arithmetic::div_mod::lemma_fundamental_div_mod_converse(
1637 va_val as int,
1638 ps as int,
1639 k,
1640 r,
1641 );
1642 };
1643 assert(pf_val as int / ps as int == k) by {
1644 let r = pf_val - start;
1645 assert(pf_val == k * ps + r) by (nonlinear_arith)
1646 requires
1647 pf_val == start + r,
1648 start == k * ps,
1649 ;
1650 vstd::arithmetic::div_mod::lemma_fundamental_div_mod_converse(
1651 pf_val as int,
1652 ps as int,
1653 k,
1654 r,
1655 );
1656 };
1657 use crate::specs::mm::page_table::cursor::page_size_lemmas::*;
1676 lemma_page_size_spec_values();
1677 vstd::arithmetic::power2::lemma2_to64();
1680 vstd::arithmetic::power2::lemma2_to64_rest();
1681 assert(ps == pow2((12 + 9 * (gl - 1)) as nat));
1682 assert(AbstractVaddr::from_vaddr(va_val).index[gl - 1] == ((va_val as usize / ps)
1684 % NR_ENTRIES) as int);
1685 assert(AbstractVaddr::from_vaddr(pf_val).index[gl - 1] == ((pf_val as usize / ps)
1686 % NR_ENTRIES) as int);
1687 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.va);
1689 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self.prefix);
1690 }
1691
1692 pub proof fn in_locked_range_level_le_nr_levels(self)
1693 requires
1694 self.inv(),
1695 self.in_locked_range(),
1696 !self.popped_too_high,
1697 ensures
1698 self.level <= NR_LEVELS,
1699 {
1700 self.in_locked_range_level_le_guard_level();
1701 }
1702
1703 pub proof fn in_locked_range_top_index_lt_top_end(self)
1707 requires
1708 self.inv(),
1709 self.in_locked_range(),
1710 !self.popped_too_high,
1711 ensures
1712 self.va.index[NR_LEVELS - 1] < C::TOP_LEVEL_INDEX_RANGE_spec().end,
1713 {
1714 self.in_locked_range_level_le_guard_level();
1715 if self.guard_level == NR_LEVELS {
1716 if self.level < self.guard_level {
1717 assert(self.va.index[NR_LEVELS - 1] == self.prefix.index[NR_LEVELS - 1]);
1719 } else {
1720 self.in_locked_range_guard_index_eq_prefix();
1731 assert(self.va.index[NR_LEVELS - 1] == self.prefix.index[NR_LEVELS - 1]);
1732 }
1733 } else {
1734 assert(self.va.index[NR_LEVELS - 1] == self.prefix.index[NR_LEVELS - 1]);
1735 }
1736 }
1737
1738 pub proof fn in_locked_range_level_le_guard_level(self)
1739 requires
1740 self.inv(),
1741 self.in_locked_range(),
1742 !self.popped_too_high,
1743 ensures
1744 self.level <= self.guard_level,
1745 {
1746 assert(self.in_locked_range() ==> !self.above_locked_range());
1747 }
1748
1749 pub proof fn cursor_top_idx_strict_lt_nr_entries(self)
1765 requires
1766 self.inv(),
1767 self.in_locked_range(),
1768 !self.popped_too_high,
1769 self.level == NR_LEVELS,
1770 self.guard_level == NR_LEVELS,
1771 ensures
1772 self.continuations[self.level - 1].idx + 1 < NR_ENTRIES,
1773 {
1774 self.in_locked_range_top_index_lt_top_end();
1775 self.in_locked_range_guard_index_eq_prefix();
1776 let top_end = C::TOP_LEVEL_INDEX_RANGE_spec().end as int;
1777 if top_end >= NR_ENTRIES {
1778 assert(self.continuations[self.level - 1].idx + 1 < NR_ENTRIES);
1779 }
1780 }
1781
1782 pub proof fn locked_range_span(self)
1790 requires
1791 self.inv(),
1792 ensures
1793 self.locked_range().start as nat == nat_align_down(
1794 self.prefix.to_vaddr() as nat,
1795 page_size(self.guard_level as PagingLevel) as nat,
1796 ),
1797 self.locked_range().start as nat % page_size(self.guard_level as PagingLevel) as nat
1798 == 0,
1799 self.locked_range().end - self.locked_range().start == page_size(
1800 self.guard_level as PagingLevel,
1801 ),
1802 {
1803 let gl = self.guard_level;
1804 let ps_gl = page_size(gl as PagingLevel) as nat;
1805 let pv = self.prefix.to_vaddr() as nat;
1806
1807 lemma_page_size_ge_page_size(gl as PagingLevel);
1808 self.prefix.align_down_concrete(gl as int);
1809 self.prefix_aligned_to_guard_level();
1810 self.prefix_plus_ps_no_overflow();
1811 self.prefix.aligned_align_up_advances(gl as int);
1812 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(pv, ps_gl) as Vaddr);
1813 vstd_extra::arithmetic::lemma_nat_align_down_sound(pv, ps_gl);
1814 }
1815
1816 pub proof fn in_node_holds_at_guard(self, self_va: Vaddr, va: Vaddr, node_size: usize)
1824 requires
1825 self.inv(),
1826 self.in_locked_range(),
1827 self.va.reflect(self_va),
1828 node_size == page_size((self.guard_level + 1) as PagingLevel),
1829 self.locked_range().start <= va < self.locked_range().end,
1830 ensures
1831 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
1832 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
1833 {
1834 let gl = self.guard_level;
1835 let pg = page_size(gl as PagingLevel) as nat;
1836 let pg1 = node_size as nat;
1837 let ls = self.locked_range().start as nat;
1838
1839 lemma_page_size_ge_page_size(gl as PagingLevel);
1841 lemma_page_size_ge_page_size((gl + 1) as PagingLevel);
1842
1843 self.locked_range_span();
1844 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(
1845 gl as PagingLevel,
1846 (gl + 1) as PagingLevel,
1847 );
1848 self.va.reflect_prop(self_va);
1849 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg);
1855 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg1);
1856 vstd_extra::arithmetic::lemma_nat_align_down_sound(va as nat, pg1);
1857 assert(nat_align_down(self_va as nat, pg) == ls) by {
1860 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, pg);
1861 let nad = nat_align_down(self_va as nat, pg) as int;
1862 let lsi = ls as int;
1863 let pgi = pg as int;
1864 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(nad, pgi);
1868 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(lsi, pgi);
1869 let kn = nad / pgi;
1870 let kl = lsi / pgi;
1871 assert(nad == pgi * kn); assert(lsi == pgi * kl); assert(nad - lsi == pgi * (kn - kl)) by (nonlinear_arith)
1874 requires
1875 nad == pgi * kn,
1876 lsi == pgi * kl,
1877 ;
1878 assert(kn - kl == 0) by (nonlinear_arith)
1879 requires
1880 0 <= pgi * (kn - kl) < pgi,
1881 pgi > 0,
1882 ;
1883 };
1884 vstd_extra::arithmetic::lemma_nat_align_down_monotone(self_va as nat, pg, pg1);
1885 vstd_extra::arithmetic::lemma_nat_align_down_within_block(self_va as nat, pg, pg1);
1886 }
1893
1894 #[verifier::rlimit(20000)]
1896 pub proof fn node_within_locked_range(self, level: PagingLevel)
1897 requires
1898 self.inv(),
1899 self.in_locked_range(),
1900 1 <= level < self.guard_level,
1901 ensures
1902 self.locked_range().start <= nat_align_down(
1903 self.va.to_vaddr() as nat,
1904 page_size((level + 1) as PagingLevel) as nat,
1905 ) as usize,
1906 nat_align_down(
1907 self.va.to_vaddr() as nat,
1908 page_size((level + 1) as PagingLevel) as nat,
1909 ) as usize + page_size((level + 1) as PagingLevel) <= self.locked_range().end,
1910 {
1911 let gl = self.guard_level;
1912 let ps_gl = page_size(gl as PagingLevel) as nat;
1913 let ps = page_size((level + 1) as PagingLevel) as nat;
1914 let pv = self.prefix.to_vaddr() as nat;
1915 let va = self.va.to_vaddr() as nat;
1916
1917 lemma_page_size_ge_page_size(gl as PagingLevel);
1918 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1919 lemma_page_size_divides((level + 1) as PagingLevel, gl as PagingLevel);
1920
1921 self.prefix.align_down_concrete(gl as int);
1922 self.prefix_aligned_to_guard_level();
1923 self.prefix_plus_ps_no_overflow();
1924 self.prefix.aligned_align_up_advances(gl as int);
1925 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(pv, ps_gl) as Vaddr);
1926
1927 let start = nat_align_down(pv, ps_gl);
1928 let end = nat_align_down(pv, ps_gl) + ps_gl;
1930
1931 lemma_nat_align_down_sound(pv, ps_gl);
1932 lemma_nat_align_down_sound(va, ps);
1933 let ad = nat_align_down(va, ps);
1934
1935 let q = (ps_gl / ps) as int;
1937 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ps_gl as int, ps as int);
1938 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps_gl as int);
1939 assert(end as int % ps_gl as int == 0) by {
1941 vstd::arithmetic::div_mod::lemma_add_mod_noop(start as int, ps_gl as int, ps_gl as int);
1942 vstd::arithmetic::div_mod::lemma_mod_self_0(ps_gl as int);
1943 };
1944 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(end as int, ps_gl as int);
1945 let ks = start as int / ps_gl as int;
1946 let ke = end as int / ps_gl as int;
1947 vstd::arithmetic::mul::lemma_mul_is_associative(ps as int, q, ks);
1948 vstd::arithmetic::mul::lemma_mul_is_associative(ps as int, q, ke);
1949 vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(q * ks, 0int, ps as int);
1950 vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(q * ke, 0int, ps as int);
1951 vstd::arithmetic::div_mod::lemma_small_mod(0nat, ps);
1952 assert(start as int % ps as int == 0int);
1953 assert(end as int % ps as int == 0int);
1954
1955 assert(ad >= start) by {
1956 vstd::arithmetic::div_mod::lemma_div_is_ordered(start as int, va as int, ps as int);
1957 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(start as int, ps as int);
1958 vstd::arithmetic::mul::lemma_mul_inequality(
1959 start as int / ps as int,
1960 va as int / ps as int,
1961 ps as int,
1962 );
1963 };
1964
1965 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ad as int, ps as int);
1966 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(end as int, ps as int);
1967 vstd::arithmetic::div_mod::lemma_div_is_ordered(ad as int, end as int, ps as int);
1968 let ad_q = ad as int / ps as int;
1969 let end_q = end as int / ps as int;
1970 let ps_i = ps as int;
1971 vstd_extra::arithmetic::lemma_nat_align_down_sound(va, ps);
1972 vstd_extra::arithmetic::lemma_nat_align_up_sound(pv, ps_gl);
1973 assert(ad as int % ps as int == 0);
1974 assert(end as int % ps as int == 0);
1975 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ad as int, ps as int);
1976 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(end as int, ps as int);
1977 assert(ad == ps * (ad as int / ps as int) + ad as int % ps as int);
1979 assert(end == ps * (end as int / ps as int) + end as int % ps as int);
1980 vstd::arithmetic::mul::lemma_mul_is_commutative(ps as int, ad as int / ps as int);
1981 vstd::arithmetic::mul::lemma_mul_is_commutative(ps as int, end as int / ps as int);
1982 assert(ad == ad_q * ps_i + (ad as int % ps as int));
1983 assert(ad as int % ps as int == 0);
1984 assert(ad == ad_q * ps_i);
1985 assert(end as int % ps as int == 0);
1986 assert(end == end_q * ps_i) by (nonlinear_arith)
1987 requires
1988 end == ps * (end as int / ps as int) + end as int % ps as int,
1989 end as int % ps as int == 0,
1990 end_q == end as int / ps as int,
1991 ps_i == ps as int,
1992 ;
1993 assert((ad_q + 1) * ps_i <= end_q * ps_i) by (nonlinear_arith)
1994 requires
1995 ad_q + 1 <= end_q,
1996 ps_i >= 0,
1997 ;
1998 assert((ad_q + 1) * ps_i == ad_q * ps_i + ps_i) by (nonlinear_arith);
1999 }
2000
2001 pub proof fn prefix_aligned_to_guard_level(self)
2005 requires
2006 self.inv(),
2007 ensures
2008 self.prefix.to_vaddr() as nat % page_size(self.guard_level as PagingLevel) as nat == 0,
2009 {
2010 let gl = self.guard_level;
2011 let ps = page_size(gl as PagingLevel) as nat;
2012 lemma_page_size_ge_page_size(gl as PagingLevel);
2013
2014 self.prefix.align_down_shape(gl as int);
2017 self.prefix.align_down_leading_bits(gl as int);
2018 let aligned = self.prefix.align_down(gl as int);
2019
2020 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] aligned.index[i]
2021 == self.prefix.index[i] by {
2022 assert(self.prefix.index.contains_key(i));
2023 assert(aligned.index.contains_key(i));
2024 if i < gl - 1 {
2025 assert(self.prefix.index[i] == 0);
2026 }
2027 };
2028 assert(aligned.index == self.prefix.index);
2029 assert(aligned == self.prefix);
2030
2031 self.prefix.align_down_concrete(gl as int);
2033 self.prefix.to_vaddr_bounded();
2034 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.prefix.to_vaddr() as nat, ps);
2035 aligned.reflect_prop(nat_align_down(self.prefix.to_vaddr() as nat, ps) as Vaddr);
2036 }
2037
2038 pub proof fn in_node_holds_at_top(self, self_va: Vaddr, va: Vaddr, node_size: usize)
2051 requires
2052 self.inv(),
2053 self.va.reflect(self_va),
2054 self.guard_level == NR_LEVELS,
2055 node_size == page_size((NR_LEVELS + 1) as PagingLevel),
2056 self.locked_range().start <= va < self.locked_range().end,
2057 ensures
2058 nat_align_down(self_va as nat, node_size as nat) <= va as nat,
2059 (va as nat) - nat_align_down(self_va as nat, node_size as nat) < node_size as nat,
2060 {
2061 let gl = self.guard_level;
2062 let lb = self.prefix.leading_bits;
2063 let big = 0x1_0000_0000_0000int; let ps_nr = page_size(NR_LEVELS as PagingLevel) as int;
2065
2066 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
2067 assert forall|i: int| 0 <= i < NR_LEVELS implies self.prefix.index[i] == 0 by {
2072 assert(self.prefix.index.contains_key(i));
2073 };
2074 self.prefix.to_vaddr_indices_drop_zero_range(0, NR_LEVELS as int);
2075 assert(self.prefix.to_vaddr_indices(NR_LEVELS as int) == 0);
2076 assert(self.prefix.to_vaddr() == lb * big);
2077
2078 self.prefix_aligned_to_guard_level();
2080 self.prefix_plus_ps_no_overflow();
2081 self.prefix.aligned_align_up_advances(gl as int);
2082 self.prefix.align_down_shape(gl as int);
2084 self.prefix.align_down_leading_bits(gl as int);
2085 let aligned = self.prefix.align_down(gl as int);
2086 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] aligned.index[i]
2087 == self.prefix.index[i] by {
2088 assert(self.prefix.index.contains_key(i));
2089 assert(aligned.index.contains_key(i));
2090 };
2091 assert(aligned.index == self.prefix.index);
2092 assert(aligned == self.prefix);
2093 assert(self.locked_range().start == lb * big);
2094 assert(self.locked_range().end == lb * big + ps_nr);
2095
2096 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;
2101 assert(self_va == pv + lb * big);
2102 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va as nat, big as nat);
2103 assert(nat_align_down(self_va as nat, big as nat) == (lb * big) as nat) by (nonlinear_arith)
2104 requires
2105 self_va as nat == (pv + lb * big) as nat,
2106 0 <= pv < big,
2107 0 <= lb < 0x1_0000int,
2108 big == 0x1_0000_0000_0000int,
2109 nat_align_down(self_va as nat, big as nat) <= self_va as nat,
2110 nat_align_down(self_va as nat, big as nat) % (big as nat) == 0,
2111 (self_va as nat) - nat_align_down(self_va as nat, big as nat) < big as nat,
2112 forall|n: nat|
2113 n <= self_va as nat && #[trigger] (n % (big as nat)) == 0 ==> n
2114 <= nat_align_down(self_va as nat, big as nat),
2115 ;
2116
2117 }
2121
2122 pub proof fn prefix_plus_ps_no_overflow(self)
2128 requires
2129 self.inv(),
2130 ensures
2131 self.prefix.to_vaddr() + page_size(self.guard_level as PagingLevel) <= usize::MAX,
2132 {
2133 let gl = self.guard_level;
2134 lemma_page_size_ge_page_size(gl as PagingLevel);
2135 self.prefix.to_vaddr_bounded();
2136 self.prefix.to_vaddr_indices_gap_bound(0);
2137 vstd::arithmetic::power2::lemma2_to64();
2138 vstd::arithmetic::power2::lemma2_to64_rest();
2139 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
2140
2141 assert forall|i: int| 0 <= i < gl implies self.prefix.index[i] == 0 by {
2144 assert(self.prefix.index.contains_key(i));
2145 };
2146 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
2147 self.prefix.to_vaddr_indices_gap_bound(gl as int);
2148
2149 let ps = page_size(gl as PagingLevel) as int;
2153 let pv = self.prefix.to_vaddr() as int;
2154 let lb = self.prefix.leading_bits;
2155 assert(pv == self.prefix.to_vaddr_indices(gl as int) + lb * 0x1_0000_0000_0000int);
2156 assert(self.prefix.to_vaddr_indices(gl as int) + pow2((12 + 9 * gl) as nat) <= pow2(
2157 (12 + 9 * NR_LEVELS) as nat,
2158 ));
2159 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
2160 assert(pow2((12 + 9 * gl) as nat) >= ps) by {
2161 if gl == 1 {
2163 assert(ps == 0x1000);
2164 } else if gl == 2 {
2165 assert(ps == 0x20_0000);
2166 } else if gl == 3 {
2167 assert(ps == 0x4000_0000);
2168 } else {
2169 assert(ps == 0x80_0000_0000);
2170 }
2171 };
2172 let tvi = self.prefix.to_vaddr_indices(gl as int) as int;
2180 assert(pow2((12 + 9 * gl) as nat) == NR_ENTRIES * ps) by {
2181 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
2182 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
2183 (gl + 1) as PagingLevel);
2184 };
2185 assert(tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int);
2186
2187 assert(pv + ps <= usize::MAX) by (nonlinear_arith)
2188 requires
2189 pv == tvi + lb * 0x1_0000_0000_0000int,
2190 tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int,
2191 0 <= lb < 0x1_0000int,
2192 ps >= 0x1000,
2193 NR_ENTRIES == 512,
2194 usize::MAX == 0xffff_ffff_ffff_ffffusize,
2195 ;
2196 }
2197
2198 pub proof fn va_plus_page_size_no_overflow(self, level: PagingLevel)
2208 requires
2209 self.inv(),
2210 self.in_locked_range(),
2211 1 <= level <= self.guard_level,
2212 ensures
2213 self.va.to_vaddr() + page_size(level) <= usize::MAX,
2214 {
2215 let gl = self.guard_level;
2216 lemma_page_size_ge_page_size(gl as PagingLevel);
2217 lemma_page_size_ge_page_size(level as PagingLevel);
2218 page_size_monotonic(level as PagingLevel, gl as PagingLevel);
2219
2220 self.prefix_aligned_to_guard_level();
2222 self.prefix_plus_ps_no_overflow();
2223 self.prefix.aligned_align_up_advances(gl as int);
2224
2225 self.prefix.to_vaddr_bounded();
2228 self.prefix.to_vaddr_indices_gap_bound(0);
2229 vstd::arithmetic::power2::lemma2_to64();
2230 vstd::arithmetic::power2::lemma2_to64_rest();
2231 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
2232
2233 assert forall|i: int| 0 <= i < gl implies self.prefix.index[i] == 0 by {
2234 assert(self.prefix.index.contains_key(i));
2235 };
2236 self.prefix.to_vaddr_indices_drop_zero_range(0, gl as int);
2237 self.prefix.to_vaddr_indices_gap_bound(gl as int);
2238
2239 let ps = page_size(gl as PagingLevel) as int;
2240 let psl = page_size(level as PagingLevel) as int;
2241 let pv = self.prefix.to_vaddr() as int;
2242 let lb = self.prefix.leading_bits;
2243 let tvi = self.prefix.to_vaddr_indices(gl as int) as int;
2244 let va_val = self.va.to_vaddr() as int;
2245 assert(pv == tvi + lb * 0x1_0000_0000_0000int);
2246 assert(self.prefix.to_vaddr_indices(gl as int) + pow2((12 + 9 * gl) as nat) <= pow2(
2247 (12 + 9 * NR_LEVELS) as nat,
2248 ));
2249 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
2250 assert(pow2((12 + 9 * gl) as nat) >= ps) by {
2251 if gl == 1 {
2252 assert(ps == 0x1000);
2253 } else if gl == 2 {
2254 assert(ps == 0x20_0000);
2255 } else if gl == 3 {
2256 assert(ps == 0x4000_0000);
2257 } else {
2258 assert(ps == 0x80_0000_0000);
2259 }
2260 };
2261 assert(pow2((12 + 9 * gl) as nat) == NR_ENTRIES * ps) by {
2262 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
2263 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
2264 (gl + 1) as PagingLevel);
2265 };
2266 assert(tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int);
2267
2268 assert(va_val + psl <= usize::MAX) by (nonlinear_arith)
2269 requires
2270 va_val < pv + ps,
2271 pv == tvi + lb * 0x1_0000_0000_0000int,
2272 tvi + NR_ENTRIES * ps <= 0x1_0000_0000_0000int,
2273 0 <= lb < 0x1_0000int,
2274 ps >= 0x1000,
2275 psl >= 0x1000,
2276 psl <= ps,
2277 NR_ENTRIES == 512,
2278 usize::MAX == 0xffff_ffff_ffff_ffffusize,
2279 ;
2280 }
2281
2282 pub proof fn locked_range_page_aligned(self)
2283 requires
2284 self.inv(),
2285 ensures
2286 self.locked_range().end % PAGE_SIZE == 0,
2287 self.locked_range().start % PAGE_SIZE == 0,
2288 {
2289 let gl = self.guard_level;
2290 let pv = self.prefix.to_vaddr() as nat;
2291 let ps = page_size(gl as PagingLevel) as nat;
2292 lemma_page_size_ge_page_size(gl as PagingLevel);
2293 lemma_page_size_divides(1u8, gl as PagingLevel);
2294 lemma_page_size_spec_level1();
2295 lemma_nat_align_down_sound(pv, ps);
2296 lemma_nat_align_up_sound(pv, ps);
2297 let start_va = nat_align_down(pv, ps);
2298 let end_va = nat_align_up(pv, ps);
2299 vstd::arithmetic::div_mod::lemma_mod_mod(
2300 start_va as int,
2301 PAGE_SIZE as int,
2302 ps as int / PAGE_SIZE as int,
2303 );
2304 vstd::arithmetic::div_mod::lemma_mod_mod(
2305 end_va as int,
2306 PAGE_SIZE as int,
2307 ps as int / PAGE_SIZE as int,
2308 );
2309 self.prefix.align_down_concrete(gl as int);
2310 self.prefix_aligned_to_guard_level();
2311 self.prefix_plus_ps_no_overflow();
2312 self.prefix.aligned_align_up_advances(gl as int);
2313
2314 self.prefix.to_vaddr_bounded();
2315 self.prefix.to_vaddr_indices_gap_bound(0);
2316 vstd::arithmetic::power2::lemma2_to64();
2317 vstd::arithmetic::power2::lemma2_to64_rest();
2318 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
2319 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
2320 page_size_monotonic(gl as PagingLevel, NR_LEVELS as PagingLevel);
2321 vstd::arithmetic::power2::lemma_pow2_adds(12nat, 27nat);
2322 assert(page_size(NR_LEVELS as PagingLevel) == pow2(39nat));
2323 vstd::arithmetic::power2::lemma_pow2_adds(1nat, 48nat);
2324 vstd_extra::external::ilog2::lemma_pow2_increases(49nat, 64nat);
2325
2326 self.prefix.align_down_shape(gl as int);
2327 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(start_va as Vaddr);
2328 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(end_va as Vaddr);
2329 }
2330
2331 pub proof fn cur_subtree_inv(self)
2332 requires
2333 self.inv(),
2334 ensures
2335 self.cur_subtree().inv(),
2336 {
2337 let cont = self.continuations[self.level - 1];
2338 cont.inv_children_unroll(cont.idx as int)
2339 }
2340
2341 pub proof fn cur_entry_absent_not_present(self)
2343 requires
2344 self.inv(),
2345 self.in_locked_range(),
2346 self.cur_entry_owner().is_absent(),
2347 ensures
2348 !self@.present(),
2349 {
2350 self.cur_subtree_inv();
2351 let cur_va = self.cur_va();
2352 let cur_subtree = self.cur_subtree();
2353 let cur_path = cur_subtree.value.path;
2354 PageTableOwner(cur_subtree).view_rec_absent_empty(cur_path);
2355
2356 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
2357 <= cur_va < m.va_range.end) by {
2358 if m.va_range.start <= cur_va < m.va_range.end {
2359 self.mapping_covering_cur_va_from_cur_subtree(m);
2360 }
2361 };
2362
2363 let filtered = self@.mappings.filter(
2364 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
2365 );
2366 assert(filtered == set![]) by {
2367 assert forall|m: Mapping| !filtered.contains(m) by {
2368 if self@.mappings.contains(m) && m.va_range.start <= self@.cur_va < m.va_range.end {
2369 assert(self.view_mappings().contains(m));
2370 }
2371 };
2372 };
2373 }
2374
2375 pub proof fn cur_subtree_empty_not_present(self)
2377 requires
2378 self.inv(),
2379 self.in_locked_range(),
2380 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value.path) =~= set![],
2381 ensures
2382 !self@.present(),
2383 {
2384 let cur_va = self.cur_va();
2385
2386 assert forall|m: Mapping| self.view_mappings().contains(m) implies !(m.va_range.start
2387 <= cur_va < m.va_range.end) by {
2388 if m.va_range.start <= cur_va < m.va_range.end {
2389 self.mapping_covering_cur_va_from_cur_subtree(m);
2390 }
2391 };
2392
2393 let filtered = self@.mappings.filter(
2394 |m: Mapping| m.va_range.start <= self@.cur_va < m.va_range.end,
2395 );
2396 assert(filtered == set![]) by {
2397 assert forall|m: Mapping| !filtered.contains(m) by {
2398 if self@.mappings.contains(m) && m.va_range.start <= self@.cur_va < m.va_range.end {
2399 assert(self.view_mappings().contains(m));
2400 }
2401 };
2402 };
2403 assert(filtered.len() == 0);
2404 }
2405
2406 pub proof fn cur_entry_frame_present(self)
2407 requires
2408 self.inv(),
2409 self.in_locked_range(),
2410 self.cur_entry_owner().is_frame(),
2411 ensures
2412 self@.present(),
2413 self@.query(
2414 self.cur_entry_owner().frame().mapped_pa,
2415 self.cur_entry_owner().frame().size,
2416 self.cur_entry_owner().frame().prop,
2417 ),
2418 {
2419 self.cur_subtree_inv();
2420 self.cur_va_in_subtree_range();
2421 self.view_preserves_inv();
2422 let subtree = self.cur_subtree();
2423 let path = subtree.value.path;
2424 let frame = self.cur_entry_owner().frame();
2425 let pt_level = INC_LEVELS - path.len();
2426 let cont = self.continuations[self.level - 1];
2427
2428 cont.path().push_tail_property_len(cont.idx as usize);
2429
2430 let m = Mapping {
2431 va_range: Range {
2432 start: vaddr_of::<C>(path) as int,
2433 end: vaddr_of::<C>(path) + page_size(pt_level as PagingLevel),
2434 },
2435 pa_range: Range {
2436 start: frame.mapped_pa,
2437 end: (frame.mapped_pa + page_size(pt_level as PagingLevel)) as Paddr,
2438 },
2439 page_size: page_size(pt_level as PagingLevel),
2440 property: frame.prop,
2441 };
2442 assert(PageTableOwner(subtree).view_rec(path) == set![m]);
2443 cont.lemma_view_mappings_intro(m, cont.idx as int);
2444 self.lemma_view_mappings_intro(m, self.level - 1);
2445 assert(m.va_range.start <= self@.cur_va < m.va_range.end) by {
2446 self.cur_va_in_subtree_range();
2447 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
2448 };
2449
2450 let filtered = self@.mappings.filter(
2451 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
2452 );
2453 assert(filtered.contains(m));
2454 lemma_set_contains_len(filtered, m);
2455 }
2456
2457 pub open spec fn path_metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2459 forall|i: int|
2460 #![trigger self.continuations[i]]
2461 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].entry_own.metaregion_sound(
2462 regions,
2463 )
2464 }
2465
2466 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
2467 &&& self.map_full_tree(
2468 |entry_owner: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2469 entry_owner.metaregion_sound(regions),
2470 )
2471 &&& self.path_metaregion_sound(regions)
2472 }
2473
2474 pub proof fn metaregion_preserved(
2475 self,
2476 other: Self,
2477 regions0: MetaRegionOwners,
2478 regions1: MetaRegionOwners,
2479 )
2480 requires
2481 self.inv(),
2482 self.metaregion_sound(regions0),
2483 self.level == other.level,
2484 self.continuations =~= other.continuations,
2485 OwnerSubtree::implies(
2486 PageTableOwner::<C>::metaregion_sound_pred(regions0),
2487 PageTableOwner::<C>::metaregion_sound_pred(regions1),
2488 ),
2489 ensures
2490 other.metaregion_sound(regions1),
2491 {
2492 let f = PageTableOwner::metaregion_sound_pred(regions0);
2493 let g = PageTableOwner::metaregion_sound_pred(regions1);
2494
2495 assert forall|i: int| #![auto] self.level - 1 <= i < NR_LEVELS implies {
2496 other.continuations[i].map_children(g)
2497 } by {
2498 let cont = self.continuations[i];
2499 assert(cont.inv());
2500 assert(cont.map_children(f));
2501 reveal(CursorContinuation::inv_children);
2502 assert forall|j: int|
2503 0 <= j < NR_ENTRIES
2504 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().tree_predicate_map(
2505 cont.path().push_tail(j as usize), g) by {
2506 cont.inv_children_unroll(j);
2507 cont.children[j].unwrap().map_implies(cont.path().push_tail(j as usize), f, g);
2508 };
2509 };
2510 assert(other.path_metaregion_sound(regions1)) by {
2511 assert forall|i: int|
2512 #![trigger other.continuations[i]]
2513 self.level - 1 <= i
2514 < NR_LEVELS implies other.continuations[i].entry_own.metaregion_sound(
2515 regions1,
2516 ) by {
2517 self.inv_continuation(i);
2518 let eo = self.continuations[i].entry_own;
2519 assert(eo.metaregion_sound(regions0));
2520 assert(g(eo, self.continuations[i].path()));
2521 };
2522 };
2523 }
2524
2525 pub proof fn metaregion_slot_owners_preserved(
2527 self,
2528 regions0: MetaRegionOwners,
2529 regions1: MetaRegionOwners,
2530 )
2531 requires
2532 self.inv(),
2533 self.metaregion_sound(regions0),
2534 regions0.slot_owners =~= regions1.slot_owners,
2535 forall|k: usize|
2536 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2537 forall|k: usize|
2538 regions0.slots.contains_key(k) ==> regions0.slots[k]
2539 == #[trigger] regions1.slots[k],
2540 ensures
2541 self.metaregion_sound(regions1),
2542 {
2543 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2544 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2545 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2546 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
2547 entry.metaregion_sound_slot_owners_only(regions0, regions1);
2548 };
2549 self.metaregion_preserved(self, regions0, regions1);
2550 }
2551
2552 pub proof fn metaregion_slot_owners_rc_increment(
2553 self,
2554 regions0: MetaRegionOwners,
2555 regions1: MetaRegionOwners,
2556 idx: usize,
2557 )
2558 requires
2559 self.inv(),
2560 self.metaregion_sound(regions0),
2561 regions0.inv(),
2562 regions1.slots == regions0.slots,
2563 regions1.slot_owners.dom() == regions0.slot_owners.dom(),
2564 regions1.slot_owners[idx].inner_perms.ref_count.value()
2565 == regions0.slot_owners[idx].inner_perms.ref_count.value() + 1,
2566 regions1.slot_owners[idx].inner_perms.ref_count.id()
2567 == regions0.slot_owners[idx].inner_perms.ref_count.id(),
2568 regions1.slot_owners[idx].inner_perms.storage
2569 == regions0.slot_owners[idx].inner_perms.storage,
2570 regions1.slot_owners[idx].inner_perms.vtable_ptr
2571 == regions0.slot_owners[idx].inner_perms.vtable_ptr,
2572 regions1.slot_owners[idx].inner_perms.in_list
2573 == regions0.slot_owners[idx].inner_perms.in_list,
2574 regions1.slot_owners[idx].paths_in_pt == regions0.slot_owners[idx].paths_in_pt,
2575 regions1.slot_owners[idx].slot_vaddr == regions0.slot_owners[idx].slot_vaddr,
2576 regions1.slot_owners[idx].usage == regions0.slot_owners[idx].usage,
2577 regions1.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
2578 regions1.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX,
2580 forall|i: usize|
2581 #![trigger regions1.slot_owners[i]]
2582 i != idx && regions0.slot_owners.contains_key(i) ==> regions1.slot_owners[i]
2583 == regions0.slot_owners[i],
2584 ensures
2585 self.metaregion_sound(regions1),
2586 {
2587 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2588 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2589 assert(OwnerSubtree::implies(f, g)) by {
2590 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2591 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
2592 if entry.meta_slot_paddr() is Some {
2593 let eidx = frame_to_index(entry.meta_slot_paddr().unwrap());
2594 if eidx != idx {
2595 } else {
2596 entry.metaregion_sound_rc_value_changed(regions0, regions1);
2597 }
2598 }
2599 };
2600 };
2601 self.metaregion_preserved(self, regions0, regions1);
2602 }
2603
2604 pub proof fn metaregion_borrow_slot(
2607 self,
2608 regions0: MetaRegionOwners,
2609 regions1: MetaRegionOwners,
2610 changed_idx: usize,
2611 )
2612 requires
2613 self.inv(),
2614 self.metaregion_sound(regions0),
2615 regions1.inv(),
2616 forall|k: usize|
2617 regions0.slots.contains_key(k) ==> #[trigger] regions1.slots.contains_key(k),
2618 forall|k: usize|
2625 regions0.slots.contains_key(k) ==> regions0.slots[k]
2626 == #[trigger] regions1.slots[k],
2627 regions1.slot_owners[changed_idx].inner_perms
2629 == regions0.slot_owners[changed_idx].inner_perms,
2630 regions1.slot_owners[changed_idx].slot_vaddr
2631 == regions0.slot_owners[changed_idx].slot_vaddr,
2632 regions1.slot_owners[changed_idx].usage == regions0.slot_owners[changed_idx].usage,
2633 regions1.slot_owners[changed_idx].paths_in_pt
2634 == regions0.slot_owners[changed_idx].paths_in_pt,
2635 forall|i: usize|
2637 #![trigger regions1.slot_owners[i]]
2638 i != changed_idx ==> regions0.slot_owners[i] == regions1.slot_owners[i],
2639 regions0.slot_owners.dom() =~= regions1.slot_owners.dom(),
2640 ensures
2641 self.metaregion_sound(regions1),
2642 {
2643 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
2644 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
2645 let nsp = PageTableOwner::<C>::not_in_scope_pred();
2646
2647 assert(OwnerSubtree::implies(
2648 |v: EntryOwner<C>, p: TreePath<NR_ENTRIES>| f(v, p) && nsp(v, p),
2649 g,
2650 )) by {
2651 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2652 entry.inv() && f(entry, path) && nsp(entry, path) implies #[trigger] g(
2653 entry,
2654 path,
2655 ) by {
2656 if entry.meta_slot_paddr() is Some {
2657 let eidx = frame_to_index(entry.meta_slot_paddr().unwrap());
2658 if eidx != changed_idx {
2659 } else if entry.is_frame() {
2660 assert(regions1.slots.contains_key(eidx));
2661 }
2662 }
2663 };
2664 };
2665
2666 assert forall|i: int|
2667 #![trigger self.continuations[i]]
2668 self.level - 1 <= i < NR_LEVELS implies { self.continuations[i].map_children(g) } by {
2669 let cont = self.continuations[i];
2670 reveal(CursorContinuation::inv_children);
2671 assert forall|j: int|
2672 0 <= j < NR_ENTRIES
2673 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().tree_predicate_map(
2674 cont.path().push_tail(j as usize), nsp) by {
2675 cont.inv_children_unroll(j);
2676 PageTableOwner::tree_not_in_scope(
2677 cont.children[j].unwrap(),
2678 cont.path().push_tail(j as usize),
2679 );
2680 };
2681 assert forall|j: int|
2682 0 <= j < NR_ENTRIES
2683 && #[trigger] cont.children[j] is Some implies cont.children[j].unwrap().tree_predicate_map(
2684 cont.path().push_tail(j as usize), g) by {
2685 cont.inv_children_unroll(j);
2686 cont.children[j].unwrap().map_implies_and(
2687 cont.path().push_tail(j as usize),
2688 f,
2689 nsp,
2690 g,
2691 );
2692 };
2693 };
2694
2695 assert(self.path_metaregion_sound(regions1)) by {
2696 assert forall|i: int|
2697 #![trigger self.continuations[i]]
2698 self.level - 1 <= i
2699 < NR_LEVELS implies self.continuations[i].entry_own.metaregion_sound(
2700 regions1,
2701 ) by {
2702 self.inv_continuation(i);
2703 let eo = self.continuations[i].entry_own;
2704 if eo.meta_slot_paddr() is Some {
2705 let eidx = frame_to_index(eo.meta_slot_paddr().unwrap());
2706 if eidx != changed_idx {
2707 }
2708 }
2709 };
2710 };
2711 }
2712
2713 pub proof fn cont_entries_metaregion(self, regions: MetaRegionOwners)
2723 requires
2724 self.inv(),
2725 self.metaregion_sound(regions),
2726 ensures
2727 forall|i: int|
2728 #![trigger self.continuations[i]]
2729 self.level - 1 <= i < NR_LEVELS
2730 ==> self.continuations[i].entry_own.metaregion_sound(regions),
2731 {
2732 }
2735
2736 pub open spec fn new(
2737 owner_subtree: OwnerSubtree<C>,
2738 idx: usize,
2739 guard: PageTableGuard<'rcu, C>,
2740 ) -> Self {
2741 let va = AbstractVaddr {
2742 offset: 0,
2743 index: Map::new(Set::<int>::range(0, NR_LEVELS as int), |i: int| 0).insert(
2744 NR_LEVELS - 1,
2745 idx as int,
2746 ),
2747 leading_bits: C::LEADING_BITS_spec() as int,
2753 };
2754 Self {
2755 level: NR_LEVELS as PagingLevel,
2756 continuations: Map::empty().insert(
2757 NR_LEVELS - 1,
2758 CursorContinuation::new(owner_subtree, idx, guard),
2759 ),
2760 va,
2761 guard_level: NR_LEVELS as PagingLevel,
2762 prefix: va,
2763 popped_too_high: false,
2764 }
2765 }
2766
2767 pub axiom fn tracked_new(
2768 tracked owner_subtree: OwnerSubtree<C>,
2769 idx: usize,
2770 guard: PageTableGuard<'rcu, C>,
2771 ) -> (tracked res: Self)
2772 ensures
2773 res == Self::new(owner_subtree, idx, guard),
2774 ;
2775
2776 pub broadcast group group_lemmas {
2777 CursorOwner::lemma_view_mappings_contains,
2778 CursorOwner::lemma_view_mappings_intro,
2779 }
2780}
2781
2782pub ghost struct CursorView<C: PageTableConfig> {
2783 pub cur_va: Vaddr,
2784 pub mappings: Set<Mapping>,
2785 pub phantom: PhantomData<C>,
2786}
2787
2788impl<'rcu, C: PageTableConfig> View for CursorOwner<'rcu, C> {
2789 type V = CursorView<C>;
2790
2791 open spec fn view(&self) -> Self::V {
2792 CursorView { cur_va: self.cur_va(), mappings: self.view_mappings(), phantom: PhantomData }
2793 }
2794}
2795
2796impl<C: PageTableConfig> Inv for CursorView<C> {
2797 open spec fn inv(self) -> bool {
2798 &&& forall|m: Mapping|
2799 #![auto]
2800 self.mappings.contains(m)
2801 ==> m.inv()
2802 &&& forall|m: Mapping|
2808 #![auto]
2809 self.mappings.contains(m) ==> {
2810 &&& vaddr_range_bounds_spec::<C>().0 <= m.va_range.start
2811 &&& m.va_range.end <= vaddr_range_bounds_spec::<C>().1 + 1
2812 }
2813 &&& self.non_overlapping()
2814 }
2815}
2816
2817impl<C: PageTableConfig> CursorView<C> {
2818 pub open spec fn non_overlapping(self) -> bool {
2821 forall|m: Mapping, n: Mapping|
2822 #![auto]
2823 self.mappings.contains(m) ==> self.mappings.contains(n) ==> m != n ==> m.va_range.end
2824 <= n.va_range.start || n.va_range.end <= m.va_range.start
2825 }
2826}
2827
2828pub proof fn lemma_view_in_vaddr_range<'rcu, C: PageTableConfig>(owner: &CursorOwner<'rcu, C>)
2831 requires
2832 owner.inv(),
2833 ensures
2834 forall|m: Mapping|
2835 #![auto]
2836 owner.view_mappings().contains(m) ==> {
2837 &&& vaddr_range_bounds_spec::<C>().0 <= m.va_range.start
2838 &&& m.va_range.end <= vaddr_range_bounds_spec::<C>().1 + 1
2839 },
2840{
2841 C::lemma_paging_consts_properties();
2842 C::lemma_page_table_config_constant_properties();
2843 crate::mm::page_table::lemma_pte_index_consts::<C>();
2844 lemma_vaddr_range_bounds_spec_unfold::<C>();
2845 vstd::arithmetic::power2::lemma2_to64();
2846 vstd::arithmetic::power2::lemma2_to64_rest();
2847 vstd::arithmetic::power2::lemma_pow2_adds(
2848 (C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<C>(C::NR_LEVELS())) as nat,
2849 pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat,
2850 );
2851 vstd::layout::unsigned_int_max_values();
2852
2853 let idx = C::TOP_LEVEL_INDEX_RANGE_spec();
2854 let start = idx.start as int;
2855 let end = idx.end as int;
2856 let lb = C::LEADING_BITS_spec() as int;
2857 let base = lb * 0x1_0000_0000_0000int;
2858 let cell = 0x80_0000_0000int;
2859 let bounds = vaddr_range_bounds_spec::<C>();
2860
2861 let aw = C::ADDRESS_WIDTH() as nat;
2862 let top_w = (C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<C>(C::NR_LEVELS())) as nat;
2863 let p_aw = pow2(aw) as int;
2864 let p_top = pow2(top_w) as int;
2865 assert(end * cell <= p_aw) by (nonlinear_arith)
2866 requires
2867 end <= p_top,
2868 cell > 0,
2869 p_aw == p_top * cell,
2870 ;
2871 let start_pre = base + start * cell;
2872 let end_exclusive = base + end * cell;
2873 let end_pre = end_exclusive - 1;
2874 if C::LEADING_BITS_spec() == 0usize {
2875 assert(0 <= start_pre < 0x1_0000_0000_0000_0000int) by (nonlinear_arith)
2876 requires
2877 start_pre == start * cell,
2878 start >= 0,
2879 start < end,
2880 cell > 0,
2881 end * cell <= usize::MAX,
2882 usize::MAX < 0x1_0000_0000_0000_0000int,
2883 ;
2884 assert(0 <= end_pre <= usize::MAX) by (nonlinear_arith)
2885 requires
2886 end_pre == end * cell - 1,
2887 end > 0,
2888 cell > 0,
2889 end * cell <= usize::MAX,
2890 ;
2891 } else {
2892 assert(base == 0x1_0000_0000_0000_0000int - p_aw);
2893 assert(0 <= start_pre < 0x1_0000_0000_0000_0000int) by (nonlinear_arith)
2894 requires
2895 start_pre == 0x1_0000_0000_0000_0000int - p_aw + start * cell,
2896 base == 0x1_0000_0000_0000_0000int - p_aw,
2897 p_aw <= 0x1_0000_0000_0000_0000int,
2898 start >= 0,
2899 start < end,
2900 cell > 0,
2901 end * cell <= p_aw,
2902 ;
2903 assert(0 <= end_pre <= usize::MAX) by (nonlinear_arith)
2904 requires
2905 end_pre == 0x1_0000_0000_0000_0000int - p_aw + end * cell - 1,
2906 base == 0x1_0000_0000_0000_0000int - p_aw,
2907 end > 0,
2908 cell > 0,
2909 end * cell <= p_aw,
2910 p_aw <= 0x1_0000_0000_0000_0000int,
2911 usize::MAX == 0x1_0000_0000_0000_0000int - 1,
2912 ;
2913 }
2914 assert(bounds.0 == base + start * cell);
2915 assert(bounds.1 == base + end * cell - 1);
2916
2917 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2918 &&& vaddr_range_bounds_spec::<C>().0 <= m.va_range.start
2919 &&& m.va_range.end <= vaddr_range_bounds_spec::<C>().1 + 1
2920 } by {
2921 owner.lemma_view_mappings_contains();
2922 let i = choose|i: int|
2923 owner.level - 1 <= i < NR_LEVELS && (
2924 #[trigger] owner.continuations[i]).view_mappings().contains(m);
2925 owner.inv_continuation(i);
2926 let cont = owner.continuations[i];
2927 cont.lemma_view_mappings_contains();
2928 let j = choose|j: int|
2929 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
2930 cont.children[j].unwrap(),
2931 ).view_rec(cont.path().push_tail(j as usize)).contains(m);
2932 cont.pt_inv_children_unroll(j);
2933 cont.inv_children_rel_unroll(j);
2934 let child = PageTableOwner(cont.children[j].unwrap());
2935 let p = cont.path().push_tail(j as usize);
2936 cont.path().push_tail_property_len(j as usize);
2937 cont.path().push_tail_property_index(j as usize);
2938 let pidx = p.index(0) as int;
2939 assert(start <= pidx < end) by {
2940 if i != NR_LEVELS - 1 {
2941 assert(cont.path().index(0) == owner.continuations[NR_LEVELS - 1].idx) by {
2942 owner.inv_continuation(NR_LEVELS - 1);
2943 owner.continuations[NR_LEVELS - 1].path().push_tail_property_index(
2944 owner.continuations[NR_LEVELS - 1].idx,
2945 );
2946 if i == 2 {
2947 } else if i == 1 {
2948 owner.continuations[2].path().push_tail_property_index(
2949 owner.continuations[2].idx,
2950 );
2951 } else {
2952 owner.continuations[2].path().push_tail_property_index(
2953 owner.continuations[2].idx,
2954 );
2955 owner.continuations[1].path().push_tail_property_index(
2956 owner.continuations[1].idx,
2957 );
2958 }
2959 }
2960 }
2961 }
2962 child.view_rec_top_index_va_bound(p, m, end);
2963 }
2964}
2965
2966pub proof fn lemma_view_in_vaddr_range_user<'rcu>(
2975 owner: &CursorOwner<'rcu, crate::mm::vm_space::UserPtConfig>,
2976)
2977 requires
2978 owner.inv(),
2979 ensures
2980 forall|m: Mapping|
2981 #![auto]
2982 owner.view_mappings().contains(m) ==> {
2983 &&& 0 <= m.va_range.start
2984 &&& m.va_range.end <= 0x8000_0000_0000int
2985 },
2986{
2987 let end = crate::mm::vm_space::UserPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end as int;
2988 assert(end == 256);
2989 assert(end * 0x80_0000_0000int == 0x8000_0000_0000int) by (nonlinear_arith)
2990 requires
2991 end == 256,
2992 ;
2993 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
2994 &&& 0 <= m.va_range.start
2995 &&& m.va_range.end <= 0x8000_0000_0000int
2996 } by {
2997 owner.lemma_view_mappings_contains();
2998 let i = choose|i: int|
2999 owner.level - 1 <= i < NR_LEVELS && (
3000 #[trigger] owner.continuations[i]).view_mappings().contains(m);
3001 owner.inv_continuation(i);
3002 let cont = owner.continuations[i];
3003 cont.lemma_view_mappings_contains();
3004 let j = choose|j: int|
3005 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
3006 cont.children[j].unwrap(),
3007 ).view_rec(cont.path().push_tail(j as usize)).contains(m);
3008 cont.pt_inv_children_unroll(j);
3009 cont.inv_children_rel_unroll(j);
3010 let child = PageTableOwner(cont.children[j].unwrap());
3011 let p = cont.path().push_tail(j as usize);
3012 cont.path().push_tail_property_index(j as usize);
3013 assert(0 <= p.index(0) < end) by {
3014 if i == NR_LEVELS - 1 {
3015 assert(cont.path().len() == 0);
3020 assert(p.index(0) == j);
3021 assert(child.0.value.is_frame() || child.0.value.is_node());
3022 assert(!child.0.value.is_borrowed());
3023 assert(!child.0.value.is_absent());
3024 } else {
3025 assert(cont.path().len() > 0);
3029 assert(p.index(0) == cont.path().index(0));
3030 assert(cont.path().index(0) == owner.continuations[NR_LEVELS - 1].idx) by {
3031 owner.inv_continuation(NR_LEVELS - 1);
3032 owner.continuations[NR_LEVELS - 1].path().push_tail_property_index(
3033 owner.continuations[NR_LEVELS - 1].idx,
3034 );
3035 if i == 2 {
3036 } else if i == 1 {
3037 owner.continuations[2].path().push_tail_property_index(
3038 owner.continuations[2].idx,
3039 );
3040 } else {
3041 owner.continuations[2].path().push_tail_property_index(
3042 owner.continuations[2].idx,
3043 );
3044 owner.continuations[1].path().push_tail_property_index(
3045 owner.continuations[1].idx,
3046 );
3047 }
3048 }
3049 }
3050 }
3051 child.view_rec_top_index_va_bound(p, m, end);
3052 }
3053}
3054
3055pub proof fn lemma_view_in_vaddr_range_kernel<'rcu>(
3060 owner: &CursorOwner<'rcu, crate::mm::kspace::KernelPtConfig>,
3061)
3062 requires
3063 owner.inv(),
3064 ensures
3065 forall|m: Mapping|
3066 #![auto]
3067 owner.view_mappings().contains(m) ==> {
3068 &&& vaddr_range_bounds_spec::<crate::mm::kspace::KernelPtConfig>().0
3069 <= m.va_range.start
3070 &&& m.va_range.end <= vaddr_range_bounds_spec::<
3071 crate::mm::kspace::KernelPtConfig,
3072 >().1 + 1
3073 },
3074{
3075 crate::mm::page_table::lemma_vaddr_range_bounds_spec_kernel();
3076 let start = crate::mm::kspace::KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().start as int;
3077 let end = crate::mm::kspace::KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end as int;
3078 let lb = crate::mm::kspace::KernelPtConfig::LEADING_BITS_spec() as int;
3079 assert(start == 256);
3080 assert(end == 512);
3081 assert(lb == 0xffff);
3082 assert(start * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int == 0xFFFF_8000_0000_0000int)
3085 by (nonlinear_arith)
3086 requires
3087 start == 256,
3088 lb == 0xffff,
3089 ;
3090 assert(end * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int)
3091 by (nonlinear_arith)
3092 requires
3093 end == 512,
3094 lb == 0xffff,
3095 ;
3096 assert forall|m: Mapping| #[trigger] owner.view_mappings().contains(m) implies {
3097 &&& vaddr_range_bounds_spec::<crate::mm::kspace::KernelPtConfig>().0 <= m.va_range.start
3098 &&& m.va_range.end <= vaddr_range_bounds_spec::<crate::mm::kspace::KernelPtConfig>().1 + 1
3099 } by {
3100 owner.lemma_view_mappings_contains();
3101 let i = choose|i: int|
3102 owner.level - 1 <= i < NR_LEVELS && (
3103 #[trigger] owner.continuations[i]).view_mappings().contains(m);
3104 owner.inv_continuation(i);
3105 let cont = owner.continuations[i];
3106 cont.lemma_view_mappings_contains();
3107 let j = choose|j: int|
3108 0 <= j < cont.children.len() && #[trigger] cont.children[j] is Some && PageTableOwner(
3109 cont.children[j].unwrap(),
3110 ).view_rec(cont.path().push_tail(j as usize)).contains(m);
3111 cont.pt_inv_children_unroll(j);
3112 cont.inv_children_rel_unroll(j);
3113 let child = PageTableOwner(cont.children[j].unwrap());
3114 let p = cont.path().push_tail(j as usize);
3115 cont.path().push_tail_property_index(j as usize);
3116 assert(start <= p.index(0) < end) by {
3117 if i == NR_LEVELS - 1 {
3118 assert(cont.path().len() == 0);
3122 assert(p.index(0) == j);
3123 assert(child.0.value.is_frame() || child.0.value.is_node());
3124 assert(!child.0.value.is_borrowed());
3125 assert(!child.0.value.is_absent());
3126 } else {
3127 assert(cont.path().len() > 0);
3130 assert(p.index(0) == cont.path().index(0));
3131 assert(cont.path().index(0) == owner.continuations[NR_LEVELS - 1].idx) by {
3132 owner.inv_continuation(NR_LEVELS - 1);
3133 owner.continuations[NR_LEVELS - 1].path().push_tail_property_index(
3134 owner.continuations[NR_LEVELS - 1].idx,
3135 );
3136 if i == 2 {
3137 } else if i == 1 {
3138 owner.continuations[2].path().push_tail_property_index(
3139 owner.continuations[2].idx,
3140 );
3141 } else {
3142 owner.continuations[2].path().push_tail_property_index(
3143 owner.continuations[2].idx,
3144 );
3145 owner.continuations[1].path().push_tail_property_index(
3146 owner.continuations[1].idx,
3147 );
3148 }
3149 }
3150 }
3151 }
3152 child.view_rec_top_index_va_bound(p, m, end);
3153 assert(p.index(0) * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int >= start
3155 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int) by (nonlinear_arith)
3156 requires
3157 start <= p.index(0),
3158 ;
3159 }
3160}
3161
3162impl<'rcu, C: PageTableConfig> InvView for CursorOwner<'rcu, C> {
3163 proof fn view_preserves_inv(self) {
3164 self.view_non_overlapping();
3166 self.view_mapping_inv();
3169 lemma_view_in_vaddr_range::<C>(&self);
3172 }
3173}
3174
3175impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
3176 pub proof fn view_non_overlapping(self)
3182 requires
3183 self.inv(),
3184 ensures
3185 self@.non_overlapping(),
3186 {
3187 self.as_page_table_owner_view_non_overlapping();
3188 }
3189}
3190
3191impl<'rcu, C: PageTableConfig, A: InAtomicMode> Inv for Cursor<'rcu, C, A> {
3192 open spec fn inv(self) -> bool {
3193 &&& 1 <= self.level <= NR_LEVELS
3201 + 1
3202 &&& self.level <= self.guard_level + 1
3210 &&& self.guard_level
3211 <= NR_LEVELS
3212 &&& self.va >= self.barrier_va.start
3214 &&& self.va % PAGE_SIZE == 0
3215 }
3216}
3217
3218impl<'rcu, C: PageTableConfig, A: InAtomicMode> OwnerOf for Cursor<'rcu, C, A> {
3219 type Owner = CursorOwner<'rcu, C>;
3220
3221 open spec fn wf(self, owner: Self::Owner) -> bool {
3222 &&& owner.va.reflect(self.va)
3223 &&& self.level == owner.level
3224 &&& owner.guard_level
3225 == self.guard_level
3226 &&& self.level <= 4 ==> {
3235 &&& 4 <= self.guard_level ==> {
3236 &&& self.path[3] is Some
3237 &&& owner.continuations.contains_key(3)
3238 &&& owner.continuations[3].guard == self.path[3]->0
3239 }
3240 &&& 4 > self.guard_level ==> self.path[3] is None
3241 }
3242 &&& self.level <= 3 ==> {
3243 &&& 3 <= self.guard_level ==> {
3244 &&& self.path[2] is Some
3245 &&& owner.continuations.contains_key(2)
3246 &&& owner.continuations[2].guard == self.path[2]->0
3247 }
3248 &&& 3 > self.guard_level ==> self.path[2] is None
3249 }
3250 &&& self.level <= 2 ==> {
3251 &&& 2 <= self.guard_level ==> {
3252 &&& self.path[1] is Some
3253 &&& owner.continuations.contains_key(1)
3254 &&& owner.continuations[1].guard == self.path[1]->0
3255 }
3256 &&& 2 > self.guard_level ==> self.path[1] is None
3257 }
3258 &&& self.level == 1 ==> {
3259 &&& 1 <= self.guard_level ==> {
3263 &&& self.path[0] is Some
3264 &&& owner.continuations.contains_key(0)
3265 &&& owner.continuations[0].guard == self.path[0]->0
3266 }
3267 &&& 1 > self.guard_level ==> self.path[0] is None
3268 }
3269 &&& self.barrier_va.start == owner.locked_range().start
3270 &&& self.barrier_va.end == owner.locked_range().end
3271 }
3272}
3273
3274}