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::{page_table::EntryOwner, Paddr, PagingLevel, Vaddr, MAX_NR_LEVELS};
17
18use crate::mm::frame::frame_to_index;
19use crate::mm::page_table::{page_size_spec, PageTableEntryTrait, PageTableGuard};
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#[verifier::rlimit(400)]
117pub proof fn lemma_vaddr_strict_bound(path: TreePath<NR_ENTRIES>)
118 requires
119 path.inv(),
120 path.len() <= INC_LEVELS - 1,
121 ensures
122 (vaddr(path) as int) < 0x1_0000_0000_0000int,
123{
124 broadcast use TreePath::index_satisfies_elem_inv;
125 broadcast use TreePath::push_tail_property;
126 lemma_page_size_spec_values();
127 vstd::arithmetic::power2::lemma2_to64();
128 vstd::arithmetic::power2::lemma2_to64_rest();
129 if path.len() == 0 {
130 assert(rec_vaddr(path, 0) == 0);
131 } else if path.len() == 1 {
132 admit();
138 } else {
139 admit();
140 }
141}
142
143pub proof fn lemma_vaddr_of_eq_int<C: PageTableConfig>(path: TreePath<NR_ENTRIES>)
147 requires
148 path.inv(),
149 path.len() <= INC_LEVELS - 1,
150 ensures
151 vaddr_of::<C>(path) as int
152 == vaddr(path) as int
153 + C::LEADING_BITS_spec() as int * 0x1_0000_0000_0000int,
154{
155 axiom_leading_bits_bounded::<C>();
156 lemma_vaddr_strict_bound(path);
157 let lb = C::LEADING_BITS_spec() as int;
158 let v = vaddr(path) as int;
159 assert(0 <= v);
161 assert(lb * 0x1_0000_0000_0000int <= 0xffff_int * 0x1_0000_0000_0000int)
162 by (nonlinear_arith) requires lb < 0x1_0000int, lb >= 0;
163 assert(v + lb * 0x1_0000_0000_0000int < 0x1_0000_0000_0000_0000int)
164 by (nonlinear_arith)
165 requires
166 v < 0x1_0000_0000_0000int,
167 lb < 0x1_0000int,
168 lb >= 0;
169}
170
171pub proof fn page_size_monotonic(a: PagingLevel, b: PagingLevel)
173 requires
174 1 <= a <= NR_LEVELS + 1,
175 1 <= b <= NR_LEVELS + 1,
176 a <= b,
177 ensures
178 page_size(a) <= page_size(b),
179{
180 if a == b {
181 } else {
182 let ps_a = page_size(a);
183 let ps_b = page_size(b);
184
185 assert(ps_a == page_size_spec(a));
186 assert(ps_b == page_size_spec(b));
187
188 lemma_page_size_ge_page_size(a);
189 lemma_page_size_ge_page_size(b);
190 assert(ps_a > 0);
191 assert(ps_b > 0);
192
193 lemma_page_size_divides(a, b);
194 assert(ps_b % ps_a == 0);
195
196 assert(ps_a <= ps_b) by {
197 if ps_b < ps_a {
198 vstd::arithmetic::div_mod::lemma_small_mod(ps_b as nat, ps_a as nat);
199 assert(ps_b % ps_a == ps_b);
200 assert(ps_b % ps_a == 0);
201 assert(false);
202 }
203 }
204 }
205}
206
207pub proof fn sibling_paths_disjoint<C: PageTableConfig>(
214 prefix: TreePath<NR_ENTRIES>,
215 j: usize,
216 k: usize,
217 size: usize,
218)
219 requires
220 prefix.inv(),
221 prefix.len() < INC_LEVELS - 1,
222 j < NR_ENTRIES,
223 k < NR_ENTRIES,
224 j != k,
225 size == page_size((INC_LEVELS - prefix.len() - 1) as PagingLevel),
226 ensures
227 vaddr(prefix.push_tail(j)) + size <= vaddr(prefix.push_tail(k))
228 || vaddr(prefix.push_tail(k)) + size <= vaddr(prefix.push_tail(j)),
229{
230 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, j);
231 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, k);
232 let s = size as int;
233 let vp = vaddr(prefix) as int;
234 let vj = vaddr(prefix.push_tail(j)) as int;
235 let vk = vaddr(prefix.push_tail(k)) as int;
236 if j < k {
237 assert(vj + s <= vk) by (nonlinear_arith)
238 requires vj == vp + (j as int) * s,
239 vk == vp + (k as int) * s,
240 j < k, s >= 0;
241 } else {
242 assert(vk + s <= vj) by (nonlinear_arith)
243 requires vj == vp + (j as int) * s,
244 vk == vp + (k as int) * s,
245 k < j, s >= 0;
246 }
247}
248
249impl<C: PageTableConfig, const L: usize> TreeNodeValue<L> for EntryOwner<C> {
250 open spec fn default(lv: nat) -> Self {
251 Self {
252 in_scope: false,
253 path: TreePath::new(Seq::empty()),
254 parent_level: (INC_LEVELS - lv) as PagingLevel,
255 node: None,
256 frame: None,
257 locked: None,
258 absent: true,
259 }
260 }
261
262 proof fn default_preserves_inv() {
263 }
264
265 open spec fn la_inv(self, lv: nat) -> bool {
266 self.is_node() ==> lv < L - 1
267 }
268
269 proof fn default_preserves_la_inv() {
270 }
271
272 open spec fn rel_children(self, i: int, child: Option<Self>) -> bool {
275 true
276 }
277
278 proof fn default_preserves_rel_children(self, lv: nat) {
279 }
280}
281
282pub const INC_LEVELS: usize = NR_LEVELS + 1;
283
284pub type OwnerSubtree<C> = Node<EntryOwner<C>, NR_ENTRIES, INC_LEVELS>;
294
295pub open spec fn allocated_empty_node_owner<C: PageTableConfig>(owner: OwnerSubtree<C>, level: PagingLevel) -> bool {
298 &&& owner.inv()
299 &&& owner.value.is_node()
300 &&& owner.value.path == TreePath::<NR_ENTRIES>::new(Seq::empty())
301 &&& owner.value.parent_level == level
302 &&& owner.value.node.unwrap().level == level - 1
303 &&& owner.value.node.unwrap().inv()
304 &&& !owner.value.node.unwrap().children_perm.value().all(|child: C::E| child.is_present())
305 &&& forall |i: int| #![auto] 0 <= i < NR_ENTRIES ==> {
306 &&& owner.children[i] is Some
307 &&& owner.children[i].unwrap().value.is_absent()
308 &&& !owner.children[i].unwrap().value.in_scope
309 &&& owner.children[i].unwrap().value.inv()
310 &&& owner.children[i].unwrap().value.path == owner.value.path.push_tail(i as usize)
311 }
312 &&& forall |i: int| #![auto] 0 <= i < NR_ENTRIES ==>
313 owner.children[i].unwrap().value.match_pte(
314 owner.value.node.unwrap().children_perm.value()[i],
315 owner.children[i].unwrap().value.parent_level,
316 )
317 &&& forall |i: int| #![auto] 0 <= i < NR_ENTRIES ==>
318 owner.children[i].unwrap().value.parent_level == owner.value.node.unwrap().level
319}
320
321pub tracked struct PageTableOwner<C: PageTableConfig>(pub OwnerSubtree<C>);
322
323impl<C: PageTableConfig> PageTableOwner<C> {
324
325 pub open spec fn pt_edge_at(parent: OwnerSubtree<C>, i: int) -> bool {
327 &&& parent.children[i] is Some
328 &&& parent.children[i].unwrap().value.path.len()
329 == parent.value.node.unwrap().tree_level + 1
330 &&& parent.children[i].unwrap().value.match_pte(
331 parent.value.node.unwrap().children_perm.value()[i],
332 parent.value.node.unwrap().level)
333 &&& parent.children[i].unwrap().value.path
334 == parent.value.path.push_tail(i as usize)
335 &&& parent.children[i].unwrap().value.parent_level
336 == parent.value.node.unwrap().level
337 }
338
339 pub open spec fn pt_inv_at_depth(self, depth: nat) -> bool
343 decreases depth
344 {
345 if depth == 0 {
346 true
347 } else if self.0.value.is_node() {
348 forall |i: int| #![trigger self.0.children[i]]
349 0 <= i < NR_ENTRIES ==>
350 Self::pt_edge_at(self.0, i)
351 && PageTableOwner(self.0.children[i].unwrap())
352 .pt_inv_at_depth((depth - 1) as nat)
353 } else {
354 forall |i: int| #![trigger self.0.children[i]]
355 0 <= i < NR_ENTRIES ==> self.0.children[i] is None
356 }
357 }
358
359 pub open spec fn pt_inv(self) -> bool {
364 &&& self.0.inv()
365 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level) as nat)
366 }
367
368 pub proof fn pt_inv_unroll(self, i: int)
369 requires
370 self.pt_inv(),
371 self.0.value.is_node(),
372 0 <= i < NR_ENTRIES,
373 ensures
374 Self::pt_edge_at(self.0, i),
375 PageTableOwner(self.0.children[i].unwrap()).pt_inv(),
376 {
377 let depth = (INC_LEVELS - self.0.level) as nat;
380 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::la_inv(self.0.value, self.0.level));
381 }
382
383 pub proof fn pt_inv_non_node(self, i: int)
384 requires
385 self.pt_inv(),
386 !self.0.value.is_node(),
387 0 <= i < NR_ENTRIES,
388 ensures
389 self.0.children[i] is None,
390 {
391 let depth = (INC_LEVELS - self.0.level) as nat;
392 if depth == 0 {
393 assert(self.0.level >= INC_LEVELS);
394 }
395 }
396
397
398pub open spec fn top_level_indices_absent(self) -> bool {
403 let range = C::TOP_LEVEL_INDEX_RANGE_spec();
404 self.0.value.is_node() ==>
405 forall|i: int|
406 #![trigger self.0.children[i]]
407 0 <= i < NR_ENTRIES
408 && !(range.start <= i < range.end)
409 ==> self.0.children[i] is Some
410 && self.0.children[i].unwrap().value.is_absent()
411 }
412
413 pub open spec fn view_rec(self, path: TreePath<NR_ENTRIES>) -> Set<Mapping>
414 decreases INC_LEVELS - path.len() when self.0.inv() && path.len() <= INC_LEVELS - 1
415 {
416 if self.0.value.is_frame() {
417 let va = vaddr_of::<C>(path);
418 let pt_level = INC_LEVELS - path.len();
419 let page_size = page_size(pt_level as PagingLevel);
420
421 set![Mapping {
422 va_range: Range { start: va as int, end: va as int + page_size as int },
423 pa_range: Range {
424 start: self.0.value.frame.unwrap().mapped_pa,
425 end: (self.0.value.frame.unwrap().mapped_pa + page_size) as Paddr,
426 },
427 page_size: page_size,
428 property: self.0.value.frame.unwrap().prop,
429 }]
430 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
431 Set::new(
432 |m: Mapping| exists|i:int|
433 #![trigger self.0.children[i]]
434 0 <= i < self.0.children.len() &&
435 self.0.children[i] is Some &&
436 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
437 )
438 } else {
439 set![]
440 }
441 }
442
443 pub proof fn view_rec_contains(self, path: TreePath<NR_ENTRIES>, m: Mapping)
444 requires
445 self.0.inv(),
446 path.len() < INC_LEVELS - 1,
447 path.len() == self.0.level,
448 self.view_rec(path).contains(m),
449 self.0.value.is_node()
450 ensures
451 exists|i:int| #![auto] 0 <= i < self.0.children.len() &&
452 self.0.children[i] is Some &&
453 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
454 { }
455
456 pub proof fn view_rec_contains_choose(self, path: TreePath<NR_ENTRIES>, m: Mapping) -> (i: int)
457 requires
458 self.0.inv(),
459 path.len() < INC_LEVELS - 1,
460 path.len() == self.0.level,
461 self.view_rec(path).contains(m),
462 self.0.value.is_node(),
463 ensures
464 0 <= i < self.0.children.len() &&
465 self.0.children[i] is Some &&
466 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
467 {
468 choose|i:int| #![auto] 0 <= i < self.0.children.len() &&
469 self.0.children[i] is Some &&
470 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
471 }
472
473 #[verifier::rlimit(400)]
475 pub proof fn lemma_vaddr_push_tail_eq(path: TreePath<NR_ENTRIES>, i: usize)
476 requires
477 path.inv(),
478 path.len() < INC_LEVELS - 1,
479 i < NR_ENTRIES,
480 ensures
481 vaddr(path.push_tail(i)) as int
482 == vaddr(path) as int
483 + (i as int)
484 * (page_size((INC_LEVELS - path.len() - 1) as PagingLevel) as int),
485 vaddr(path) as int
486 + (i as int + 1)
487 * (page_size((INC_LEVELS - path.len() - 1) as PagingLevel) as int)
488 <= usize::MAX as int,
489 {
490 broadcast use TreePath::push_tail_property;
491 broadcast use TreePath::index_satisfies_elem_inv;
492 lemma_page_size_spec_values();
493 vstd::arithmetic::power2::lemma2_to64();
494 vstd::arithmetic::power2::lemma2_to64_rest();
495 let pt = path.push_tail(i);
496 if path.len() >= 1 {
497 Self::lemma_vaddr_path_alignment_and_bound(path);
498 }
499 if path.len() == 0 {
500 assert(rec_vaddr(path, 0) == 0);
501 assert(pt.len() == 1);
502 assert(rec_vaddr(pt, 1) == 0);
503 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i) + 0) as usize);
504 assert(vaddr_make::<NR_LEVELS>(0, i) == 0x80_0000_0000usize * i) by (compute);
505 assert(page_size(4) == 0x80_0000_0000usize);
506 assert(0x80_0000_0000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
507 requires i < 512;
508 } else if path.len() == 1 {
509 let i0 = path.index(0);
510 assert(0 <= i0 < NR_ENTRIES);
511 assert(rec_vaddr(path, 1) == 0);
512 assert(rec_vaddr(path, 0) == vaddr_make::<NR_LEVELS>(0, i0) as usize);
513 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
514 assert(rec_vaddr(path, 0) == 0x80_0000_0000usize * i0);
515 assert(pt.len() == 2);
516 assert(pt.index(0) == i0);
517 assert(pt.index(1) == i);
518 assert(rec_vaddr(pt, 2) == 0);
519 assert(rec_vaddr(pt, 1) == vaddr_make::<NR_LEVELS>(1, i) as usize);
520 assert(vaddr_make::<NR_LEVELS>(1, i) == 0x4000_0000usize * i) by (compute);
521 assert(rec_vaddr(pt, 0) as int == (0x80_0000_0000usize * i0) as int + (0x4000_0000usize * i) as int);
522 assert(page_size(3) == 0x4000_0000usize);
523 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
524 requires i0 < 512, i < 512;
525 } else if path.len() == 2 {
526 let i0 = path.index(0); let i1 = path.index(1);
527 assert(0 <= i0 < NR_ENTRIES); assert(0 <= i1 < NR_ENTRIES);
528 assert(rec_vaddr(path, 2) == 0);
529 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1) as usize);
530 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(1, i1)) as usize);
531 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
532 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
533 assert(pt.len() == 3);
534 assert(pt.index(0) == i0); assert(pt.index(1) == i1); assert(pt.index(2) == i);
535 assert(rec_vaddr(pt, 3) == 0);
536 assert(rec_vaddr(pt, 2) == vaddr_make::<NR_LEVELS>(2, i) as usize);
537 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(2, i)) as usize);
538 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i0)
539 + vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(2, i)) as usize);
540 assert(vaddr_make::<NR_LEVELS>(2, i) == 0x20_0000usize * i) by (compute);
541 assert(page_size(2) == 0x20_0000usize);
542 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * (i + 1)
543 <= usize::MAX) by (nonlinear_arith)
544 requires i0 < 512, i1 < 512, i < 512;
545 } else {
546 assert(path.len() == 3);
547 let i0 = path.index(0); let i1 = path.index(1); let i2 = path.index(2);
548 assert(0 <= i0 < NR_ENTRIES); assert(0 <= i1 < NR_ENTRIES); assert(0 <= i2 < NR_ENTRIES);
549 assert(rec_vaddr(path, 3) == 0);
550 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2) as usize);
551 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(2, i2)) as usize);
552 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0)
553 + vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(2, i2)) as usize);
554 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
555 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
556 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
557 assert(pt.len() == 4);
558 assert(pt.index(0) == i0); assert(pt.index(1) == i1);
559 assert(pt.index(2) == i2); assert(pt.index(3) == i);
560 assert(rec_vaddr(pt, 4) == 0);
561 assert(rec_vaddr(pt, 3) == vaddr_make::<NR_LEVELS>(3, i) as usize);
562 assert(rec_vaddr(pt, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(3, i)) as usize);
563 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1)
564 + vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(3, i)) as usize);
565 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i0)
566 + vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(2, i2)
567 + vaddr_make::<NR_LEVELS>(3, i)) as usize);
568 assert(vaddr_make::<NR_LEVELS>(3, i) == 0x1000usize * i) by (compute);
569 assert(page_size(1) == 0x1000usize);
570 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1
571 + 0x20_0000usize * i2 + 0x1000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
572 requires i0 < 512, i1 < 512, i2 < 512, i < 512;
573 }
574 }
575
576 pub proof fn view_rec_vaddr_range(self, path: TreePath<NR_ENTRIES>, m: Mapping)
577 requires
578 self.pt_inv(),
579 path.inv(),
580 path.len() <= INC_LEVELS - 1,
581 path.len() == self.0.level,
582 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
583 self.view_rec(path).contains(m),
584 ensures
585 vaddr_of::<C>(path) as int <= m.va_range.start,
586 m.va_range.start < m.va_range.end,
587 m.va_range.end <= vaddr_of::<C>(path) as int + page_size((INC_LEVELS - path.len()) as PagingLevel) as int,
588 decreases INC_LEVELS - path.len(),
589 {
590 lemma_page_size_spec_values();
591 if self.0.value.is_frame() {
592 Self::lemma_vaddr_path_alignment_and_bound(path);
593 let frame = self.0.value.frame.unwrap();
594 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
595 let expected = Mapping {
596 va_range: Range {
597 start: vaddr_of::<C>(path) as int,
598 end: vaddr_of::<C>(path) as int + page_size(pt_level) as int,
599 },
600 pa_range: Range {
601 start: frame.mapped_pa,
602 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
603 },
604 page_size: page_size(pt_level),
605 property: frame.prop,
606 };
607 assert(self.view_rec(path) =~= set![expected]);
608 assert(m == expected);
609 assert(page_size(pt_level) > 0);
610 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
611 let i = choose|i: int|
612 #![trigger self.0.children[i]]
613 0 <= i < self.0.children.len()
614 && self.0.children[i] is Some
615 && PageTableOwner(self.0.children[i].unwrap())
616 .view_rec(path.push_tail(i as usize)).contains(m);
617 self.pt_inv_unroll(i);
618 let child = PageTableOwner(self.0.children[i].unwrap());
619 path.push_tail_preserves_inv(i as usize);
620 path.push_tail_property_len(i as usize);
621 child.view_rec_vaddr_range(path.push_tail(i as usize), m);
622 Self::lemma_vaddr_push_tail_eq(path, i as usize);
623
624 let parent_ps = page_size((INC_LEVELS - path.len()) as PagingLevel) as int;
625 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel) as int;
626 vstd::arithmetic::power2::lemma2_to64();
627 vstd::arithmetic::power2::lemma2_to64_rest();
628 if path.len() == 0 {
629 assert(parent_ps == 0x1_0000_0000_0000);
630 assert(child_ps == 0x80_0000_0000);
631 } else if path.len() == 1 {
632 assert(parent_ps == 0x80_0000_0000);
633 assert(child_ps == 0x4000_0000);
634 } else if path.len() == 2 {
635 assert(parent_ps == 0x4000_0000);
636 assert(child_ps == 0x20_0000);
637 } else {
638 assert(path.len() == 3);
639 assert(parent_ps == 0x20_0000);
640 assert(child_ps == 0x1000);
641 }
642 assert(parent_ps == 512 * child_ps) by (nonlinear_arith)
643 requires
644 (parent_ps == 0x1_0000_0000_0000 && child_ps == 0x80_0000_0000)
645 || (parent_ps == 0x80_0000_0000 && child_ps == 0x4000_0000)
646 || (parent_ps == 0x4000_0000 && child_ps == 0x20_0000)
647 || (parent_ps == 0x20_0000 && child_ps == 0x1000);
648 assert((i + 1) * child_ps <= 512 * child_ps) by (nonlinear_arith)
649 requires 0 <= i < 512, child_ps >= 0;
650 assert(m.va_range.end <= vaddr_of::<C>(path.push_tail(i as usize)) as int + child_ps);
651 assert(vaddr(path.push_tail(i as usize)) == vaddr(path) + i * child_ps);
652 lemma_vaddr_of_eq_int::<C>(path);
656 lemma_vaddr_of_eq_int::<C>(path.push_tail(i as usize));
657 assert(vaddr_of::<C>(path.push_tail(i as usize)) as int
658 == vaddr_of::<C>(path) as int + i * child_ps);
659 assert(i * child_ps + child_ps == (i + 1) * child_ps) by (nonlinear_arith);
660 assert(m.va_range.end <= vaddr_of::<C>(path) as int + (i + 1) * child_ps);
661 assert(m.va_range.end <= vaddr_of::<C>(path) as int + parent_ps);
662 }
663 }
664
665 pub proof fn view_rec_disjoint_vaddrs(self, path: TreePath<NR_ENTRIES>, m1: Mapping, m2: Mapping)
666 requires
667 self.pt_inv(),
668 path.inv(),
669 path.len() <= INC_LEVELS - 1,
670 path.len() == self.0.level,
671 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
672 self.view_rec(path).contains(m1),
673 self.view_rec(path).contains(m2),
674 m1 != m2,
675 ensures
676 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start
677 decreases INC_LEVELS - path.len()
678 {
679 broadcast use group_set_properties;
680
681 if self.0.value.is_frame() {
682 assert(self.view_rec(path).is_singleton());
683 } else if self.0.value.is_node() {
684 self.view_rec_contains(path, m1);
685 self.view_rec_contains(path, m2);
686
687 let i1 = self.view_rec_contains_choose(path, m1);
688 let i2 = self.view_rec_contains_choose(path, m2);
689
690 path.push_tail_preserves_inv(i1 as usize);
691 path.push_tail_preserves_inv(i2 as usize);
692 path.push_tail_property_len(i1 as usize);
693 path.push_tail_property_len(i2 as usize);
694
695 if i1 == i2 {
696 self.pt_inv_unroll(i1);
697 PageTableOwner(self.0.children[i1].unwrap()).view_rec_disjoint_vaddrs(path.push_tail(i1 as usize), m1, m2);
698 } else {
699 self.pt_inv_unroll(i1);
700 self.pt_inv_unroll(i2);
701 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel);
702 PageTableOwner(self.0.children[i1].unwrap()).view_rec_vaddr_range(path.push_tail(i1 as usize), m1);
703 PageTableOwner(self.0.children[i2].unwrap()).view_rec_vaddr_range(path.push_tail(i2 as usize), m2);
704 if i1 < i2 {
705 sibling_paths_disjoint::<C>(path, i1 as usize, i2 as usize, child_ps);
706 } else {
707 sibling_paths_disjoint::<C>(path, i2 as usize, i1 as usize, child_ps);
708 }
709 lemma_vaddr_of_eq_int::<C>(path.push_tail(i1 as usize));
713 lemma_vaddr_of_eq_int::<C>(path.push_tail(i2 as usize));
714 }
715 }
716 }
717
718 pub proof fn view_rec_finite(self, path: TreePath<NR_ENTRIES>)
722 requires
723 self.0.inv(),
724 path.len() <= INC_LEVELS - 1,
725 path.len() == self.0.level,
726 ensures
727 self.view_rec(path).finite(),
728 decreases INC_LEVELS - path.len()
729 {
730 broadcast use group_set_properties;
731
732 if self.0.value.is_frame() {
733 assert(self.view_rec(path).finite());
735 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
736 assert forall |i: int| 0 <= i < NR_ENTRIES && #[trigger] self.0.children[i] is Some implies
738 PageTableOwner(self.0.children[i].unwrap())
739 .view_rec(path.push_tail(i as usize)).finite()
740 by {
741 let child = self.0.children[i].unwrap();
742 PageTableOwner(child).view_rec_finite(path.push_tail(i as usize));
745 };
746
747 let f = |i: int| -> Set<Mapping> {
749 if 0 <= i < NR_ENTRIES && self.0.children[i] is Some {
750 PageTableOwner(self.0.children[i].unwrap())
751 .view_rec(path.push_tail(i as usize))
752 } else {
753 Set::<Mapping>::empty()
754 }
755 };
756 let dom: Set<int> = Set::new(|i: int| 0 <= i < NR_ENTRIES);
757 assert(dom =~= int::range_set(0int, NR_ENTRIES as int));
758 vstd::set_lib::range_set_properties::<int>(0int, NR_ENTRIES as int);
759 assert(dom.finite());
760 dom.lemma_map_finite(f);
761 let ss = dom.map(f);
762 assert(ss.finite());
763
764 assert forall |s: Set<Mapping>| ss.contains(s) implies #[trigger] s.finite() by {
766 let i = choose |i: int| dom.contains(i) && f(i) == s;
767 if 0 <= i < NR_ENTRIES && self.0.children[i] is Some {
768 } else {
770 assert(s =~= Set::<Mapping>::empty());
771 }
772 };
773
774 ss.lemma_flatten_finite();
775 assert(self.view_rec(path) =~= ss.flatten()) by {
779 assert forall |m: Mapping| self.view_rec(path).contains(m) implies
780 #[trigger] ss.flatten().contains(m)
781 by {
782 let i = choose |i: int|
783 #![trigger self.0.children[i]]
784 0 <= i < self.0.children.len() &&
785 self.0.children[i] is Some &&
786 PageTableOwner(self.0.children[i].unwrap())
787 .view_rec(path.push_tail(i as usize)).contains(m);
788 assert(dom.contains(i));
789 assert(ss.contains(f(i)));
790 assert(f(i).contains(m));
791 };
792 assert forall |m: Mapping| #[trigger] ss.flatten().contains(m) implies
793 self.view_rec(path).contains(m)
794 by {
795 let s = choose |s: Set<Mapping>| ss.contains(s) && s.contains(m);
796 let i = choose |i: int| dom.contains(i) && f(i) == s;
797 assert(0 <= i < NR_ENTRIES && self.0.children[i] is Some);
798 };
799 };
800 } else {
801 assert(self.view_rec(path) =~= Set::<Mapping>::empty());
803 }
804 }
805
806 pub proof fn view_rec_mapping_page_size(self, path: TreePath<NR_ENTRIES>)
813 requires
814 self.pt_inv(),
815 path.len() <= INC_LEVELS - 1,
816 path.len() == self.0.level,
817 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
818 ensures
819 forall |m: Mapping| #[trigger] self.view_rec(path).contains(m) ==>
820 set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size),
821 decreases INC_LEVELS - path.len()
822 {
823 if self.0.value.is_frame() {
824 lemma_page_size_spec_values();
825 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
826 assert forall |m: Mapping| #[trigger] self.view_rec(path).contains(m) implies
827 set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size)
828 by {
829 let i = choose |i: int|
830 #![trigger self.0.children[i]]
831 0 <= i < self.0.children.len() &&
832 self.0.children[i] is Some &&
833 PageTableOwner(self.0.children[i].unwrap())
834 .view_rec(path.push_tail(i as usize)).contains(m);
835 self.pt_inv_unroll(i);
836 let child = self.0.children[i].unwrap();
837 PageTableOwner(child).view_rec_mapping_page_size(path.push_tail(i as usize));
838 };
839 }
840 }
841
842 #[verifier::rlimit(400)]
849 proof fn lemma_vaddr_path_alignment_and_bound(path: TreePath<NR_ENTRIES>)
850 requires
851 path.inv(),
852 path.len() <= INC_LEVELS - 1,
853 1 <= INC_LEVELS - path.len() <= NR_LEVELS,
854 ensures
855 vaddr(path) % page_size((INC_LEVELS - path.len()) as PagingLevel) == 0,
856 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= usize::MAX,
857 {
858 lemma_page_size_spec_values();
859 vstd::arithmetic::power2::lemma2_to64();
860 vstd::arithmetic::power2::lemma2_to64_rest();
861 broadcast use TreePath::index_satisfies_elem_inv;
862 if path.len() == 0 {
873 assert(rec_vaddr(path, 0) == 0);
874 } else if path.len() == 1 {
875 let i0 = path.index(0);
876 assert(0 <= i0 < NR_ENTRIES);
877 assert(rec_vaddr(path, 1) == 0);
878 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(path, 1)) as usize);
879 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
880 assert(rec_vaddr(path, 0) == 0x80_0000_0000usize * i0);
881 assert(page_size(4) == 0x80_0000_0000usize);
882 assert((0x80_0000_0000usize * i0) % 0x80_0000_0000 == 0) by (nonlinear_arith);
883 assert(0x80_0000_0000usize * i0 + 0x80_0000_0000 <= usize::MAX) by (nonlinear_arith)
884 requires i0 < 512;
885 } else if path.len() == 2 {
886 let i0 = path.index(0); let i1 = path.index(1);
887 assert(0 <= i0 < NR_ENTRIES); assert(0 <= i1 < NR_ENTRIES);
888 assert(rec_vaddr(path, 2) == 0);
889 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(path, 2)) as usize);
890 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(path, 1)) as usize);
891 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
892 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
893 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1) as int;
894 assert(rec_vaddr(path, 0) == s);
895 assert(page_size(3) == 0x4000_0000usize);
896 assert(s % 0x4000_0000 == 0) by (nonlinear_arith)
897 requires s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1;
898 assert(s + 0x4000_0000 <= usize::MAX) by (nonlinear_arith)
899 requires s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1, i0 < 512, i1 < 512;
900 } else if path.len() == 3 {
901 let i0 = path.index(0); let i1 = path.index(1); let i2 = path.index(2);
902 assert(0 <= i0 < NR_ENTRIES); assert(0 <= i1 < NR_ENTRIES); assert(0 <= i2 < NR_ENTRIES);
903 assert(rec_vaddr(path, 3) == 0);
904 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + rec_vaddr(path, 3)) as usize);
905 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(path, 2)) as usize);
906 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(path, 1)) as usize);
907 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
908 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
909 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
910 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2) as int;
911 assert(rec_vaddr(path, 0) == s);
912 assert(page_size(2) == 0x20_0000usize);
913 assert(s % 0x20_0000 == 0) by (nonlinear_arith)
914 requires s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2;
915 assert(s + 0x20_0000 <= usize::MAX) by (nonlinear_arith)
916 requires s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2,
917 i0 < 512, i1 < 512, i2 < 512;
918 } else {
919 assert(path.len() == 4);
920 let i0 = path.index(0); let i1 = path.index(1);
921 let i2 = path.index(2); let i3 = path.index(3);
922 assert(0 <= i0 < NR_ENTRIES); assert(0 <= i1 < NR_ENTRIES);
923 assert(0 <= i2 < NR_ENTRIES); assert(0 <= i3 < NR_ENTRIES);
924 assert(rec_vaddr(path, 4) == 0);
925 assert(rec_vaddr(path, 3) == (vaddr_make::<NR_LEVELS>(3, i3) + rec_vaddr(path, 4)) as usize);
926 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + rec_vaddr(path, 3)) as usize);
927 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(path, 2)) as usize);
928 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(path, 1)) as usize);
929 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
930 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
931 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
932 assert(vaddr_make::<NR_LEVELS>(3, i3) == 0x1000usize * i3) by (compute);
933 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1
934 + 0x20_0000usize * i2 + 0x1000usize * i3) as int;
935 assert(rec_vaddr(path, 0) == s);
936 assert(page_size(1) == 0x1000usize);
937 assert(s % 0x1000 == 0) by (nonlinear_arith)
938 requires s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3;
939 assert(s + 0x1000 <= usize::MAX) by (nonlinear_arith)
940 requires s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3,
941 i0 < 512, i1 < 512, i2 < 512, i3 < 512;
942 }
943 }
944
945 pub proof fn view_rec_mapping_inv(self, path: TreePath<NR_ENTRIES>)
954 requires
955 self.pt_inv(),
956 path.inv(),
957 path.len() <= INC_LEVELS - 1,
958 path.len() == self.0.level,
959 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
960 ensures
961 forall |m: Mapping| #[trigger] self.view_rec(path).contains(m) ==> m.inv(),
962 decreases INC_LEVELS - path.len()
963 {
964 if self.0.value.is_frame() {
965 lemma_page_size_spec_values();
966 let frame = self.0.value.frame.unwrap();
967 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
968 Self::lemma_vaddr_path_alignment_and_bound(path);
969 let m = Mapping {
970 va_range: Range {
971 start: vaddr_of::<C>(path) as int,
972 end: vaddr_of::<C>(path) as int + page_size(pt_level) as int,
973 },
974 pa_range: Range {
975 start: frame.mapped_pa,
976 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
977 },
978 page_size: page_size(pt_level),
979 property: frame.prop,
980 };
981 assert(self.view_rec(path) =~= set![m]);
982 assert(set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size));
983 let ps = page_size(pt_level) as int;
984 assert(ps > 0);
985 assert((frame.mapped_pa as int + ps) % ps == 0) by (nonlinear_arith)
986 requires (frame.mapped_pa as int) % ps == 0, ps > 0;
987 lemma_vaddr_of_eq_int::<C>(path);
989 axiom_leading_bits_bounded::<C>();
990 lemma_vaddr_strict_bound(path);
991 let lb = C::LEADING_BITS_spec() as int;
992 vstd::arithmetic::power2::lemma2_to64();
993 vstd::arithmetic::power2::lemma2_to64_rest();
994 assert(vaddr(path) as int % ps == 0);
998 assert(lb * 0x1_0000_0000_0000int % ps == 0) by (nonlinear_arith)
999 requires
1000 lb >= 0,
1001 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int);
1002 vstd::arithmetic::div_mod::lemma_mod_adds(
1003 vaddr(path) as int, lb * 0x1_0000_0000_0000int, ps);
1004 assert((vaddr_of::<C>(path) as int) % ps == 0);
1005 assert((vaddr_of::<C>(path) as int + ps) % ps == 0) by (nonlinear_arith)
1006 requires (vaddr_of::<C>(path) as int) % ps == 0, ps > 0;
1007 let v = vaddr(path) as int;
1010 assert((v % ps) == 0);
1011 assert(v < 0x1_0000_0000_0000int);
1012 assert(v + ps <= 0x1_0000_0000_0000int) by (nonlinear_arith)
1013 requires
1014 v % ps == 0,
1015 v < 0x1_0000_0000_0000int,
1016 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int),
1017 (0x1_0000_0000_0000int % ps == 0);
1018 assert(vaddr_of::<C>(path) as int + ps <= pow2(64)) by (nonlinear_arith)
1019 requires
1020 vaddr_of::<C>(path) as int == v + lb * 0x1_0000_0000_0000int,
1021 v + ps <= 0x1_0000_0000_0000int,
1022 lb < 0x1_0000int,
1023 lb >= 0,
1024 pow2(64) == 0x1_0000_0000_0000_0000int;
1025 assert(m.inv());
1026 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1027 assert forall |m: Mapping| #[trigger] self.view_rec(path).contains(m) implies m.inv()
1028 by {
1029 let i = choose |i: int|
1030 #![trigger self.0.children[i]]
1031 0 <= i < self.0.children.len() &&
1032 self.0.children[i] is Some &&
1033 PageTableOwner(self.0.children[i].unwrap())
1034 .view_rec(path.push_tail(i as usize)).contains(m);
1035 self.pt_inv_unroll(i);
1036 let child = self.0.children[i].unwrap();
1037 path.push_tail_preserves_inv(i as usize);
1038 PageTableOwner(child).view_rec_mapping_inv(path.push_tail(i as usize));
1039 };
1040 }
1041 }
1042
1043 pub proof fn view_rec_absent_empty(self, path: TreePath<NR_ENTRIES>)
1045 requires
1046 self.0.inv(),
1047 self.0.value.is_absent(),
1048 path.len() <= INC_LEVELS - 1,
1049 ensures
1050 self.view_rec(path) =~= set![],
1051 { }
1052
1053 pub axiom fn view_rec_nr_children_zero_empty(self, path: TreePath<NR_ENTRIES>)
1059 requires
1060 self.0.inv(),
1061 self.0.value.is_node(),
1062 self.0.value.node.unwrap().meta_own.nr_children.value() == 0,
1063 path.len() <= INC_LEVELS - 1,
1064 path.len() == self.0.level,
1065 ensures
1066 self.view_rec(path) =~= set![];
1067
1068 pub open spec fn metaregion_sound_pred(regions: MetaRegionOwners)
1069 -> (spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool) {
1070 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions)
1071 }
1072
1073 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool
1074 decreases INC_LEVELS - self.0.level when self.0.inv()
1075 {
1076 self.0.tree_predicate_map(self.0.value.path, Self::metaregion_sound_pred(regions))
1077 }
1078
1079 pub proof fn metaregion_sound_preserved_slot_owners_eq(
1084 self,
1085 r0: MetaRegionOwners,
1086 r1: MetaRegionOwners,
1087 )
1088 requires
1089 self.inv(),
1090 self.metaregion_sound(r0),
1091 r0.slot_owners == r1.slot_owners,
1092 forall |k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1093 forall |k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1094 ensures
1095 self.metaregion_sound(r1),
1096 {
1097 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1098 self.0, self.0.value.path, r0, r1);
1099 }
1100
1101 pub proof fn metaregion_sound_preserved_slot_owners_eq_subtree(
1103 subtree: OwnerSubtree<C>,
1104 path: TreePath<NR_ENTRIES>,
1105 r0: MetaRegionOwners,
1106 r1: MetaRegionOwners,
1107 )
1108 requires
1109 subtree.inv(),
1110 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r0)),
1111 r0.slot_owners == r1.slot_owners,
1112 forall |k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1113 forall |k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1114 ensures
1115 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r1)),
1116 decreases INC_LEVELS - subtree.level
1117 {
1118 subtree.value.metaregion_sound_slot_owners_only(r0, r1);
1120 if subtree.level < INC_LEVELS - 1 {
1122 assert forall |i: int|
1123 #![trigger subtree.children[i]]
1124 0 <= i < NR_ENTRIES && subtree.children[i] is Some
1125 implies subtree.children[i].unwrap().tree_predicate_map(
1126 path.push_tail(i as usize),
1127 Self::metaregion_sound_pred(r1),
1128 ) by {
1129 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1130 subtree.children[i].unwrap(),
1131 path.push_tail(i as usize),
1132 r0, r1,
1133 );
1134 }
1135 }
1136 }
1137
1138 pub proof fn metaregion_sound_preserved_one_slot_changed(
1144 self,
1145 r0: MetaRegionOwners,
1146 r1: MetaRegionOwners,
1147 changed_idx: usize,
1148 )
1149 requires
1150 self.inv(),
1151 self.metaregion_sound(r0),
1152 forall |i: usize| #![trigger r1.slot_owners[i]]
1153 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1154 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
1155 forall |k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1156 forall |k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1157 self.0.tree_predicate_map(
1159 self.0.value.path,
1160 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1161 e.meta_slot_paddr() is Some
1162 ==> frame_to_index(e.meta_slot_paddr().unwrap()) != changed_idx,
1163 ),
1164 self.0.tree_predicate_map(
1168 self.0.value.path,
1169 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1170 e.is_frame() && e.parent_level > 1 ==> {
1171 let pa = e.frame.unwrap().mapped_pa;
1172 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1173 forall |j: usize| 0 < j < nr_pages ==> {
1174 let sub_idx = #[trigger] frame_to_index((pa + j * PAGE_SIZE) as usize);
1175 sub_idx != changed_idx
1176 || (
1177 r1.slots.contains_key(sub_idx)
1178 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1179 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1180 )
1181 }
1182 },
1183 ),
1184 ensures
1185 self.metaregion_sound(r1),
1186 {
1187 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1188 self.0, self.0.value.path, r0, r1, changed_idx);
1189 }
1190
1191 pub proof fn metaregion_sound_preserved_one_slot_changed_subtree(
1192 subtree: OwnerSubtree<C>,
1193 path: TreePath<NR_ENTRIES>,
1194 r0: MetaRegionOwners,
1195 r1: MetaRegionOwners,
1196 changed_idx: usize,
1197 )
1198 requires
1199 subtree.inv(),
1200 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r0)),
1201 forall |i: usize| #![trigger r1.slot_owners[i]]
1202 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1203 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
1204 forall |k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1205 forall |k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1206 subtree.tree_predicate_map(
1207 path,
1208 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1209 e.meta_slot_paddr() is Some
1210 ==> frame_to_index(e.meta_slot_paddr().unwrap()) != changed_idx,
1211 ),
1212 subtree.tree_predicate_map(
1213 path,
1214 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1215 e.is_frame() && e.parent_level > 1 ==> {
1216 let pa = e.frame.unwrap().mapped_pa;
1217 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1218 forall |j: usize| 0 < j < nr_pages ==> {
1219 let sub_idx = #[trigger] frame_to_index((pa + j * PAGE_SIZE) as usize);
1220 sub_idx != changed_idx
1221 || (
1222 r1.slots.contains_key(sub_idx)
1223 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1224 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1225 )
1226 }
1227 },
1228 ),
1229 ensures
1230 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r1)),
1231 decreases INC_LEVELS - subtree.level
1232 {
1233 subtree.value.metaregion_sound_one_slot_changed(r0, r1, changed_idx);
1234 if subtree.level < INC_LEVELS - 1 {
1235 assert forall |i: int|
1236 #![trigger subtree.children[i]]
1237 0 <= i < NR_ENTRIES && subtree.children[i] is Some
1238 implies subtree.children[i].unwrap().tree_predicate_map(
1239 path.push_tail(i as usize),
1240 Self::metaregion_sound_pred(r1),
1241 ) by {
1242 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1243 subtree.children[i].unwrap(),
1244 path.push_tail(i as usize),
1245 r0, r1, changed_idx,
1246 );
1247 }
1248 }
1249 }
1250
1251 pub open spec fn path_tracked_pred(regions: MetaRegionOwners)
1254 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
1255 {
1256 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
1257 entry.is_node() && entry.meta_slot_paddr() is Some ==> {
1259 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr().unwrap()))
1260 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr().unwrap())].paths_in_pt
1261 == set![entry.path]
1262 }
1263 }
1264 }
1265
1266 pub open spec fn relate_region_tracked_pred(regions: MetaRegionOwners)
1267 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
1268 {
1269 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
1270 &&& entry.meta_slot_paddr() is Some
1271 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr().unwrap()))
1272 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr().unwrap())].paths_in_pt
1273 == set![path]
1274 }
1275 }
1276
1277 pub open spec fn path_correct_pred()
1278 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
1279 {
1280 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
1281 entry.path == path
1282 }
1283 }
1284
1285 pub open spec fn not_in_scope_pred()
1286 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
1287 {
1288 |entry: EntryOwner<C>, _path: TreePath<NR_ENTRIES>| !entry.in_scope
1289 }
1290
1291 pub proof fn tree_not_in_scope(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
1294 requires
1295 subtree.inv(),
1296 ensures
1297 subtree.tree_predicate_map(path, Self::not_in_scope_pred()),
1298 decreases INC_LEVELS - subtree.level,
1299 {
1300 if subtree.level < INC_LEVELS - 1 {
1302 assert forall |i: int|
1303 0 <= i < subtree.children.len()
1304 && (#[trigger] subtree.children[i]) is Some implies
1305 subtree.children[i].unwrap().tree_predicate_map(
1306 path.push_tail(i as usize), Self::not_in_scope_pred())
1307 by {
1308 Self::tree_not_in_scope(
1309 subtree.children[i].unwrap(), path.push_tail(i as usize));
1310 };
1311 }
1312 }
1313
1314 pub proof fn view_rec_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1317 requires
1318 self.0.inv(),
1319 path.len() <= INC_LEVELS - 1,
1320 self.view_rec(path).contains(m),
1321 ensures
1322 m.page_size <= page_size((INC_LEVELS - path.len()) as PagingLevel),
1323 decreases INC_LEVELS - path.len(),
1324 {
1325 if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1326 let i = choose|i: int|
1327 #![auto]
1328 0 <= i < self.0.children.len()
1329 && self.0.children[i] is Some
1330 && PageTableOwner(self.0.children[i].unwrap())
1331 .view_rec(path.push_tail(i as usize)).contains(m);
1332 PageTableOwner(self.0.children[i].unwrap())
1333 .view_rec_page_size_bound(path.push_tail(i as usize), m);
1334 page_size_monotonic(
1335 (INC_LEVELS - path.len() - 1) as PagingLevel,
1336 (INC_LEVELS - path.len()) as PagingLevel,
1337 );
1338 }
1339 }
1340
1341 pub proof fn view_rec_node_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1344 requires
1345 self.0.inv(),
1346 self.0.value.is_node(),
1347 path.len() < INC_LEVELS - 1,
1348 self.view_rec(path).contains(m),
1349 ensures
1350 m.page_size <= page_size(((INC_LEVELS - path.len()) - 1) as PagingLevel),
1351 decreases INC_LEVELS - path.len(),
1352 {
1353 let i = choose|i: int|
1354 #![auto]
1355 0 <= i < self.0.children.len()
1356 && self.0.children[i] is Some
1357 && PageTableOwner(self.0.children[i].unwrap())
1358 .view_rec(path.push_tail(i as usize)).contains(m);
1359 PageTableOwner(self.0.children[i].unwrap())
1360 .view_rec_page_size_bound(path.push_tail(i as usize), m);
1361 }
1362
1363 pub open spec fn is_prefix_of<const N: usize>(
1365 prefix: TreePath<N>,
1366 path: TreePath<N>,
1367 ) -> bool {
1368 &&& prefix.len() <= path.len()
1369 &&& forall |i: int| 0 <= i < prefix.len() ==> prefix.index(i) == path.index(i)
1370 }
1371
1372 pub proof fn prefix_transitive<const N: usize>(
1374 p1: TreePath<N>,
1375 p2: TreePath<N>,
1376 p3: TreePath<N>,
1377 )
1378 requires
1379 Self::is_prefix_of(p1, p2),
1380 Self::is_prefix_of(p2, p3),
1381 ensures
1382 Self::is_prefix_of(p1, p3),
1383 {
1384 assert(p1.len() <= p3.len());
1385 assert forall |i: int| 0 <= i < p1.len() implies p1.index(i) == p3.index(i) by {
1386 assert(p1.index(i) == p2.index(i));
1387 assert(p2.index(i) == p3.index(i));
1388 };
1389 }
1390
1391 pub proof fn prefix_push_different_indices(
1392 prefix: TreePath<NR_ENTRIES>,
1393 path: TreePath<NR_ENTRIES>,
1394 i: usize,
1395 j: usize,
1396 )
1397 requires
1398 prefix.inv(),
1399 path.inv(),
1400 i != j,
1401 Self::is_prefix_of(prefix.push_tail(i), path),
1402 ensures
1403 !Self::is_prefix_of(prefix.push_tail(j), path),
1404 {
1405 assert(path.index(prefix.len() as int) == i);
1406 }
1407
1408 pub open spec fn is_at_pred(entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>)
1409 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
1410 {
1411 |entry0: EntryOwner<C>, path0: TreePath<NR_ENTRIES>| {
1412 path0 == path ==> entry0 == entry
1413 }
1414 }
1415
1416 pub open spec fn path_in_tree_pred(path: TreePath<NR_ENTRIES>)
1417 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
1418 {
1419 |entry: EntryOwner<C>, path0: TreePath<NR_ENTRIES>|
1420 Self::is_prefix_of(path0, path) ==>
1421 !entry.is_node() ==>
1422 path == path0
1423 }
1424
1425 pub proof fn is_at_pred_eq(path: TreePath<NR_ENTRIES>, entry1: EntryOwner<C>, entry2: EntryOwner<C>)
1426 requires
1427 entry1.inv(),
1428 OwnerSubtree::implies(Self::is_at_pred(entry1, path), Self::is_at_pred(entry2, path)),
1429 ensures
1430 entry1 == entry2,
1431 {
1432 assert(Self::is_at_pred(entry1, path)(entry1, path) ==>
1433 Self::is_at_pred(entry2, path)(entry1, path));
1434 }
1435
1436 pub proof fn is_at_holds_when_on_wrong_path(
1437 subtree: OwnerSubtree<C>,
1438 root_path: TreePath<NR_ENTRIES>,
1439 dest_path: TreePath<NR_ENTRIES>,
1440 entry: EntryOwner<C>,
1441 )
1442 requires
1443 subtree.inv(),
1444 PageTableOwner(subtree).pt_inv(),
1445 dest_path.inv(),
1446 !Self::is_prefix_of(root_path, dest_path),
1447 root_path.len() <= INC_LEVELS - 1,
1448 root_path.len() == subtree.level,
1449 ensures
1450 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry, dest_path)),
1451 decreases INC_LEVELS - root_path.len()
1452 {
1453 if subtree.level < INC_LEVELS - 1 {
1454 if subtree.value.is_node() {
1455 assert forall |i: int| 0 <= i < NR_ENTRIES implies
1456 (#[trigger] subtree.children[i as int]).unwrap().tree_predicate_map(root_path.push_tail(i as usize), Self::is_at_pred(entry, dest_path)) by {
1457 PageTableOwner(subtree).pt_inv_unroll(i);
1458 Self::is_at_holds_when_on_wrong_path(subtree.children[i as int].unwrap(),
1459 root_path.push_tail(i as usize), dest_path, entry);
1460 };
1461 } else {
1462 assert forall |i: int| 0 <= i < NR_ENTRIES implies
1463 (#[trigger] subtree.children[i as int]) is None by {
1464 PageTableOwner(subtree).pt_inv_non_node(i);
1465 };
1466 }
1467 }
1468 }
1469
1470 pub proof fn path_in_tree_holds_when_on_wrong_path(
1474 subtree: OwnerSubtree<C>,
1475 root_path: TreePath<NR_ENTRIES>,
1476 dest_path: TreePath<NR_ENTRIES>,
1477 )
1478 requires
1479 subtree.inv(),
1480 PageTableOwner(subtree).pt_inv(),
1481 dest_path.inv(),
1482 !Self::is_prefix_of(root_path, dest_path),
1483 root_path.len() <= INC_LEVELS - 1,
1484 root_path.len() == subtree.level,
1485 ensures
1486 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
1487 decreases INC_LEVELS - root_path.len()
1488 {
1489 if subtree.level < INC_LEVELS - 1 {
1490 if subtree.value.is_node() {
1491 assert forall |i: int| 0 <= i < NR_ENTRIES implies
1492 (#[trigger] subtree.children[i as int]).unwrap().tree_predicate_map(root_path.push_tail(i as usize), Self::path_in_tree_pred(dest_path)) by {
1493 PageTableOwner(subtree).pt_inv_unroll(i);
1494 Self::path_in_tree_holds_when_on_wrong_path(subtree.children[i as int].unwrap(),
1495 root_path.push_tail(i as usize), dest_path);
1496 };
1497 } else {
1498 assert forall |i: int| 0 <= i < NR_ENTRIES implies
1499 (#[trigger] subtree.children[i as int]) is None by {
1500 PageTableOwner(subtree).pt_inv_non_node(i);
1501 };
1502 }
1503 }
1504 }
1505
1506pub axiom fn neq_old_from_path_disjoint(
1509 subtree: OwnerSubtree<C>,
1510 path_j: TreePath<NR_ENTRIES>,
1511 old_entry: EntryOwner<C>,
1512 regions: MetaRegionOwners,
1513 )
1514 requires
1515 subtree.inv(),
1516 subtree.value.path == path_j,
1517 path_j.len() == subtree.level,
1518 path_j.inv(),
1519 path_j.len() <= INC_LEVELS - 1,
1520 subtree.tree_predicate_map(path_j, Self::metaregion_sound_pred(regions)),
1521 old_entry.is_node(),
1522 old_entry.meta_slot_paddr() is Some,
1523 regions.slot_owners[
1524 frame_to_index(old_entry.meta_slot_paddr().unwrap())
1525 ].paths_in_pt == set![old_entry.path],
1526 !Self::is_prefix_of(path_j, old_entry.path),
1527 ensures
1528 subtree.tree_predicate_map(
1529 path_j,
1530 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry),
1531 );
1532
1533 pub proof fn is_at_eq_rec(
1534 subtree: OwnerSubtree<C>,
1535 root_path: TreePath<NR_ENTRIES>,
1536 dest_path: TreePath<NR_ENTRIES>,
1537 entry1: EntryOwner<C>,
1538 entry2: EntryOwner<C>
1539 )
1540 requires
1541 subtree.inv(),
1542 PageTableOwner(subtree).pt_inv(),
1543 dest_path.inv(),
1544 root_path.inv(),
1545 Self::is_prefix_of(root_path, dest_path),
1546 root_path.len() <= INC_LEVELS - 1,
1547 root_path.len() == subtree.level,
1548 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
1549 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry1, dest_path)),
1550 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry2, dest_path)),
1551 ensures
1552 entry1 == entry2,
1553 decreases INC_LEVELS - root_path.len()
1554 {
1555 if root_path == dest_path {
1556 assert(subtree.value == entry1);
1557 assert(subtree.value == entry2);
1558 } else if subtree.level == INC_LEVELS - 1 || !subtree.value.is_node() {
1559 proof_from_false()
1560 } else {
1561 assert(root_path.len() <= dest_path.len());
1562 if root_path.len() == dest_path.len() {
1563 assert(root_path.0.len() == dest_path.0.len());
1564 assert forall |i: int| 0 <= i < root_path.0.len()
1565 implies #[trigger] root_path.0[i] == dest_path.0[i]
1566 by {
1567 assert(root_path.index(i) == dest_path.index(i));
1568 };
1569 assert(root_path =~= dest_path);
1570 assert(root_path == dest_path);
1571 assert(false);
1572 }
1573 assert(root_path.len() < dest_path.len());
1574 let i = dest_path.index(root_path.len() as int);
1575 assert(0 <= i < NR_ENTRIES);
1576 PageTableOwner(subtree).pt_inv_unroll(i as int);
1577 assert(Self::is_prefix_of(root_path.push_tail(i), dest_path));
1578 Self::is_at_eq_rec(subtree.children[i as int].unwrap(), root_path.push_tail(i as usize),
1579 dest_path, entry1, entry2);
1580 }
1581 }
1582
1583 pub proof fn view_rec_inversion(self,
1584 path: TreePath<NR_ENTRIES>,
1585 regions: MetaRegionOwners,
1586 m: Mapping,
1587 ) -> (entry: EntryOwner<C>)
1588 requires
1589 self.pt_inv(),
1590 path.len() == self.0.level,
1591 self.view_rec(path).contains(m),
1592 self.0.tree_predicate_map(path, Self::path_correct_pred()),
1593 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
1594 ensures
1595 Self::is_prefix_of(path, entry.path),
1596 regions.slot_owners[frame_to_index(m.pa_range.start)].paths_in_pt == set![entry.path],
1597 m.va_range.start == vaddr_of::<C>(entry.path) as int,
1598 m.page_size == page_size((INC_LEVELS - entry.path.len()) as PagingLevel),
1599 entry.is_frame(),
1600 m.property == entry.frame.unwrap().prop,
1601 self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path)),
1602 self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path)),
1603 entry.inv(),
1604 decreases INC_LEVELS - path.len()
1605 {
1606 if self.0.value.is_frame() {
1607 assert(Self::is_prefix_of(path, self.0.value.path));
1608 if self.0.level < INC_LEVELS - 1 {
1609 assert forall |i: int| 0 <= i < NR_ENTRIES implies
1612 (#[trigger] self.0.children[i]) is None by {
1613 self.pt_inv_non_node(i);
1614 };
1615 }
1616 assert(self.0.tree_predicate_map(path, Self::is_at_pred(self.0.value, self.0.value.path)));
1617 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(self.0.value.path)));
1618 self.0.value
1619 } else if self.0.value.is_node() {
1620 self.view_rec_contains(path, m);
1621 let i = self.view_rec_contains_choose(path, m);
1622 self.pt_inv_unroll(i);
1623 let entry = PageTableOwner(self.0.children[i].unwrap()).view_rec_inversion(path.push_tail(i as usize), regions, m);
1624 Self::prefix_transitive(path, path.push_tail(i as usize), entry.path);
1625 assert forall |j: int| 0 <= j < NR_ENTRIES && #[trigger] self.0.children[j] is Some implies
1626 self.0.children[j].unwrap().tree_predicate_map(path.push_tail(j as usize),
1627 Self::is_at_pred(entry, entry.path))
1628 by {
1629 if j != i {
1630 self.pt_inv_unroll(j);
1631 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
1632 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path));
1633 Self::is_at_holds_when_on_wrong_path(self.0.children[j].unwrap(),
1634 path.push_tail(j as usize), entry.path, entry);
1635 }
1636 };
1637 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path)));
1638
1639 assert forall |j: int| 0 <= j < NR_ENTRIES && #[trigger] self.0.children[j] is Some implies
1640 self.0.children[j].unwrap().tree_predicate_map(path.push_tail(j as usize),
1641 Self::path_in_tree_pred(entry.path))
1642 by {
1643 if j != i {
1644 self.pt_inv_unroll(j);
1645 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
1646 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path));
1647 Self::path_in_tree_holds_when_on_wrong_path(self.0.children[j].unwrap(),
1648 path.push_tail(j as usize), entry.path);
1649 }
1650 };
1651 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path)));
1652 entry
1653 } else {
1654 proof_from_false()
1655 }
1656 }
1657
1658 pub proof fn view_rec_inversion_unique(self,
1659 path: TreePath<NR_ENTRIES>,
1660 regions: MetaRegionOwners,
1661 m1: Mapping,
1662 m2: Mapping,
1663 )
1664 requires
1665 self.pt_inv(),
1666 path.len() <= INC_LEVELS - 1,
1667 path.len() == self.0.level,
1668 self.view_rec(path).contains(m1),
1669 self.view_rec(path).contains(m2),
1670 m1.pa_range.start == m2.pa_range.start,
1671 m1.inv(),
1672 m2.inv(),
1673 self.0.tree_predicate_map(path, Self::path_tracked_pred(regions)),
1674 self.0.tree_predicate_map(path, Self::path_correct_pred()),
1675 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
1676 ensures
1677 m1 == m2,
1678 {
1679 let entry1 = self.view_rec_inversion(path, regions, m1);
1680 let entry2 = self.view_rec_inversion(path, regions, m2);
1681
1682 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry1, entry1.path)));
1683 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry2, entry2.path)));
1684
1685 let idx = frame_to_index(m1.pa_range.start);
1687 assert(regions.slot_owners[idx].paths_in_pt == set![entry1.path]);
1688 assert(regions.slot_owners[idx].paths_in_pt == set![entry2.path]);
1689 assert(set![entry1.path].contains(entry2.path));
1690 assert(entry1.path == entry2.path);
1691
1692 Self::is_at_eq_rec(self.0, path, entry1.path, entry1, entry2);
1693 }
1694
1695}
1696
1697impl<C: PageTableConfig> Inv for PageTableOwner<C> {
1698 open spec fn inv(self) -> bool {
1699 &&& self.0.inv()
1700 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level) as nat)
1701 &&& self.0.value.is_node()
1702 &&& self.0.value.path.len() <= INC_LEVELS - 1
1703 &&& self.0.value.path.inv()
1704 &&& self.0.value.path.len() == self.0.level
1705 &&& self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel
1706 &&& self.0.value.node.unwrap().tree_level == self.0.value.path.len()
1707 &&& self.0.tree_predicate_map(self.0.value.path, Self::path_correct_pred())
1708 }
1709}
1710
1711impl<C: PageTableConfig> View for PageTableOwner<C> {
1712 type V = PageTableView;
1713
1714 open spec fn view(&self) -> <Self as View>::V {
1715 let mappings = self.view_rec(self.0.value.path);
1716 PageTableView {
1717 mappings
1718 }
1719 }
1720}
1721
1722}