1use vstd::prelude::*;
2
3use core::ops::Range;
4
5use vstd::arithmetic::power2::pow2;
6use vstd::seq::*;
7use vstd::seq_lib::*;
8use vstd::set_lib::*;
9use vstd_extra::array_ptr;
10use vstd_extra::cast_ptr::Repr;
11use vstd_extra::drop_tracking::*;
12use vstd_extra::ghost_tree::*;
13use vstd_extra::ownership::*;
14use vstd_extra::prelude::TreeNodeValue;
15
16use crate::mm::{MAX_NR_LEVELS, Paddr, PagingLevel, Vaddr, page_table::EntryOwner};
17
18use crate::mm::frame::frame_to_index;
19use crate::mm::page_table::{PageTableEntryTrait, PageTableGuard, page_size_spec};
20
21use crate::specs::arch::*;
22use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
23use crate::specs::mm::page_table::cursor::page_size_lemmas::{
24 lemma_page_size_divides, lemma_page_size_ge_page_size, lemma_page_size_spec_values,
25};
26use crate::specs::mm::page_table::*;
27
28use core::ops::Deref;
29
30verus! {
31
32#[verifier::inline]
33pub open spec fn vaddr_shift_bits<const L: usize>(idx: int) -> nat
34 recommends
35 0 < L,
36 idx < L,
37{
38 (12 + 9 * (L - 1 - idx)) as nat
39}
40
41#[verifier::inline]
42pub open spec fn vaddr_shift<const L: usize>(idx: int) -> usize
43 recommends
44 0 < L,
45 idx < L,
46{
47 pow2(vaddr_shift_bits::<L>(idx)) as usize
48}
49
50#[verifier::inline]
51pub open spec fn vaddr_make<const L: usize>(idx: int, offset: usize) -> usize
52 recommends
53 0 < L,
54 idx < L,
55 0 <= offset < 512,
56{
57 (vaddr_shift::<L>(idx) * offset) as usize
58}
59
60pub open spec fn rec_vaddr(
61 path: TreePath<NR_ENTRIES>,
62 idx: int,
63) -> usizedecreases path.len() - idx,
69 when 0 <= idx <= path.len()
70{
71 if idx == path.len() {
72 0
73 } else {
74 let offset: usize = path.index(idx);
75 (vaddr_make::<NR_LEVELS>(idx, offset) + rec_vaddr(path, idx + 1)) as usize
76 }
77}
78
79pub open spec fn vaddr(path: TreePath<NR_ENTRIES>) -> usize {
80 rec_vaddr(path, 0)
81}
82
83pub open spec fn vaddr_at(path: TreePath<NR_ENTRIES>, leading_bits: int) -> usize {
90 (vaddr(path) as int + leading_bits * 0x1_0000_0000_0000int) as usize
91}
92
93pub open spec fn vaddr_of<C: PageTableConfig>(path: TreePath<NR_ENTRIES>) -> usize {
99 vaddr_at(path, C::LEADING_BITS_spec() as int)
100}
101
102pub axiom fn axiom_leading_bits_bounded<C: PageTableConfig>()
110 ensures
111 C::LEADING_BITS_spec() < 0x1_0000_usize,
112;
113
114#[verifier::rlimit(400)]
118pub proof fn lemma_vaddr_strict_bound(path: TreePath<NR_ENTRIES>)
119 requires
120 path.inv(),
121 path.len() <= INC_LEVELS - 1,
122 ensures
123 (vaddr(path) as int) < 0x1_0000_0000_0000int,
124{
125 broadcast use TreePath::index_satisfies_elem_inv;
126 broadcast use TreePath::push_tail_property;
127
128 lemma_page_size_spec_values();
129 vstd::arithmetic::power2::lemma2_to64();
130 vstd::arithmetic::power2::lemma2_to64_rest();
131 if path.len() == 0 {
132 assert(rec_vaddr(path, 0) == 0);
133 } else if path.len() == 1 {
134 let i0 = path.index(0);
135 assert(0 <= i0 < NR_ENTRIES);
136 assert(rec_vaddr(path, 1) == 0);
137 assert(rec_vaddr(path, 0) == vaddr_make::<NR_LEVELS>(0, i0) as usize);
138 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
139 assert(0x80_0000_0000usize * i0 < 0x1_0000_0000_0000int) by (nonlinear_arith)
140 requires
141 i0 < 512,
142 ;
143 } else if path.len() == 2 {
144 let i0 = path.index(0);
145 let i1 = path.index(1);
146 assert(0 <= i0 < NR_ENTRIES);
147 assert(0 <= i1 < NR_ENTRIES);
148 assert(rec_vaddr(path, 2) == 0);
149 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1) as usize);
150 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
151 1,
152 i1,
153 )) as usize);
154 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
155 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
156 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 < 0x1_0000_0000_0000int)
157 by (nonlinear_arith)
158 requires
159 i0 < 512,
160 i1 < 512,
161 ;
162 } else if path.len() == 3 {
163 let i0 = path.index(0);
164 let i1 = path.index(1);
165 let i2 = path.index(2);
166 assert(0 <= i0 < NR_ENTRIES);
167 assert(0 <= i1 < NR_ENTRIES);
168 assert(0 <= i2 < NR_ENTRIES);
169 assert(rec_vaddr(path, 3) == 0);
170 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2) as usize);
171 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
172 2,
173 i2,
174 )) as usize);
175 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
176 1,
177 i1,
178 ) + vaddr_make::<NR_LEVELS>(2, i2)) as usize);
179 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
180 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
181 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
182 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
183 < 0x1_0000_0000_0000int) by (nonlinear_arith)
184 requires
185 i0 < 512,
186 i1 < 512,
187 i2 < 512,
188 ;
189 } else {
190 assert(path.len() == 4);
191 let i0 = path.index(0);
192 let i1 = path.index(1);
193 let i2 = path.index(2);
194 let i3 = path.index(3);
195 assert(0 <= i0 < NR_ENTRIES);
196 assert(0 <= i1 < NR_ENTRIES);
197 assert(0 <= i2 < NR_ENTRIES);
198 assert(0 <= i3 < NR_ENTRIES);
199 assert(rec_vaddr(path, 4) == 0);
200 assert(rec_vaddr(path, 3) == vaddr_make::<NR_LEVELS>(3, i3) as usize);
201 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(
202 3,
203 i3,
204 )) as usize);
205 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
206 2,
207 i2,
208 ) + vaddr_make::<NR_LEVELS>(3, i3)) as usize);
209 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
210 1,
211 i1,
212 ) + vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(3, i3)) as usize);
213 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
214 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
215 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
216 assert(vaddr_make::<NR_LEVELS>(3, i3) == 0x1000usize * i3) by (compute);
217 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2 + 0x1000usize
218 * i3 < 0x1_0000_0000_0000int) by (nonlinear_arith)
219 requires
220 i0 < 512,
221 i1 < 512,
222 i2 < 512,
223 i3 < 512,
224 ;
225 }
226}
227
228pub proof fn lemma_vaddr_of_eq_int<C: PageTableConfig>(path: TreePath<NR_ENTRIES>)
232 requires
233 path.inv(),
234 path.len() <= INC_LEVELS - 1,
235 ensures
236 vaddr_of::<C>(path) as int == vaddr(path) as int + C::LEADING_BITS_spec() as int
237 * 0x1_0000_0000_0000int,
238{
239 axiom_leading_bits_bounded::<C>();
240 lemma_vaddr_strict_bound(path);
241 let lb = C::LEADING_BITS_spec() as int;
242 let v = vaddr(path) as int;
243 assert(0 <= v);
245 assert(lb * 0x1_0000_0000_0000int <= 0xffff_int * 0x1_0000_0000_0000int) by (nonlinear_arith)
246 requires
247 lb < 0x1_0000int,
248 lb >= 0,
249 ;
250 assert(v + lb * 0x1_0000_0000_0000int < 0x1_0000_0000_0000_0000int) by (nonlinear_arith)
251 requires
252 v < 0x1_0000_0000_0000int,
253 lb < 0x1_0000int,
254 lb >= 0,
255 ;
256}
257
258pub proof fn page_size_monotonic(a: PagingLevel, b: PagingLevel)
260 requires
261 1 <= a <= NR_LEVELS + 1,
262 1 <= b <= NR_LEVELS + 1,
263 a <= b,
264 ensures
265 page_size(a) <= page_size(b),
266{
267 if a == b {
268 } else {
269 let ps_a = page_size(a);
270 let ps_b = page_size(b);
271
272 assert(ps_a == page_size_spec(a));
273 assert(ps_b == page_size_spec(b));
274
275 lemma_page_size_ge_page_size(a);
276 lemma_page_size_ge_page_size(b);
277 assert(ps_a > 0);
278 assert(ps_b > 0);
279
280 lemma_page_size_divides(a, b);
281 assert(ps_b % ps_a == 0);
282
283 assert(ps_a <= ps_b) by {
284 if ps_b < ps_a {
285 vstd::arithmetic::div_mod::lemma_small_mod(ps_b as nat, ps_a as nat);
286 assert(ps_b % ps_a == ps_b);
287 assert(ps_b % ps_a == 0);
288 assert(false);
289 }
290 }
291 }
292}
293
294pub proof fn sibling_paths_disjoint<C: PageTableConfig>(
301 prefix: TreePath<NR_ENTRIES>,
302 j: usize,
303 k: usize,
304 size: usize,
305)
306 requires
307 prefix.inv(),
308 prefix.len() < INC_LEVELS - 1,
309 j < NR_ENTRIES,
310 k < NR_ENTRIES,
311 j != k,
312 size == page_size((INC_LEVELS - prefix.len() - 1) as PagingLevel),
313 ensures
314 vaddr(prefix.push_tail(j)) + size <= vaddr(prefix.push_tail(k)) || vaddr(
315 prefix.push_tail(k),
316 ) + size <= vaddr(prefix.push_tail(j)),
317{
318 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, j);
319 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, k);
320 let s = size as int;
321 let vp = vaddr(prefix) as int;
322 let vj = vaddr(prefix.push_tail(j)) as int;
323 let vk = vaddr(prefix.push_tail(k)) as int;
324 if j < k {
325 assert(vj + s <= vk) by (nonlinear_arith)
326 requires
327 vj == vp + (j as int) * s,
328 vk == vp + (k as int) * s,
329 j < k,
330 s >= 0,
331 ;
332 } else {
333 assert(vk + s <= vj) by (nonlinear_arith)
334 requires
335 vj == vp + (j as int) * s,
336 vk == vp + (k as int) * s,
337 k < j,
338 s >= 0,
339 ;
340 }
341}
342
343impl<C: PageTableConfig, const L: usize> TreeNodeValue<L> for EntryOwner<C> {
344 open spec fn default(lv: nat) -> Self {
345 Self {
346 in_scope: false,
347 path: TreePath::new(Seq::empty()),
348 parent_level: (INC_LEVELS - lv) as PagingLevel,
349 node: None,
350 frame: None,
351 locked: None,
352 borrowed: None,
353 absent: true,
354 }
355 }
356
357 proof fn default_preserves_inv() {
358 }
359
360 open spec fn la_inv(self, lv: nat) -> bool {
361 self.is_node() ==> lv < L - 1
362 }
363
364 proof fn default_preserves_la_inv() {
365 }
366
367 open spec fn rel_children(self, i: int, child: Option<Self>) -> bool {
370 true
371 }
372
373 proof fn default_preserves_rel_children(self, lv: nat) {
374 }
375}
376
377pub const INC_LEVELS: usize = NR_LEVELS + 1;
378
379pub type OwnerSubtree<C> = Node<EntryOwner<C>, NR_ENTRIES, INC_LEVELS>;
389
390pub open spec fn allocated_empty_node_owner<C: PageTableConfig>(
399 owner: OwnerSubtree<C>,
400 level: PagingLevel,
401) -> bool {
402 &&& owner.inv()
403 &&& owner.value.is_node()
404 &&& owner.value.in_scope
409 &&& owner.value.path == TreePath::<NR_ENTRIES>::new(Seq::empty())
410 &&& owner.value.parent_level == (level + 1) as PagingLevel
411 &&& owner.value.node.unwrap().level == level
412 &&& owner.value.node.unwrap().inv()
413 &&& !owner.value.node.unwrap().children_perm.value().all(|child: C::E| child.is_present())
414 &&& forall|i: int|
415 #![auto]
416 0 <= i < NR_ENTRIES ==> {
417 &&& owner.children[i] is Some
418 &&& owner.children[i].unwrap().value.is_absent()
419 &&& !owner.children[i].unwrap().value.in_scope
420 &&& owner.children[i].unwrap().value.inv()
421 &&& owner.children[i].unwrap().value.path == owner.value.path.push_tail(i as usize)
422 }
423 &&& forall|i: int|
424 #![auto]
425 0 <= i < NR_ENTRIES ==> owner.children[i].unwrap().value.match_pte(
426 owner.value.node.unwrap().children_perm.value()[i],
427 owner.children[i].unwrap().value.parent_level,
428 )
429 &&& forall|i: int|
430 #![auto]
431 0 <= i < NR_ENTRIES ==> owner.children[i].unwrap().value.parent_level
432 == owner.value.node.unwrap().level
433 &&& forall|j: int|
438 0 <= j < NR_ENTRIES ==> #[trigger] owner.value.node.unwrap().children_perm.value()[j]
439 == C::E::new_absent_spec()
440}
441
442pub open spec fn allocated_empty_node_grandchildren_none<C: PageTableConfig>(
450 owner: OwnerSubtree<C>,
451) -> bool {
452 forall|i: int, j: int|
453 0 <= i < NR_ENTRIES && 0 <= j < NR_ENTRIES
454 ==> #[trigger] owner.children[i].unwrap().children[j] is None
455}
456
457pub proof fn rebase_freshly_allocated_children_at<C: PageTableConfig>(
462 tracked owner: &mut OwnerSubtree<C>,
463 new_path: TreePath<NR_ENTRIES>,
464 i: usize,
465)
466 requires
467 i <= NR_ENTRIES,
468 old(owner).children.len() == NR_ENTRIES,
469 new_path.inv(),
470 forall|j: int| i <= j < NR_ENTRIES ==> (#[trigger] old(owner).children[j]) is Some,
471 ensures
472 final(owner).value == old(owner).value,
473 final(owner).level == old(owner).level,
474 final(owner).children.len() == NR_ENTRIES,
475 forall|j: int|
476 0 <= j < i ==> (#[trigger] final(owner).children[j]) == old(owner).children[j],
477 forall|j: int|
478 i <= j < NR_ENTRIES ==> {
479 let c_old = old(owner).children[j].unwrap();
480 let c_new = (#[trigger] final(owner).children[j]).unwrap();
481 &&& final(owner).children[j] is Some
482 &&& c_new.value == EntryOwner {
483 path: new_path.push_tail(j as usize),
484 ..c_old.value
485 }
486 &&& c_new.level == c_old.level
487 &&& c_new.children == c_old.children
488 },
489 decreases NR_ENTRIES - i as int,
490{
491 if i < NR_ENTRIES {
492 let tracked mut child_opt = owner.children.tracked_remove(i as int);
493 let tracked mut child = child_opt.tracked_unwrap();
494 child.value.set_path_axiom(new_path.push_tail(i));
495 owner.children.tracked_insert(i as int, Some(child));
496 rebase_freshly_allocated_children_at(owner, new_path, (i + 1) as usize);
497 }
498}
499
500pub proof fn rebase_freshly_allocated_children<C: PageTableConfig>(
510 tracked owner: &mut OwnerSubtree<C>,
511 new_path: TreePath<NR_ENTRIES>,
512)
513 requires
514 old(owner).children.len() == NR_ENTRIES,
515 new_path.inv(),
516 forall|i: int| 0 <= i < NR_ENTRIES ==> (#[trigger] old(owner).children[i]) is Some,
517 ensures
518 final(owner).value == old(owner).value,
519 final(owner).level == old(owner).level,
520 final(owner).children.len() == NR_ENTRIES,
521 forall|i: int|
522 0 <= i < NR_ENTRIES ==> {
523 let c_old = old(owner).children[i].unwrap();
524 let c_new = (#[trigger] final(owner).children[i]).unwrap();
525 &&& final(owner).children[i] is Some
526 &&& c_new.value == EntryOwner {
527 path: new_path.push_tail(i as usize),
528 ..c_old.value
529 }
530 &&& c_new.level == c_old.level
531 &&& c_new.children == c_old.children
532 },
533{
534 rebase_freshly_allocated_children_at(owner, new_path, 0);
535}
536
537pub tracked struct PageTableOwner<C: PageTableConfig>(pub OwnerSubtree<C>);
538
539impl<C: PageTableConfig> PageTableOwner<C> {
540 pub open spec fn pt_edge_at(parent: OwnerSubtree<C>, i: int) -> bool {
542 &&& parent.children[i] is Some
543 &&& parent.children[i].unwrap().value.path.len() == parent.value.node.unwrap().tree_level
544 + 1
545 &&& parent.children[i].unwrap().value.match_pte(
546 parent.value.node.unwrap().children_perm.value()[i],
547 parent.value.node.unwrap().level,
548 )
549 &&& parent.children[i].unwrap().value.path == parent.value.path.push_tail(i as usize)
550 &&& parent.children[i].unwrap().value.parent_level == parent.value.node.unwrap().level
551 }
552
553 pub open spec fn pt_inv_at_depth(self, depth: nat) -> bool
557 decreases depth,
558 {
559 if depth == 0 {
560 true
561 } else if self.0.value.is_node() {
562 forall|i: int|
563 #![trigger self.0.children[i]]
564 0 <= i < NR_ENTRIES ==> Self::pt_edge_at(self.0, i) && PageTableOwner(
565 self.0.children[i].unwrap(),
566 ).pt_inv_at_depth((depth - 1) as nat)
567 } else {
568 forall|i: int|
569 #![trigger self.0.children[i]]
570 0 <= i < NR_ENTRIES ==> self.0.children[i] is None
571 }
572 }
573
574 pub open spec fn pt_inv(self) -> bool {
579 &&& self.0.inv()
580 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level) as nat)
581 }
582
583 pub proof fn pt_inv_unroll(self, i: int)
584 requires
585 self.pt_inv(),
586 self.0.value.is_node(),
587 0 <= i < NR_ENTRIES,
588 ensures
589 Self::pt_edge_at(self.0, i),
590 PageTableOwner(self.0.children[i].unwrap()).pt_inv(),
591 {
592 let depth = (INC_LEVELS - self.0.level) as nat;
595 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::la_inv(self.0.value, self.0.level));
596 }
597
598 pub proof fn pt_inv_non_node(self, i: int)
599 requires
600 self.pt_inv(),
601 !self.0.value.is_node(),
602 0 <= i < NR_ENTRIES,
603 ensures
604 self.0.children[i] is None,
605 {
606 let depth = (INC_LEVELS - self.0.level) as nat;
607 if depth == 0 {
608 assert(self.0.level >= INC_LEVELS);
609 }
610 }
611
612 pub proof fn non_node_pt_inv_at_depth(self, depth: nat)
616 requires
617 !self.0.value.is_node(),
618 forall|j: int| 0 <= j < NR_ENTRIES ==> #[trigger] self.0.children[j] is None,
619 ensures
620 self.pt_inv_at_depth(depth),
621 decreases depth,
622 {
623 if depth == 0 {
624 } else {
625 }
626 }
627
628 #[verifier::spinoff_prover]
637 pub proof fn allocated_empty_node_pt_inv(owner: OwnerSubtree<C>)
638 requires
639 owner.inv(),
640 owner.value.is_node(),
641 owner.children.len() == NR_ENTRIES,
642 forall|i: int|
643 0 <= i < NR_ENTRIES ==> {
644 let c = #[trigger] owner.children[i];
645 &&& c is Some
646 &&& c.unwrap().value.is_absent()
647 &&& c.unwrap().value.path.len() == owner.value.node.unwrap().tree_level + 1
648 &&& c.unwrap().value.match_pte(
649 owner.value.node.unwrap().children_perm.value()[i],
650 owner.value.node.unwrap().level,
651 )
652 &&& c.unwrap().value.path == owner.value.path.push_tail(i as usize)
653 &&& c.unwrap().value.parent_level == owner.value.node.unwrap().level
654 },
655 allocated_empty_node_grandchildren_none(owner),
656 ensures
657 PageTableOwner(owner).pt_inv(),
658 {
659 let depth = (INC_LEVELS - owner.level) as nat;
660 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::la_inv(owner.value, owner.level));
662 assert forall|i: int| 0 <= i < NR_ENTRIES implies #[trigger] Self::pt_edge_at(owner, i)
665 && PageTableOwner(owner.children[i].unwrap()).pt_inv_at_depth((depth - 1) as nat) by {
666 let child = owner.children[i].unwrap();
667 assert(Self::pt_edge_at(owner, i));
669 assert(child.inv());
673 assert(child.value.inv());
674 assert(child.value.inv_base());
675 assert(!child.value.is_node());
676 PageTableOwner(child).non_node_pt_inv_at_depth((depth - 1) as nat);
679 };
680 }
681
682 pub open spec fn top_level_indices_absent(self) -> bool {
687 let range = C::TOP_LEVEL_INDEX_RANGE_spec();
688 self.0.value.is_node() ==> forall|i: int|
689 #![trigger self.0.children[i]]
690 0 <= i < NR_ENTRIES && !(range.start <= i < range.end) ==> self.0.children[i] is Some
691 && self.0.children[i].unwrap().value.is_absent()
692 }
693
694 pub open spec fn view_rec(self, path: TreePath<NR_ENTRIES>) -> Set<Mapping>
695 decreases INC_LEVELS - path.len(),
696 when self.0.inv() && path.len() <= INC_LEVELS - 1
697 {
698 if self.0.value.is_frame() {
699 let va = vaddr_of::<C>(path);
700 let pt_level = INC_LEVELS - path.len();
701 let page_size = page_size(pt_level as PagingLevel);
702
703 set![Mapping {
704 va_range: Range { start: va as int, end: va as int + page_size as int },
705 pa_range: Range {
706 start: self.0.value.frame.unwrap().mapped_pa,
707 end: (self.0.value.frame.unwrap().mapped_pa + page_size) as Paddr,
708 },
709 page_size: page_size,
710 property: self.0.value.frame.unwrap().prop,
711 }]
712 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
713 Set::new(
714 |m: Mapping|
715 exists|i: int|
716 #![trigger self.0.children[i]]
717 0 <= i < self.0.children.len() && self.0.children[i] is Some
718 && PageTableOwner(self.0.children[i].unwrap()).view_rec(
719 path.push_tail(i as usize),
720 ).contains(m),
721 )
722 } else {
723 set![]
724 }
725 }
726
727 pub proof fn view_rec_contains(self, path: TreePath<NR_ENTRIES>, m: Mapping)
728 requires
729 self.0.inv(),
730 path.len() < INC_LEVELS - 1,
731 path.len() == self.0.level,
732 self.view_rec(path).contains(m),
733 self.0.value.is_node(),
734 ensures
735 exists|i: int|
736 #![auto]
737 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
738 self.0.children[i].unwrap(),
739 ).view_rec(path.push_tail(i as usize)).contains(m),
740 {
741 }
742
743 pub proof fn view_rec_contains_choose(self, path: TreePath<NR_ENTRIES>, m: Mapping) -> (i: int)
744 requires
745 self.0.inv(),
746 path.len() < INC_LEVELS - 1,
747 path.len() == self.0.level,
748 self.view_rec(path).contains(m),
749 self.0.value.is_node(),
750 ensures
751 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
752 self.0.children[i].unwrap(),
753 ).view_rec(path.push_tail(i as usize)).contains(m),
754 {
755 choose|i: int|
756 #![auto]
757 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
758 self.0.children[i].unwrap(),
759 ).view_rec(path.push_tail(i as usize)).contains(m)
760 }
761
762 #[verifier::rlimit(400)]
764 pub proof fn lemma_vaddr_push_tail_eq(path: TreePath<NR_ENTRIES>, i: usize)
765 requires
766 path.inv(),
767 path.len() < INC_LEVELS - 1,
768 i < NR_ENTRIES,
769 ensures
770 vaddr(path.push_tail(i)) as int == vaddr(path) as int + (i as int) * (page_size(
771 (INC_LEVELS - path.len() - 1) as PagingLevel,
772 ) as int),
773 vaddr(path) as int + (i as int + 1) * (page_size(
774 (INC_LEVELS - path.len() - 1) as PagingLevel,
775 ) as int) <= usize::MAX as int,
776 {
777 broadcast use TreePath::push_tail_property;
778 broadcast use TreePath::index_satisfies_elem_inv;
779
780 lemma_page_size_spec_values();
781 vstd::arithmetic::power2::lemma2_to64();
782 vstd::arithmetic::power2::lemma2_to64_rest();
783 let pt = path.push_tail(i);
784 if path.len() >= 1 {
785 Self::lemma_vaddr_path_alignment_and_bound(path);
786 }
787 if path.len() == 0 {
788 assert(rec_vaddr(path, 0) == 0);
789 assert(pt.len() == 1);
790 assert(rec_vaddr(pt, 1) == 0);
791 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i) + 0) as usize);
792 assert(vaddr_make::<NR_LEVELS>(0, i) == 0x80_0000_0000usize * i) by (compute);
793 assert(page_size(4) == 0x80_0000_0000usize);
794 assert(0x80_0000_0000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
795 requires
796 i < 512,
797 ;
798 } else if path.len() == 1 {
799 let i0 = path.index(0);
800 assert(0 <= i0 < NR_ENTRIES);
801 assert(rec_vaddr(path, 1) == 0);
802 assert(rec_vaddr(path, 0) == vaddr_make::<NR_LEVELS>(0, i0) as usize);
803 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
804 assert(rec_vaddr(path, 0) == 0x80_0000_0000usize * i0);
805 assert(pt.len() == 2);
806 assert(pt.index(0) == i0);
807 assert(pt.index(1) == i);
808 assert(rec_vaddr(pt, 2) == 0);
809 assert(rec_vaddr(pt, 1) == vaddr_make::<NR_LEVELS>(1, i) as usize);
810 assert(vaddr_make::<NR_LEVELS>(1, i) == 0x4000_0000usize * i) by (compute);
811 assert(rec_vaddr(pt, 0) as int == (0x80_0000_0000usize * i0) as int + (0x4000_0000usize
812 * i) as int);
813 assert(page_size(3) == 0x4000_0000usize);
814 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * (i + 1) <= usize::MAX)
815 by (nonlinear_arith)
816 requires
817 i0 < 512,
818 i < 512,
819 ;
820 } else if path.len() == 2 {
821 let i0 = path.index(0);
822 let i1 = path.index(1);
823 assert(0 <= i0 < NR_ENTRIES);
824 assert(0 <= i1 < NR_ENTRIES);
825 assert(rec_vaddr(path, 2) == 0);
826 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1) as usize);
827 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
828 1,
829 i1,
830 )) as usize);
831 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
832 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
833 assert(pt.len() == 3);
834 assert(pt.index(0) == i0);
835 assert(pt.index(1) == i1);
836 assert(pt.index(2) == i);
837 assert(rec_vaddr(pt, 3) == 0);
838 assert(rec_vaddr(pt, 2) == vaddr_make::<NR_LEVELS>(2, i) as usize);
839 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
840 2,
841 i,
842 )) as usize);
843 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
844 1,
845 i1,
846 ) + vaddr_make::<NR_LEVELS>(2, i)) as usize);
847 assert(vaddr_make::<NR_LEVELS>(2, i) == 0x20_0000usize * i) by (compute);
848 assert(page_size(2) == 0x20_0000usize);
849 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * (i + 1)
850 <= usize::MAX) by (nonlinear_arith)
851 requires
852 i0 < 512,
853 i1 < 512,
854 i < 512,
855 ;
856 } else {
857 assert(path.len() == 3);
858 let i0 = path.index(0);
859 let i1 = path.index(1);
860 let i2 = path.index(2);
861 assert(0 <= i0 < NR_ENTRIES);
862 assert(0 <= i1 < NR_ENTRIES);
863 assert(0 <= i2 < NR_ENTRIES);
864 assert(rec_vaddr(path, 3) == 0);
865 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2) as usize);
866 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
867 2,
868 i2,
869 )) as usize);
870 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
871 1,
872 i1,
873 ) + vaddr_make::<NR_LEVELS>(2, i2)) as usize);
874 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
875 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
876 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
877 assert(pt.len() == 4);
878 assert(pt.index(0) == i0);
879 assert(pt.index(1) == i1);
880 assert(pt.index(2) == i2);
881 assert(pt.index(3) == i);
882 assert(rec_vaddr(pt, 4) == 0);
883 assert(rec_vaddr(pt, 3) == vaddr_make::<NR_LEVELS>(3, i) as usize);
884 assert(rec_vaddr(pt, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(
885 3,
886 i,
887 )) as usize);
888 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
889 2,
890 i2,
891 ) + vaddr_make::<NR_LEVELS>(3, i)) as usize);
892 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
893 1,
894 i1,
895 ) + vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(3, i)) as usize);
896 assert(vaddr_make::<NR_LEVELS>(3, i) == 0x1000usize * i) by (compute);
897 assert(page_size(1) == 0x1000usize);
898 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
899 + 0x1000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
900 requires
901 i0 < 512,
902 i1 < 512,
903 i2 < 512,
904 i < 512,
905 ;
906 }
907 }
908
909 pub proof fn view_rec_vaddr_range(self, path: TreePath<NR_ENTRIES>, m: Mapping)
910 requires
911 self.pt_inv(),
912 path.inv(),
913 path.len() <= INC_LEVELS - 1,
914 path.len() == self.0.level,
915 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
916 self.view_rec(path).contains(m),
917 ensures
918 vaddr_of::<C>(path) as int <= m.va_range.start,
919 m.va_range.start < m.va_range.end,
920 m.va_range.end <= vaddr_of::<C>(path) as int + page_size(
921 (INC_LEVELS - path.len()) as PagingLevel,
922 ) as int,
923 decreases INC_LEVELS - path.len(),
924 {
925 lemma_page_size_spec_values();
926 if self.0.value.is_frame() {
927 Self::lemma_vaddr_path_alignment_and_bound(path);
928 let frame = self.0.value.frame.unwrap();
929 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
930 let expected = Mapping {
931 va_range: Range {
932 start: vaddr_of::<C>(path) as int,
933 end: vaddr_of::<C>(path) as int + page_size(pt_level) as int,
934 },
935 pa_range: Range {
936 start: frame.mapped_pa,
937 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
938 },
939 page_size: page_size(pt_level),
940 property: frame.prop,
941 };
942 assert(self.view_rec(path) =~= set![expected]);
943 assert(m == expected);
944 assert(page_size(pt_level) > 0);
945 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
946 let i = choose|i: int|
947 #![trigger self.0.children[i]]
948 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
949 self.0.children[i].unwrap(),
950 ).view_rec(path.push_tail(i as usize)).contains(m);
951 self.pt_inv_unroll(i);
952 let child = PageTableOwner(self.0.children[i].unwrap());
953 path.push_tail_preserves_inv(i as usize);
954 path.push_tail_property_len(i as usize);
955 child.view_rec_vaddr_range(path.push_tail(i as usize), m);
956 Self::lemma_vaddr_push_tail_eq(path, i as usize);
957
958 let parent_ps = page_size((INC_LEVELS - path.len()) as PagingLevel) as int;
959 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel) as int;
960 vstd::arithmetic::power2::lemma2_to64();
961 vstd::arithmetic::power2::lemma2_to64_rest();
962 if path.len() == 0 {
963 assert(parent_ps == 0x1_0000_0000_0000);
964 assert(child_ps == 0x80_0000_0000);
965 } else if path.len() == 1 {
966 assert(parent_ps == 0x80_0000_0000);
967 assert(child_ps == 0x4000_0000);
968 } else if path.len() == 2 {
969 assert(parent_ps == 0x4000_0000);
970 assert(child_ps == 0x20_0000);
971 } else {
972 assert(path.len() == 3);
973 assert(parent_ps == 0x20_0000);
974 assert(child_ps == 0x1000);
975 }
976 assert(parent_ps == 512 * child_ps) by (nonlinear_arith)
977 requires
978 (parent_ps == 0x1_0000_0000_0000 && child_ps == 0x80_0000_0000) || (parent_ps
979 == 0x80_0000_0000 && child_ps == 0x4000_0000) || (parent_ps == 0x4000_0000
980 && child_ps == 0x20_0000) || (parent_ps == 0x20_0000 && child_ps == 0x1000),
981 ;
982 assert((i + 1) * child_ps <= 512 * child_ps) by (nonlinear_arith)
983 requires
984 0 <= i < 512,
985 child_ps >= 0,
986 ;
987 assert(m.va_range.end <= vaddr_of::<C>(path.push_tail(i as usize)) as int + child_ps);
988 assert(vaddr(path.push_tail(i as usize)) == vaddr(path) + i * child_ps);
989 lemma_vaddr_of_eq_int::<C>(path);
993 lemma_vaddr_of_eq_int::<C>(path.push_tail(i as usize));
994 assert(vaddr_of::<C>(path.push_tail(i as usize)) as int == vaddr_of::<C>(path) as int
995 + i * child_ps);
996 assert(i * child_ps + child_ps == (i + 1) * child_ps) by (nonlinear_arith);
997 assert(m.va_range.end <= vaddr_of::<C>(path) as int + (i + 1) * child_ps);
998 assert(m.va_range.end <= vaddr_of::<C>(path) as int + parent_ps);
999 }
1000 }
1001
1002 pub proof fn pt_inv_implies_path_correct(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
1010 requires
1011 PageTableOwner(subtree).pt_inv(),
1012 subtree.value.path == path,
1013 ensures
1014 subtree.tree_predicate_map(path, Self::path_correct_pred()),
1015 decreases INC_LEVELS - subtree.level,
1016 {
1017 assert(subtree.children.len() == NR_ENTRIES);
1018 assert(Self::path_correct_pred()(subtree.value, path));
1020 if subtree.level < INC_LEVELS - 1 {
1021 assert forall|i: int|
1022 0 <= i < subtree.children.len() && (
1023 #[trigger] subtree.children[i]) is Some implies subtree.children[i].unwrap().tree_predicate_map(
1024 path.push_tail(i as usize), Self::path_correct_pred()) by {
1025 if subtree.value.is_node() {
1026 PageTableOwner(subtree).pt_inv_unroll(i);
1027 assert(subtree.children[i].unwrap().value.path == path.push_tail(i as usize));
1029 Self::pt_inv_implies_path_correct(
1030 subtree.children[i].unwrap(),
1031 path.push_tail(i as usize),
1032 );
1033 } else {
1034 PageTableOwner(subtree).pt_inv_non_node(i);
1036 }
1037 };
1038 }
1039 }
1040
1041 pub proof fn no_frame_with_path_rec(
1051 self,
1052 path: TreePath<NR_ENTRIES>,
1053 removed_path: TreePath<NR_ENTRIES>,
1054 ambient: Set<Mapping>,
1055 )
1056 requires
1057 self.pt_inv(),
1058 path.inv(),
1059 path.len() <= INC_LEVELS - 1,
1060 path.len() == self.0.level,
1061 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1062 self.0.value.path == path,
1063 self.0.tree_predicate_map(path, Self::path_correct_pred()),
1064 forall|mm: Mapping|
1065 #![trigger self.view_rec(path).contains(mm)]
1066 self.view_rec(path).contains(mm) ==> ambient.contains(mm),
1067 forall|mm: Mapping|
1068 #![trigger ambient.contains(mm)]
1069 ambient.contains(mm) ==> mm.va_range.start != vaddr_of::<C>(removed_path) as int,
1070 ensures
1071 self.0.tree_predicate_map(
1072 path,
1073 |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1074 e.is_frame() ==> e.path != removed_path,
1075 ),
1076 decreases INC_LEVELS - path.len(),
1077 {
1078 let g = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1079 e.is_frame() ==> e.path != removed_path;
1080
1081 assert(Self::path_correct_pred()(self.0.value, path));
1083 assert(self.0.value.path == path);
1084
1085 if self.0.value.is_frame() {
1087 let frame = self.0.value.frame.unwrap();
1088 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1089 let expected = Mapping {
1090 va_range: Range {
1091 start: vaddr_of::<C>(path) as int,
1092 end: vaddr_of::<C>(path) as int + page_size(pt_level) as int,
1093 },
1094 pa_range: Range {
1095 start: frame.mapped_pa,
1096 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1097 },
1098 page_size: page_size(pt_level),
1099 property: frame.prop,
1100 };
1101 assert(self.view_rec(path) =~= set![expected]);
1102 assert(self.view_rec(path).contains(expected));
1103 assert(ambient.contains(expected));
1104 assert(vaddr_of::<C>(path) as int != vaddr_of::<C>(removed_path) as int);
1105 assert(self.0.value.path != removed_path);
1106 }
1107 assert(g(self.0.value, path));
1108
1109 if self.0.level < INC_LEVELS - 1 {
1110 assert forall|i: int|
1111 0 <= i < self.0.children.len() && (
1112 #[trigger] self.0.children[i]) is Some implies self.0.children[i].unwrap().tree_predicate_map(
1113 path.push_tail(i as usize), g) by {
1114 if self.0.value.is_node() {
1115 self.pt_inv_unroll(i);
1116 let child = PageTableOwner(self.0.children[i].unwrap());
1117 path.push_tail_preserves_inv(i as usize);
1118 path.push_tail_property_len(i as usize);
1119 assert forall|mm: Mapping|
1121 child.view_rec(path.push_tail(i as usize)).contains(
1122 mm,
1123 ) implies ambient.contains(mm) by {
1124 assert(self.view_rec(path).contains(mm));
1125 };
1126 self.0.map_unroll_once(path, Self::path_correct_pred(), i);
1128 child.no_frame_with_path_rec(path.push_tail(i as usize), removed_path, ambient);
1129 } else {
1130 PageTableOwner(self.0).pt_inv_non_node(i);
1131 }
1132 };
1133 }
1134 assert(self.0.tree_predicate_map(path, g));
1135 }
1136
1137 pub proof fn view_rec_disjoint_vaddrs(
1138 self,
1139 path: TreePath<NR_ENTRIES>,
1140 m1: Mapping,
1141 m2: Mapping,
1142 )
1143 requires
1144 self.pt_inv(),
1145 path.inv(),
1146 path.len() <= INC_LEVELS - 1,
1147 path.len() == self.0.level,
1148 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1149 self.view_rec(path).contains(m1),
1150 self.view_rec(path).contains(m2),
1151 m1 != m2,
1152 ensures
1153 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start,
1154 decreases INC_LEVELS - path.len(),
1155 {
1156 broadcast use group_set_properties;
1157
1158 if self.0.value.is_frame() {
1159 assert(self.view_rec(path).is_singleton());
1160 } else if self.0.value.is_node() {
1161 self.view_rec_contains(path, m1);
1162 self.view_rec_contains(path, m2);
1163
1164 let i1 = self.view_rec_contains_choose(path, m1);
1165 let i2 = self.view_rec_contains_choose(path, m2);
1166
1167 path.push_tail_preserves_inv(i1 as usize);
1168 path.push_tail_preserves_inv(i2 as usize);
1169 path.push_tail_property_len(i1 as usize);
1170 path.push_tail_property_len(i2 as usize);
1171
1172 if i1 == i2 {
1173 self.pt_inv_unroll(i1);
1174 PageTableOwner(self.0.children[i1].unwrap()).view_rec_disjoint_vaddrs(
1175 path.push_tail(i1 as usize),
1176 m1,
1177 m2,
1178 );
1179 } else {
1180 self.pt_inv_unroll(i1);
1181 self.pt_inv_unroll(i2);
1182 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel);
1183 PageTableOwner(self.0.children[i1].unwrap()).view_rec_vaddr_range(
1184 path.push_tail(i1 as usize),
1185 m1,
1186 );
1187 PageTableOwner(self.0.children[i2].unwrap()).view_rec_vaddr_range(
1188 path.push_tail(i2 as usize),
1189 m2,
1190 );
1191 if i1 < i2 {
1192 sibling_paths_disjoint::<C>(path, i1 as usize, i2 as usize, child_ps);
1193 } else {
1194 sibling_paths_disjoint::<C>(path, i2 as usize, i1 as usize, child_ps);
1195 }
1196 lemma_vaddr_of_eq_int::<C>(path.push_tail(i1 as usize));
1200 lemma_vaddr_of_eq_int::<C>(path.push_tail(i2 as usize));
1201 }
1202 }
1203 }
1204
1205 pub proof fn view_rec_finite(self, path: TreePath<NR_ENTRIES>)
1209 requires
1210 self.0.inv(),
1211 path.len() <= INC_LEVELS - 1,
1212 path.len() == self.0.level,
1213 ensures
1214 self.view_rec(path).finite(),
1215 decreases INC_LEVELS - path.len(),
1216 {
1217 broadcast use group_set_properties;
1218
1219 if self.0.value.is_frame() {
1220 assert(self.view_rec(path).finite());
1222 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1223 assert forall|i: int|
1225 0 <= i < NR_ENTRIES && #[trigger] self.0.children[i] is Some implies PageTableOwner(
1226 self.0.children[i].unwrap(),
1227 ).view_rec(path.push_tail(i as usize)).finite() by {
1228 let child = self.0.children[i].unwrap();
1229 PageTableOwner(child).view_rec_finite(path.push_tail(i as usize));
1232 };
1233
1234 let f = |i: int| -> Set<Mapping>
1236 {
1237 if 0 <= i < NR_ENTRIES && self.0.children[i] is Some {
1238 PageTableOwner(self.0.children[i].unwrap()).view_rec(
1239 path.push_tail(i as usize),
1240 )
1241 } else {
1242 Set::<Mapping>::empty()
1243 }
1244 };
1245 let dom: Set<int> = Set::new(|i: int| 0 <= i < NR_ENTRIES);
1246 assert(dom =~= int::range_set(0int, NR_ENTRIES as int));
1247 vstd::set_lib::range_set_properties::<int>(0int, NR_ENTRIES as int);
1248 assert(dom.finite());
1249 dom.lemma_map_finite(f);
1250 let ss = dom.map(f);
1251 assert(ss.finite());
1252
1253 assert forall|s: Set<Mapping>| ss.contains(s) implies #[trigger] s.finite() by {
1255 let i = choose|i: int| dom.contains(i) && f(i) == s;
1256 if 0 <= i < NR_ENTRIES && self.0.children[i] is Some {
1257 } else {
1259 assert(s =~= Set::<Mapping>::empty());
1260 }
1261 };
1262
1263 ss.lemma_flatten_finite();
1264 assert(self.view_rec(path) =~= ss.flatten()) by {
1268 assert forall|m: Mapping|
1269 self.view_rec(path).contains(m) implies #[trigger] ss.flatten().contains(m) by {
1270 let i = choose|i: int|
1271 #![trigger self.0.children[i]]
1272 0 <= i < self.0.children.len() && self.0.children[i] is Some
1273 && PageTableOwner(self.0.children[i].unwrap()).view_rec(
1274 path.push_tail(i as usize),
1275 ).contains(m);
1276 assert(dom.contains(i));
1277 assert(ss.contains(f(i)));
1278 assert(f(i).contains(m));
1279 };
1280 assert forall|m: Mapping| #[trigger] ss.flatten().contains(m) implies self.view_rec(
1281 path,
1282 ).contains(m) by {
1283 let s = choose|s: Set<Mapping>| ss.contains(s) && s.contains(m);
1284 let i = choose|i: int| dom.contains(i) && f(i) == s;
1285 assert(0 <= i < NR_ENTRIES && self.0.children[i] is Some);
1286 };
1287 };
1288 } else {
1289 assert(self.view_rec(path) =~= Set::<Mapping>::empty());
1291 }
1292 }
1293
1294 pub proof fn view_rec_mapping_page_size(self, path: TreePath<NR_ENTRIES>)
1301 requires
1302 self.pt_inv(),
1303 path.len() <= INC_LEVELS - 1,
1304 path.len() == self.0.level,
1305 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1306 ensures
1307 forall|m: Mapping| #[trigger]
1308 self.view_rec(path).contains(m)
1309 ==> set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size),
1310 decreases INC_LEVELS - path.len(),
1311 {
1312 if self.0.value.is_frame() {
1313 lemma_page_size_spec_values();
1314 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1315 assert forall|m: Mapping| #[trigger]
1316 self.view_rec(path).contains(
1317 m,
1318 ) implies set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size) by {
1319 let i = choose|i: int|
1320 #![trigger self.0.children[i]]
1321 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1322 self.0.children[i].unwrap(),
1323 ).view_rec(path.push_tail(i as usize)).contains(m);
1324 self.pt_inv_unroll(i);
1325 let child = self.0.children[i].unwrap();
1326 PageTableOwner(child).view_rec_mapping_page_size(path.push_tail(i as usize));
1327 };
1328 }
1329 }
1330
1331 #[verifier::rlimit(400)]
1338 proof fn lemma_vaddr_path_alignment_and_bound(path: TreePath<NR_ENTRIES>)
1339 requires
1340 path.inv(),
1341 path.len() <= INC_LEVELS - 1,
1342 1 <= INC_LEVELS - path.len() <= NR_LEVELS,
1343 ensures
1344 vaddr(path) % page_size((INC_LEVELS - path.len()) as PagingLevel) == 0,
1345 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= usize::MAX,
1346 {
1347 lemma_page_size_spec_values();
1348 vstd::arithmetic::power2::lemma2_to64();
1349 vstd::arithmetic::power2::lemma2_to64_rest();
1350 broadcast use TreePath::index_satisfies_elem_inv;
1351 if path.len() == 0 {
1363 assert(rec_vaddr(path, 0) == 0);
1364 } else if path.len() == 1 {
1365 let i0 = path.index(0);
1366 assert(0 <= i0 < NR_ENTRIES);
1367 assert(rec_vaddr(path, 1) == 0);
1368 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1369 path,
1370 1,
1371 )) as usize);
1372 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1373 assert(rec_vaddr(path, 0) == 0x80_0000_0000usize * i0);
1374 assert(page_size(4) == 0x80_0000_0000usize);
1375 assert((0x80_0000_0000usize * i0) % 0x80_0000_0000 == 0) by (nonlinear_arith);
1376 assert(0x80_0000_0000usize * i0 + 0x80_0000_0000 <= usize::MAX) by (nonlinear_arith)
1377 requires
1378 i0 < 512,
1379 ;
1380 } else if path.len() == 2 {
1381 let i0 = path.index(0);
1382 let i1 = path.index(1);
1383 assert(0 <= i0 < NR_ENTRIES);
1384 assert(0 <= i1 < NR_ENTRIES);
1385 assert(rec_vaddr(path, 2) == 0);
1386 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(
1387 path,
1388 2,
1389 )) as usize);
1390 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1391 path,
1392 1,
1393 )) as usize);
1394 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1395 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1396 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1) as int;
1397 assert(rec_vaddr(path, 0) == s);
1398 assert(page_size(3) == 0x4000_0000usize);
1399 assert(s % 0x4000_0000 == 0) by (nonlinear_arith)
1400 requires
1401 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1,
1402 ;
1403 assert(s + 0x4000_0000 <= usize::MAX) by (nonlinear_arith)
1404 requires
1405 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1,
1406 i0 < 512,
1407 i1 < 512,
1408 ;
1409 } else if path.len() == 3 {
1410 let i0 = path.index(0);
1411 let i1 = path.index(1);
1412 let i2 = path.index(2);
1413 assert(0 <= i0 < NR_ENTRIES);
1414 assert(0 <= i1 < NR_ENTRIES);
1415 assert(0 <= i2 < NR_ENTRIES);
1416 assert(rec_vaddr(path, 3) == 0);
1417 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + rec_vaddr(
1418 path,
1419 3,
1420 )) as usize);
1421 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(
1422 path,
1423 2,
1424 )) as usize);
1425 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1426 path,
1427 1,
1428 )) as usize);
1429 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1430 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1431 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
1432 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2) as int;
1433 assert(rec_vaddr(path, 0) == s);
1434 assert(page_size(2) == 0x20_0000usize);
1435 assert(s % 0x20_0000 == 0) by (nonlinear_arith)
1436 requires
1437 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2,
1438 ;
1439 assert(s + 0x20_0000 <= usize::MAX) by (nonlinear_arith)
1440 requires
1441 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2,
1442 i0 < 512,
1443 i1 < 512,
1444 i2 < 512,
1445 ;
1446 } else {
1447 assert(path.len() == 4);
1448 let i0 = path.index(0);
1449 let i1 = path.index(1);
1450 let i2 = path.index(2);
1451 let i3 = path.index(3);
1452 assert(0 <= i0 < NR_ENTRIES);
1453 assert(0 <= i1 < NR_ENTRIES);
1454 assert(0 <= i2 < NR_ENTRIES);
1455 assert(0 <= i3 < NR_ENTRIES);
1456 assert(rec_vaddr(path, 4) == 0);
1457 assert(rec_vaddr(path, 3) == (vaddr_make::<NR_LEVELS>(3, i3) + rec_vaddr(
1458 path,
1459 4,
1460 )) as usize);
1461 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + rec_vaddr(
1462 path,
1463 3,
1464 )) as usize);
1465 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(
1466 path,
1467 2,
1468 )) as usize);
1469 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1470 path,
1471 1,
1472 )) as usize);
1473 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1474 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1475 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
1476 assert(vaddr_make::<NR_LEVELS>(3, i3) == 0x1000usize * i3) by (compute);
1477 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
1478 + 0x1000usize * i3) as int;
1479 assert(rec_vaddr(path, 0) == s);
1480 assert(page_size(1) == 0x1000usize);
1481 assert(s % 0x1000 == 0) by (nonlinear_arith)
1482 requires
1483 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3,
1484 ;
1485 assert(s + 0x1000 <= usize::MAX) by (nonlinear_arith)
1486 requires
1487 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3,
1488 i0 < 512,
1489 i1 < 512,
1490 i2 < 512,
1491 i3 < 512,
1492 ;
1493 }
1494 }
1495
1496 pub proof fn view_rec_mapping_inv(self, path: TreePath<NR_ENTRIES>)
1505 requires
1506 self.pt_inv(),
1507 path.inv(),
1508 path.len() <= INC_LEVELS - 1,
1509 path.len() == self.0.level,
1510 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1511 ensures
1512 forall|m: Mapping| #[trigger] self.view_rec(path).contains(m) ==> m.inv(),
1513 decreases INC_LEVELS - path.len(),
1514 {
1515 if self.0.value.is_frame() {
1516 lemma_page_size_spec_values();
1517 let frame = self.0.value.frame.unwrap();
1518 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1519 Self::lemma_vaddr_path_alignment_and_bound(path);
1520 let m = Mapping {
1521 va_range: Range {
1522 start: vaddr_of::<C>(path) as int,
1523 end: vaddr_of::<C>(path) as int + page_size(pt_level) as int,
1524 },
1525 pa_range: Range {
1526 start: frame.mapped_pa,
1527 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1528 },
1529 page_size: page_size(pt_level),
1530 property: frame.prop,
1531 };
1532 assert(self.view_rec(path) =~= set![m]);
1533 assert(set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size));
1534 let ps = page_size(pt_level) as int;
1535 assert(ps > 0);
1536 assert((frame.mapped_pa as int + ps) % ps == 0) by (nonlinear_arith)
1537 requires
1538 (frame.mapped_pa as int) % ps == 0,
1539 ps > 0,
1540 ;
1541 lemma_vaddr_of_eq_int::<C>(path);
1543 axiom_leading_bits_bounded::<C>();
1544 lemma_vaddr_strict_bound(path);
1545 let lb = C::LEADING_BITS_spec() as int;
1546 vstd::arithmetic::power2::lemma2_to64();
1547 vstd::arithmetic::power2::lemma2_to64_rest();
1548 assert(vaddr(path) as int % ps == 0);
1552 assert(lb * 0x1_0000_0000_0000int % ps == 0) by (nonlinear_arith)
1553 requires
1554 lb >= 0,
1555 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int),
1556 ;
1557 vstd::arithmetic::div_mod::lemma_mod_adds(
1558 vaddr(path) as int,
1559 lb * 0x1_0000_0000_0000int,
1560 ps,
1561 );
1562 assert((vaddr_of::<C>(path) as int) % ps == 0);
1563 assert((vaddr_of::<C>(path) as int + ps) % ps == 0) by (nonlinear_arith)
1564 requires
1565 (vaddr_of::<C>(path) as int) % ps == 0,
1566 ps > 0,
1567 ;
1568 let v = vaddr(path) as int;
1571 assert((v % ps) == 0);
1572 assert(v < 0x1_0000_0000_0000int);
1573 assert(v + ps <= 0x1_0000_0000_0000int) by (nonlinear_arith)
1574 requires
1575 v % ps == 0,
1576 v < 0x1_0000_0000_0000int,
1577 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int),
1578 (0x1_0000_0000_0000int % ps == 0),
1579 ;
1580 assert(vaddr_of::<C>(path) as int + ps <= pow2(64)) by (nonlinear_arith)
1581 requires
1582 vaddr_of::<C>(path) as int == v + lb * 0x1_0000_0000_0000int,
1583 v + ps <= 0x1_0000_0000_0000int,
1584 lb < 0x1_0000int,
1585 lb >= 0,
1586 pow2(64) == 0x1_0000_0000_0000_0000int,
1587 ;
1588 assert(m.inv());
1589 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1590 assert forall|m: Mapping| #[trigger]
1591 self.view_rec(path).contains(m) implies m.inv() by {
1592 let i = choose|i: int|
1593 #![trigger self.0.children[i]]
1594 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1595 self.0.children[i].unwrap(),
1596 ).view_rec(path.push_tail(i as usize)).contains(m);
1597 self.pt_inv_unroll(i);
1598 let child = self.0.children[i].unwrap();
1599 path.push_tail_preserves_inv(i as usize);
1600 PageTableOwner(child).view_rec_mapping_inv(path.push_tail(i as usize));
1601 };
1602 }
1603 }
1604
1605 pub proof fn view_rec_absent_empty(self, path: TreePath<NR_ENTRIES>)
1607 requires
1608 self.0.inv(),
1609 self.0.value.is_absent(),
1610 path.len() <= INC_LEVELS - 1,
1611 ensures
1612 self.view_rec(path) =~= set![],
1613 {
1614 }
1615
1616 pub axiom fn view_rec_nr_children_zero_empty(self, path: TreePath<NR_ENTRIES>)
1622 requires
1623 self.0.inv(),
1624 self.0.value.is_node(),
1625 self.0.value.node.unwrap().meta_own.nr_children.value() == 0,
1626 path.len() <= INC_LEVELS - 1,
1627 path.len() == self.0.level,
1628 ensures
1629 self.view_rec(path) =~= set![],
1630 ;
1631
1632 pub open spec fn metaregion_sound_pred(regions: MetaRegionOwners) -> (spec_fn(
1633 EntryOwner<C>,
1634 TreePath<NR_ENTRIES>,
1635 ) -> bool) {
1636 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions)
1637 }
1638
1639 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool
1640 decreases INC_LEVELS - self.0.level,
1641 when self.0.inv()
1642 {
1643 self.0.tree_predicate_map(self.0.value.path, Self::metaregion_sound_pred(regions))
1644 }
1645
1646 pub proof fn metaregion_sound_preserved_slot_owners_eq(
1651 self,
1652 r0: MetaRegionOwners,
1653 r1: MetaRegionOwners,
1654 )
1655 requires
1656 self.inv(),
1657 self.metaregion_sound(r0),
1658 r0.slot_owners == r1.slot_owners,
1659 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1660 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1661 ensures
1662 self.metaregion_sound(r1),
1663 {
1664 Self::metaregion_sound_preserved_slot_owners_eq_subtree(self.0, self.0.value.path, r0, r1);
1665 }
1666
1667 pub proof fn metaregion_sound_preserved_slot_owners_eq_subtree(
1669 subtree: OwnerSubtree<C>,
1670 path: TreePath<NR_ENTRIES>,
1671 r0: MetaRegionOwners,
1672 r1: MetaRegionOwners,
1673 )
1674 requires
1675 subtree.inv(),
1676 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r0)),
1677 r0.slot_owners == r1.slot_owners,
1678 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1679 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1680 ensures
1681 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r1)),
1682 decreases INC_LEVELS - subtree.level,
1683 {
1684 subtree.value.metaregion_sound_slot_owners_only(r0, r1);
1686 if subtree.level < INC_LEVELS - 1 {
1688 assert forall|i: int|
1689 #![trigger subtree.children[i]]
1690 0 <= i < NR_ENTRIES
1691 && subtree.children[i] is Some implies subtree.children[i].unwrap().tree_predicate_map(
1692 path.push_tail(i as usize), Self::metaregion_sound_pred(r1)) by {
1693 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1694 subtree.children[i].unwrap(),
1695 path.push_tail(i as usize),
1696 r0,
1697 r1,
1698 );
1699 }
1700 }
1701 }
1702
1703 pub proof fn metaregion_sound_preserved_one_slot_changed(
1709 self,
1710 r0: MetaRegionOwners,
1711 r1: MetaRegionOwners,
1712 changed_idx: usize,
1713 )
1714 requires
1715 self.inv(),
1716 self.metaregion_sound(r0),
1717 forall|i: usize|
1718 #![trigger r1.slot_owners[i]]
1719 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1720 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
1721 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1722 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1723 self.0.tree_predicate_map(
1725 self.0.value.path,
1726 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1727 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr().unwrap())
1728 != changed_idx,
1729 ),
1730 self.0.tree_predicate_map(
1734 self.0.value.path,
1735 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1736 e.is_frame() && e.parent_level > 1 ==> {
1737 let pa = e.frame.unwrap().mapped_pa;
1738 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1739 forall|j: usize|
1740 0 < j < nr_pages ==> {
1741 let sub_idx = #[trigger] frame_to_index(
1742 (pa + j * PAGE_SIZE) as usize,
1743 );
1744 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1745 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1746 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1747 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0)
1748 }
1749 },
1750 ),
1751 ensures
1752 self.metaregion_sound(r1),
1753 {
1754 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1755 self.0,
1756 self.0.value.path,
1757 r0,
1758 r1,
1759 changed_idx,
1760 );
1761 }
1762
1763 pub proof fn metaregion_sound_preserved_one_slot_changed_subtree(
1764 subtree: OwnerSubtree<C>,
1765 path: TreePath<NR_ENTRIES>,
1766 r0: MetaRegionOwners,
1767 r1: MetaRegionOwners,
1768 changed_idx: usize,
1769 )
1770 requires
1771 subtree.inv(),
1772 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r0)),
1773 forall|i: usize|
1774 #![trigger r1.slot_owners[i]]
1775 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1776 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
1777 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1778 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1779 subtree.tree_predicate_map(
1780 path,
1781 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1782 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr().unwrap())
1783 != changed_idx,
1784 ),
1785 subtree.tree_predicate_map(
1786 path,
1787 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1788 e.is_frame() && e.parent_level > 1 ==> {
1789 let pa = e.frame.unwrap().mapped_pa;
1790 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1791 forall|j: usize|
1792 0 < j < nr_pages ==> {
1793 let sub_idx = #[trigger] frame_to_index(
1794 (pa + j * PAGE_SIZE) as usize,
1795 );
1796 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1797 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1798 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1799 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0)
1800 }
1801 },
1802 ),
1803 ensures
1804 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r1)),
1805 decreases INC_LEVELS - subtree.level,
1806 {
1807 subtree.value.metaregion_sound_one_slot_changed(r0, r1, changed_idx);
1808 if subtree.level < INC_LEVELS - 1 {
1809 assert forall|i: int|
1810 #![trigger subtree.children[i]]
1811 0 <= i < NR_ENTRIES
1812 && subtree.children[i] is Some implies subtree.children[i].unwrap().tree_predicate_map(
1813 path.push_tail(i as usize), Self::metaregion_sound_pred(r1)) by {
1814 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1815 subtree.children[i].unwrap(),
1816 path.push_tail(i as usize),
1817 r0,
1818 r1,
1819 changed_idx,
1820 );
1821 }
1822 }
1823 }
1824
1825 pub open spec fn path_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
1828 EntryOwner<C>,
1829 TreePath<NR_ENTRIES>,
1830 ) -> bool {
1831 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1832 {
1833 entry.is_node() && entry.meta_slot_paddr() is Some ==> {
1835 &&& regions.slot_owners.contains_key(
1836 frame_to_index(entry.meta_slot_paddr().unwrap()),
1837 )
1838 &&& regions.slot_owners[frame_to_index(
1839 entry.meta_slot_paddr().unwrap(),
1840 )].paths_in_pt == set![entry.path]
1841 }
1842 }
1843 }
1844
1845 pub open spec fn relate_region_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
1846 EntryOwner<C>,
1847 TreePath<NR_ENTRIES>,
1848 ) -> bool {
1849 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1850 {
1851 &&& entry.meta_slot_paddr() is Some
1852 &&& regions.slot_owners.contains_key(
1853 frame_to_index(entry.meta_slot_paddr().unwrap()),
1854 )
1855 &&& regions.slot_owners[frame_to_index(
1856 entry.meta_slot_paddr().unwrap(),
1857 )].paths_in_pt == set![path]
1858 }
1859 }
1860
1861 pub open spec fn path_correct_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
1862 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| { entry.path == path }
1863 }
1864
1865 pub open spec fn not_in_scope_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
1866 |entry: EntryOwner<C>, _path: TreePath<NR_ENTRIES>| !entry.in_scope
1867 }
1868
1869 pub proof fn tree_not_in_scope(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
1872 requires
1873 subtree.inv(),
1874 ensures
1875 subtree.tree_predicate_map(path, Self::not_in_scope_pred()),
1876 decreases INC_LEVELS - subtree.level,
1877 {
1878 if subtree.level < INC_LEVELS - 1 {
1880 assert forall|i: int|
1881 0 <= i < subtree.children.len() && (
1882 #[trigger] subtree.children[i]) is Some implies subtree.children[i].unwrap().tree_predicate_map(
1883 path.push_tail(i as usize), Self::not_in_scope_pred()) by {
1884 Self::tree_not_in_scope(subtree.children[i].unwrap(), path.push_tail(i as usize));
1885 };
1886 }
1887 }
1888
1889 pub proof fn view_rec_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1892 requires
1893 self.0.inv(),
1894 path.len() <= INC_LEVELS - 1,
1895 self.view_rec(path).contains(m),
1896 ensures
1897 m.page_size <= page_size((INC_LEVELS - path.len()) as PagingLevel),
1898 decreases INC_LEVELS - path.len(),
1899 {
1900 if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1901 let i = choose|i: int|
1902 #![auto]
1903 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1904 self.0.children[i].unwrap(),
1905 ).view_rec(path.push_tail(i as usize)).contains(m);
1906 PageTableOwner(self.0.children[i].unwrap()).view_rec_page_size_bound(
1907 path.push_tail(i as usize),
1908 m,
1909 );
1910 page_size_monotonic(
1911 (INC_LEVELS - path.len() - 1) as PagingLevel,
1912 (INC_LEVELS - path.len()) as PagingLevel,
1913 );
1914 }
1915 }
1916
1917 pub proof fn view_rec_node_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1920 requires
1921 self.0.inv(),
1922 self.0.value.is_node(),
1923 path.len() < INC_LEVELS - 1,
1924 self.view_rec(path).contains(m),
1925 ensures
1926 m.page_size <= page_size(((INC_LEVELS - path.len()) - 1) as PagingLevel),
1927 decreases INC_LEVELS - path.len(),
1928 {
1929 let i = choose|i: int|
1930 #![auto]
1931 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1932 self.0.children[i].unwrap(),
1933 ).view_rec(path.push_tail(i as usize)).contains(m);
1934 PageTableOwner(self.0.children[i].unwrap()).view_rec_page_size_bound(
1935 path.push_tail(i as usize),
1936 m,
1937 );
1938 }
1939
1940 pub open spec fn is_prefix_of<const N: usize>(prefix: TreePath<N>, path: TreePath<N>) -> bool {
1942 &&& prefix.len() <= path.len()
1943 &&& forall|i: int| 0 <= i < prefix.len() ==> prefix.index(i) == path.index(i)
1944 }
1945
1946 pub proof fn prefix_transitive<const N: usize>(
1948 p1: TreePath<N>,
1949 p2: TreePath<N>,
1950 p3: TreePath<N>,
1951 )
1952 requires
1953 Self::is_prefix_of(p1, p2),
1954 Self::is_prefix_of(p2, p3),
1955 ensures
1956 Self::is_prefix_of(p1, p3),
1957 {
1958 assert(p1.len() <= p3.len());
1959 assert forall|i: int| 0 <= i < p1.len() implies p1.index(i) == p3.index(i) by {
1960 assert(p1.index(i) == p2.index(i));
1961 assert(p2.index(i) == p3.index(i));
1962 };
1963 }
1964
1965 pub proof fn prefix_push_different_indices(
1966 prefix: TreePath<NR_ENTRIES>,
1967 path: TreePath<NR_ENTRIES>,
1968 i: usize,
1969 j: usize,
1970 )
1971 requires
1972 prefix.inv(),
1973 path.inv(),
1974 i != j,
1975 Self::is_prefix_of(prefix.push_tail(i), path),
1976 ensures
1977 !Self::is_prefix_of(prefix.push_tail(j), path),
1978 {
1979 assert(path.index(prefix.len() as int) == i);
1980 }
1981
1982 pub open spec fn is_at_pred(entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>) -> spec_fn(
1983 EntryOwner<C>,
1984 TreePath<NR_ENTRIES>,
1985 ) -> bool {
1986 |entry0: EntryOwner<C>, path0: TreePath<NR_ENTRIES>| { path0 == path ==> entry0 == entry }
1987 }
1988
1989 pub open spec fn path_in_tree_pred(path: TreePath<NR_ENTRIES>) -> spec_fn(
1990 EntryOwner<C>,
1991 TreePath<NR_ENTRIES>,
1992 ) -> bool {
1993 |entry: EntryOwner<C>, path0: TreePath<NR_ENTRIES>|
1994 Self::is_prefix_of(path0, path) ==> !entry.is_node() ==> path == path0
1995 }
1996
1997 pub proof fn is_at_pred_eq(
1998 path: TreePath<NR_ENTRIES>,
1999 entry1: EntryOwner<C>,
2000 entry2: EntryOwner<C>,
2001 )
2002 requires
2003 entry1.inv(),
2004 OwnerSubtree::implies(Self::is_at_pred(entry1, path), Self::is_at_pred(entry2, path)),
2005 ensures
2006 entry1 == entry2,
2007 {
2008 assert(Self::is_at_pred(entry1, path)(entry1, path) ==> Self::is_at_pred(entry2, path)(
2009 entry1,
2010 path,
2011 ));
2012 }
2013
2014 pub proof fn is_at_holds_when_on_wrong_path(
2015 subtree: OwnerSubtree<C>,
2016 root_path: TreePath<NR_ENTRIES>,
2017 dest_path: TreePath<NR_ENTRIES>,
2018 entry: EntryOwner<C>,
2019 )
2020 requires
2021 subtree.inv(),
2022 PageTableOwner(subtree).pt_inv(),
2023 dest_path.inv(),
2024 !Self::is_prefix_of(root_path, dest_path),
2025 root_path.len() <= INC_LEVELS - 1,
2026 root_path.len() == subtree.level,
2027 ensures
2028 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry, dest_path)),
2029 decreases INC_LEVELS - root_path.len(),
2030 {
2031 if subtree.level < INC_LEVELS - 1 {
2032 if subtree.value.is_node() {
2033 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2034 #[trigger] subtree.children[i as int]).unwrap().tree_predicate_map(
2035 root_path.push_tail(i as usize),
2036 Self::is_at_pred(entry, dest_path),
2037 ) by {
2038 PageTableOwner(subtree).pt_inv_unroll(i);
2039 Self::is_at_holds_when_on_wrong_path(
2040 subtree.children[i as int].unwrap(),
2041 root_path.push_tail(i as usize),
2042 dest_path,
2043 entry,
2044 );
2045 };
2046 } else {
2047 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2048 #[trigger] subtree.children[i as int]) is None by {
2049 PageTableOwner(subtree).pt_inv_non_node(i);
2050 };
2051 }
2052 }
2053 }
2054
2055 pub proof fn path_in_tree_holds_when_on_wrong_path(
2059 subtree: OwnerSubtree<C>,
2060 root_path: TreePath<NR_ENTRIES>,
2061 dest_path: TreePath<NR_ENTRIES>,
2062 )
2063 requires
2064 subtree.inv(),
2065 PageTableOwner(subtree).pt_inv(),
2066 dest_path.inv(),
2067 !Self::is_prefix_of(root_path, dest_path),
2068 root_path.len() <= INC_LEVELS - 1,
2069 root_path.len() == subtree.level,
2070 ensures
2071 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
2072 decreases INC_LEVELS - root_path.len(),
2073 {
2074 if subtree.level < INC_LEVELS - 1 {
2075 if subtree.value.is_node() {
2076 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2077 #[trigger] subtree.children[i as int]).unwrap().tree_predicate_map(
2078 root_path.push_tail(i as usize),
2079 Self::path_in_tree_pred(dest_path),
2080 ) by {
2081 PageTableOwner(subtree).pt_inv_unroll(i);
2082 Self::path_in_tree_holds_when_on_wrong_path(
2083 subtree.children[i as int].unwrap(),
2084 root_path.push_tail(i as usize),
2085 dest_path,
2086 );
2087 };
2088 } else {
2089 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2090 #[trigger] subtree.children[i as int]) is None by {
2091 PageTableOwner(subtree).pt_inv_non_node(i);
2092 };
2093 }
2094 }
2095 }
2096
2097 pub axiom fn neq_old_from_path_disjoint(
2100 subtree: OwnerSubtree<C>,
2101 path_j: TreePath<NR_ENTRIES>,
2102 old_entry: EntryOwner<C>,
2103 regions: MetaRegionOwners,
2104 )
2105 requires
2106 subtree.inv(),
2107 subtree.value.path == path_j,
2108 path_j.len() == subtree.level,
2109 path_j.inv(),
2110 path_j.len() <= INC_LEVELS - 1,
2111 subtree.tree_predicate_map(path_j, Self::metaregion_sound_pred(regions)),
2112 old_entry.is_node(),
2113 old_entry.meta_slot_paddr() is Some,
2114 regions.slot_owners[frame_to_index(old_entry.meta_slot_paddr().unwrap())].paths_in_pt
2115 == set![old_entry.path],
2116 !Self::is_prefix_of(path_j, old_entry.path),
2117 ensures
2118 subtree.tree_predicate_map(
2119 path_j,
2120 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry),
2121 ),
2122 ;
2123
2124 pub proof fn is_at_eq_rec(
2125 subtree: OwnerSubtree<C>,
2126 root_path: TreePath<NR_ENTRIES>,
2127 dest_path: TreePath<NR_ENTRIES>,
2128 entry1: EntryOwner<C>,
2129 entry2: EntryOwner<C>,
2130 )
2131 requires
2132 subtree.inv(),
2133 PageTableOwner(subtree).pt_inv(),
2134 dest_path.inv(),
2135 root_path.inv(),
2136 Self::is_prefix_of(root_path, dest_path),
2137 root_path.len() <= INC_LEVELS - 1,
2138 root_path.len() == subtree.level,
2139 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
2140 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry1, dest_path)),
2141 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry2, dest_path)),
2142 ensures
2143 entry1 == entry2,
2144 decreases INC_LEVELS - root_path.len(),
2145 {
2146 if root_path == dest_path {
2147 assert(subtree.value == entry1);
2148 assert(subtree.value == entry2);
2149 } else if subtree.level == INC_LEVELS - 1 || !subtree.value.is_node() {
2150 proof_from_false()
2151 } else {
2152 assert(root_path.len() <= dest_path.len());
2153 if root_path.len() == dest_path.len() {
2154 assert(root_path.0.len() == dest_path.0.len());
2155 assert forall|i: int| 0 <= i < root_path.0.len() implies #[trigger] root_path.0[i]
2156 == dest_path.0[i] by {
2157 assert(root_path.index(i) == dest_path.index(i));
2158 };
2159 assert(root_path =~= dest_path);
2160 assert(root_path == dest_path);
2161 assert(false);
2162 }
2163 assert(root_path.len() < dest_path.len());
2164 let i = dest_path.index(root_path.len() as int);
2165 assert(0 <= i < NR_ENTRIES);
2166 PageTableOwner(subtree).pt_inv_unroll(i as int);
2167 assert(Self::is_prefix_of(root_path.push_tail(i), dest_path));
2168 Self::is_at_eq_rec(
2169 subtree.children[i as int].unwrap(),
2170 root_path.push_tail(i as usize),
2171 dest_path,
2172 entry1,
2173 entry2,
2174 );
2175 }
2176 }
2177
2178 pub proof fn view_rec_inversion(
2179 self,
2180 path: TreePath<NR_ENTRIES>,
2181 regions: MetaRegionOwners,
2182 m: Mapping,
2183 ) -> (entry: EntryOwner<C>)
2184 requires
2185 self.pt_inv(),
2186 path.len() == self.0.level,
2187 self.view_rec(path).contains(m),
2188 self.0.tree_predicate_map(path, Self::path_correct_pred()),
2189 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
2190 ensures
2191 Self::is_prefix_of(path, entry.path),
2192 regions.slot_owners[frame_to_index(m.pa_range.start)].paths_in_pt == set![entry.path],
2193 m.va_range.start == vaddr_of::<C>(entry.path) as int,
2194 m.page_size == page_size((INC_LEVELS - entry.path.len()) as PagingLevel),
2195 entry.is_frame(),
2196 m.property == entry.frame.unwrap().prop,
2197 self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path)),
2198 self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path)),
2199 entry.inv(),
2200 decreases INC_LEVELS - path.len(),
2201 {
2202 if self.0.value.is_frame() {
2203 assert(Self::is_prefix_of(path, self.0.value.path));
2204 if self.0.level < INC_LEVELS - 1 {
2205 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2208 #[trigger] self.0.children[i]) is None by {
2209 self.pt_inv_non_node(i);
2210 };
2211 }
2212 assert(self.0.tree_predicate_map(
2213 path,
2214 Self::is_at_pred(self.0.value, self.0.value.path),
2215 ));
2216 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(self.0.value.path)));
2217 self.0.value
2218 } else if self.0.value.is_node() {
2219 self.view_rec_contains(path, m);
2220 let i = self.view_rec_contains_choose(path, m);
2221 self.pt_inv_unroll(i);
2222 let entry = PageTableOwner(self.0.children[i].unwrap()).view_rec_inversion(
2223 path.push_tail(i as usize),
2224 regions,
2225 m,
2226 );
2227 Self::prefix_transitive(path, path.push_tail(i as usize), entry.path);
2228 assert forall|j: int|
2229 0 <= j < NR_ENTRIES
2230 && #[trigger] self.0.children[j] is Some implies self.0.children[j].unwrap().tree_predicate_map(
2231 path.push_tail(j as usize), Self::is_at_pred(entry, entry.path)) by {
2232 if j != i {
2233 self.pt_inv_unroll(j);
2234 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
2235 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path));
2236 Self::is_at_holds_when_on_wrong_path(
2237 self.0.children[j].unwrap(),
2238 path.push_tail(j as usize),
2239 entry.path,
2240 entry,
2241 );
2242 }
2243 };
2244 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path)));
2245
2246 assert forall|j: int|
2247 0 <= j < NR_ENTRIES
2248 && #[trigger] self.0.children[j] is Some implies self.0.children[j].unwrap().tree_predicate_map(
2249 path.push_tail(j as usize), Self::path_in_tree_pred(entry.path)) by {
2250 if j != i {
2251 self.pt_inv_unroll(j);
2252 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
2253 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path));
2254 Self::path_in_tree_holds_when_on_wrong_path(
2255 self.0.children[j].unwrap(),
2256 path.push_tail(j as usize),
2257 entry.path,
2258 );
2259 }
2260 };
2261 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path)));
2262 entry
2263 } else {
2264 proof_from_false()
2265 }
2266 }
2267
2268 pub proof fn view_rec_inversion_unique(
2269 self,
2270 path: TreePath<NR_ENTRIES>,
2271 regions: MetaRegionOwners,
2272 m1: Mapping,
2273 m2: Mapping,
2274 )
2275 requires
2276 self.pt_inv(),
2277 path.len() <= INC_LEVELS - 1,
2278 path.len() == self.0.level,
2279 self.view_rec(path).contains(m1),
2280 self.view_rec(path).contains(m2),
2281 m1.pa_range.start == m2.pa_range.start,
2282 m1.inv(),
2283 m2.inv(),
2284 self.0.tree_predicate_map(path, Self::path_tracked_pred(regions)),
2285 self.0.tree_predicate_map(path, Self::path_correct_pred()),
2286 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
2287 ensures
2288 m1 == m2,
2289 {
2290 let entry1 = self.view_rec_inversion(path, regions, m1);
2291 let entry2 = self.view_rec_inversion(path, regions, m2);
2292
2293 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry1, entry1.path)));
2294 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry2, entry2.path)));
2295
2296 let idx = frame_to_index(m1.pa_range.start);
2298 assert(regions.slot_owners[idx].paths_in_pt == set![entry1.path]);
2299 assert(regions.slot_owners[idx].paths_in_pt == set![entry2.path]);
2300 assert(set![entry1.path].contains(entry2.path));
2301 assert(entry1.path == entry2.path);
2302
2303 Self::is_at_eq_rec(self.0, path, entry1.path, entry1, entry2);
2304 }
2305}
2306
2307impl<C: PageTableConfig> Inv for PageTableOwner<C> {
2308 open spec fn inv(self) -> bool {
2309 &&& self.0.inv()
2310 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level) as nat)
2311 &&& self.0.value.is_node()
2312 &&& self.0.value.path.len() <= INC_LEVELS - 1
2313 &&& self.0.value.path.inv()
2314 &&& self.0.value.path.len() == self.0.level
2315 &&& self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel
2316 &&& self.0.value.node.unwrap().tree_level == self.0.value.path.len()
2317 &&& self.0.tree_predicate_map(self.0.value.path, Self::path_correct_pred())
2318 }
2319}
2320
2321impl<C: PageTableConfig> View for PageTableOwner<C> {
2322 type V = PageTableView;
2323
2324 open spec fn view(&self) -> <Self as View>::V {
2325 let mappings = self.view_rec(self.0.value.path);
2326 PageTableView { mappings }
2327 }
2328}
2329
2330}