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::*;
24use crate::specs::mm::page_table::cursor::page_size_lemmas::{
25 lemma_page_size_divides, lemma_page_size_ge_page_size,
26};
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 proof fn page_size_monotonic(a: PagingLevel, b: PagingLevel)
85 requires
86 1 <= a <= NR_LEVELS + 1,
87 1 <= b <= NR_LEVELS + 1,
88 a <= b,
89 ensures
90 page_size(a) <= page_size(b),
91{
92 if a == b {
93 } else {
94 let ps_a = page_size(a);
95 let ps_b = page_size(b);
96
97 assert(ps_a == page_size_spec(a));
98 assert(ps_b == page_size_spec(b));
99
100 lemma_page_size_ge_page_size(a);
101 lemma_page_size_ge_page_size(b);
102 assert(ps_a > 0);
103 assert(ps_b > 0);
104
105 lemma_page_size_divides(a, b);
106 assert(ps_b % ps_a == 0);
107
108 assert(ps_a <= ps_b) by {
109 if ps_b < ps_a {
110 vstd::arithmetic::div_mod::lemma_small_mod(ps_b as nat, ps_a as nat);
111 assert(ps_b % ps_a == ps_b);
112 assert(ps_b % ps_a == 0);
113 assert(false);
114 }
115 }
116 }
117}
118
119pub proof fn sibling_paths_disjoint(
123 prefix: TreePath<NR_ENTRIES>,
124 j: usize,
125 k: usize,
126 size: usize,
127)
128 requires
129 j < NR_ENTRIES,
130 k < NR_ENTRIES,
131 j != k,
132 size == page_size((INC_LEVELS - prefix.len()) as PagingLevel),
133 ensures
134 vaddr(prefix.push_tail(j)) + size <= vaddr(prefix.push_tail(k))
135 || vaddr(prefix.push_tail(k)) + size <= vaddr(prefix.push_tail(j)),
136{
137 admit()
138}
139
140impl<C: PageTableConfig, const L: usize> TreeNodeValue<L> for EntryOwner<C> {
141 open spec fn default(lv: nat) -> Self {
142 Self {
143 in_scope: false,
144 path: TreePath::new(Seq::empty()),
145 parent_level: (INC_LEVELS - lv) as PagingLevel,
146 node: None,
147 frame: None,
148 locked: None,
149 absent: true,
150 }
151 }
152
153 proof fn default_preserves_inv() {
154 }
155
156 open spec fn la_inv(self, lv: nat) -> bool {
157 self.is_node() ==> lv < L - 1
158 }
159
160 proof fn default_preserves_la_inv() {
161 }
162
163 open spec fn rel_children(self, i: int, child: Option<Self>) -> bool {
164 if self.is_node() {
165 &&& child is Some
166 &&& child.unwrap().path.len() == self.node.unwrap().tree_level + 1
167 &&& child.unwrap().match_pte(self.node.unwrap().children_perm.value()[i], self.node.unwrap().level)
168 &&& child.unwrap().path == self.path.push_tail(i as usize)
169 } else {
170 &&& child is None
171 }
172 }
173
174 proof fn default_preserves_rel_children(self, lv: nat) {
175 admit()
176 }
177}
178
179pub const INC_LEVELS: usize = NR_LEVELS + 1;
180
181pub type OwnerSubtree<C> = Node<EntryOwner<C>, NR_ENTRIES, INC_LEVELS>;
191
192pub open spec fn allocated_empty_node_owner<C: PageTableConfig>(owner: OwnerSubtree<C>, level: PagingLevel) -> bool {
195 &&& owner.inv()
196 &&& owner.value.is_node()
197 &&& owner.value.path == TreePath::<NR_ENTRIES>::new(Seq::empty())
198 &&& owner.value.parent_level == level
199 &&& owner.value.node.unwrap().level == level - 1
200 &&& owner.value.node.unwrap().inv()
201 &&& !owner.value.node.unwrap().children_perm.value().all(|child: C::E| child.is_present())
202 &&& forall |i: int| #![auto] 0 <= i < NR_ENTRIES ==> {
203 &&& owner.children[i] is Some
204 &&& owner.children[i].unwrap().value.is_absent()
205 &&& !owner.children[i].unwrap().value.in_scope
206 &&& owner.children[i].unwrap().value.inv()
207 &&& owner.children[i].unwrap().value.path == owner.value.path.push_tail(i as usize)
208 }
209 &&& forall |i: int| #![auto] 0 <= i < NR_ENTRIES ==>
210 owner.children[i].unwrap().value.match_pte(
211 owner.value.node.unwrap().children_perm.value()[i],
212 owner.children[i].unwrap().value.parent_level,
213 )
214 &&& forall |i: int| #![auto] 0 <= i < NR_ENTRIES ==>
215 owner.children[i].unwrap().value.parent_level == owner.value.node.unwrap().level
216}
217
218pub struct PageTableOwner<C: PageTableConfig>(pub OwnerSubtree<C>);
219
220impl<C: PageTableConfig> PageTableOwner<C> {
221
222 pub open spec fn top_level_indices_absent(self) -> bool {
227 let range = C::TOP_LEVEL_INDEX_RANGE_spec();
228 self.0.value.is_node() ==>
229 forall|i: int|
230 #![trigger self.0.children[i]]
231 0 <= i < NR_ENTRIES
232 && !(range.start <= i < range.end)
233 ==> self.0.children[i] is Some
234 && self.0.children[i].unwrap().value.is_absent()
235 }
236
237 pub open spec fn view_rec(self, path: TreePath<NR_ENTRIES>) -> Set<Mapping>
238 decreases INC_LEVELS - path.len() when self.0.inv() && path.len() <= INC_LEVELS - 1
239 {
240 if self.0.value.is_frame() {
241 let vaddr = vaddr(path);
242 let pt_level = INC_LEVELS - path.len();
243 let page_size = page_size(pt_level as PagingLevel);
244
245 set![Mapping {
246 va_range: Range { start: vaddr, end: (vaddr + page_size) as Vaddr },
247 pa_range: Range {
248 start: self.0.value.frame.unwrap().mapped_pa,
249 end: (self.0.value.frame.unwrap().mapped_pa + page_size) as Paddr,
250 },
251 page_size: page_size,
252 property: self.0.value.frame.unwrap().prop,
253 }]
254 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
255 Set::new(
256 |m: Mapping| exists|i:int|
257 #![trigger self.0.children[i]]
258 0 <= i < self.0.children.len() &&
259 self.0.children[i] is Some &&
260 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
261 )
262 } else {
263 set![]
264 }
265 }
266
267 pub proof fn view_rec_contains(self, path: TreePath<NR_ENTRIES>, m: Mapping)
268 requires
269 self.0.inv(),
270 path.len() < INC_LEVELS - 1,
271 path.len() == self.0.level,
272 self.view_rec(path).contains(m),
273 self.0.value.is_node()
274 ensures
275 exists|i:int| #![auto] 0 <= i < self.0.children.len() &&
276 self.0.children[i] is Some &&
277 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
278 { }
279
280 pub proof fn view_rec_contains_choose(self, path: TreePath<NR_ENTRIES>, m: Mapping) -> (i: int)
281 requires
282 self.0.inv(),
283 path.len() < INC_LEVELS - 1,
284 path.len() == self.0.level,
285 self.view_rec(path).contains(m),
286 self.0.value.is_node(),
287 ensures
288 0 <= i < self.0.children.len() &&
289 self.0.children[i] is Some &&
290 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
291 {
292 choose|i:int| #![auto] 0 <= i < self.0.children.len() &&
293 self.0.children[i] is Some &&
294 PageTableOwner(self.0.children[i].unwrap()).view_rec(path.push_tail(i as usize)).contains(m)
295 }
296
297 pub proof fn view_rec_vaddr_range(self, path: TreePath<NR_ENTRIES>, m: Mapping)
298 requires
299 self.0.inv(),
300 path.len() <= INC_LEVELS - 1,
301 path.len() == self.0.level,
302 self.view_rec(path).contains(m),
303 ensures
304 vaddr(path) <= m.va_range.start < m.va_range.end <= vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel),
305 {
306 admit();
307 }
308
309 pub proof fn view_rec_disjoint_vaddrs(self, path: TreePath<NR_ENTRIES>, m1: Mapping, m2: Mapping)
310 requires
311 self.0.inv(),
312 path.len() <= INC_LEVELS - 1,
313 path.len() == self.0.level,
314 self.view_rec(path).contains(m1),
315 self.view_rec(path).contains(m2),
316 m1 != m2,
317 ensures
318 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start
319 decreases INC_LEVELS - path.len()
320 {
321 broadcast use group_set_properties;
322
323 if self.0.value.is_frame() {
324 assert(self.view_rec(path).is_singleton());
325 } else if self.0.value.is_node() {
326 self.view_rec_contains(path, m1);
327 self.view_rec_contains(path, m2);
328
329 let i1 = self.view_rec_contains_choose(path, m1);
330 let i2 = self.view_rec_contains_choose(path, m2);
331
332 if i1 == i2 {
333 PageTableOwner(self.0.children[i1].unwrap()).view_rec_disjoint_vaddrs(path.push_tail(i1 as usize), m1, m2);
334 } else if i1 < i2 {
335 let parent_page_size = page_size((INC_LEVELS - path.len()) as PagingLevel);
336 let child_page_size = page_size((INC_LEVELS - path.len() - 1) as PagingLevel);
337 PageTableOwner(self.0.children[i1].unwrap()).view_rec_vaddr_range(path.push_tail(i1 as usize), m1);
338 PageTableOwner(self.0.children[i2].unwrap()).view_rec_vaddr_range(path.push_tail(i2 as usize), m2);
339 page_size_monotonic((INC_LEVELS - path.len() - 1) as PagingLevel, (INC_LEVELS - path.len()) as PagingLevel);
340 assert(child_page_size <= parent_page_size);
341 sibling_paths_disjoint(path, i1 as usize, i2 as usize, parent_page_size);
342 if vaddr(path.push_tail(i1 as usize)) + parent_page_size <= vaddr(path.push_tail(i2 as usize)) {
343 let start1: usize = vaddr(path.push_tail(i1 as usize));
344 let start2: usize = vaddr(path.push_tail(i2 as usize));
345 let m1_end: usize = m1.va_range.end;
346 let m2_start: usize = m2.va_range.start;
347 assert(m1_end <= start1 + child_page_size);
348 assert(start1 + child_page_size <= start1 + parent_page_size) by (nonlinear_arith)
349 requires
350 child_page_size <= parent_page_size,
351 ;
352 assert(m1_end <= start1 + parent_page_size) by (nonlinear_arith)
353 requires
354 m1_end <= start1 + child_page_size,
355 start1 + child_page_size <= start1 + parent_page_size,
356 ;
357 assert(start2 <= m2_start);
358 assert(m1_end <= m2_start) by (nonlinear_arith)
359 requires
360 m1_end <= start1 + parent_page_size,
361 start1 + parent_page_size <= start2,
362 start2 <= m2_start,
363 ;
364 } else {
365 let start2: usize = vaddr(path.push_tail(i2 as usize));
366 let start1: usize = vaddr(path.push_tail(i1 as usize));
367 let m2_end: usize = m2.va_range.end;
368 let m1_start: usize = m1.va_range.start;
369 assert(start2 + parent_page_size <= start1);
370 assert(m2_end <= start2 + child_page_size);
371 assert(start2 + child_page_size <= start2 + parent_page_size) by (nonlinear_arith)
372 requires
373 child_page_size <= parent_page_size,
374 ;
375 assert(m2_end <= start2 + parent_page_size) by (nonlinear_arith)
376 requires
377 m2_end <= start2 + child_page_size,
378 start2 + child_page_size <= start2 + parent_page_size,
379 ;
380 assert(start1 <= m1_start);
381 assert(m2_end <= m1_start) by (nonlinear_arith)
382 requires
383 m2_end <= start2 + parent_page_size,
384 start2 + parent_page_size <= start1,
385 start1 <= m1_start,
386 ;
387 }
388 } else {
389 let parent_page_size = page_size((INC_LEVELS - path.len()) as PagingLevel);
390 let child_page_size = page_size((INC_LEVELS - path.len() - 1) as PagingLevel);
391 PageTableOwner(self.0.children[i2].unwrap()).view_rec_vaddr_range(path.push_tail(i2 as usize), m2);
392 PageTableOwner(self.0.children[i1].unwrap()).view_rec_vaddr_range(path.push_tail(i1 as usize), m1);
393 page_size_monotonic((INC_LEVELS - path.len() - 1) as PagingLevel, (INC_LEVELS - path.len()) as PagingLevel);
394 assert(child_page_size <= parent_page_size);
395 sibling_paths_disjoint(path, i2 as usize, i1 as usize, parent_page_size);
396 if vaddr(path.push_tail(i2 as usize)) + parent_page_size <= vaddr(path.push_tail(i1 as usize)) {
397 let start2: usize = vaddr(path.push_tail(i2 as usize));
398 let start1: usize = vaddr(path.push_tail(i1 as usize));
399 let m2_end: usize = m2.va_range.end;
400 let m1_start: usize = m1.va_range.start;
401 assert(m2_end <= start2 + child_page_size);
402 assert(start2 + child_page_size <= start2 + parent_page_size) by (nonlinear_arith)
403 requires
404 child_page_size <= parent_page_size,
405 ;
406 assert(m2_end <= start2 + parent_page_size) by (nonlinear_arith)
407 requires
408 m2_end <= start2 + child_page_size,
409 start2 + child_page_size <= start2 + parent_page_size,
410 ;
411 assert(start1 <= m1_start);
412 assert(m2_end <= m1_start) by (nonlinear_arith)
413 requires
414 m2_end <= start2 + parent_page_size,
415 start2 + parent_page_size <= start1,
416 start1 <= m1_start,
417 ;
418 } else {
419 let start1: usize = vaddr(path.push_tail(i1 as usize));
420 let start2: usize = vaddr(path.push_tail(i2 as usize));
421 let m1_end: usize = m1.va_range.end;
422 let m2_start: usize = m2.va_range.start;
423 assert(start1 + parent_page_size <= start2);
424 assert(m1_end <= start1 + child_page_size);
425 assert(start1 + child_page_size <= start1 + parent_page_size) by (nonlinear_arith)
426 requires
427 child_page_size <= parent_page_size,
428 ;
429 assert(m1_end <= start1 + parent_page_size) by (nonlinear_arith)
430 requires
431 m1_end <= start1 + child_page_size,
432 start1 + child_page_size <= start1 + parent_page_size,
433 ;
434 assert(start2 <= m2_start);
435 assert(m1_end <= m2_start) by (nonlinear_arith)
436 requires
437 m1_end <= start1 + parent_page_size,
438 start1 + parent_page_size <= start2,
439 start2 <= m2_start,
440 ;
441 }
442 }
443 }
444 }
445
446 pub proof fn view_rec_absent_empty(self, path: TreePath<NR_ENTRIES>)
448 requires
449 self.0.inv(),
450 self.0.value.is_absent(),
451 path.len() <= INC_LEVELS - 1,
452 ensures
453 self.view_rec(path) =~= set![],
454 { }
455
456 pub axiom fn view_rec_nr_children_zero_empty(self, path: TreePath<NR_ENTRIES>)
462 requires
463 self.0.inv(),
464 self.0.value.is_node(),
465 self.0.value.node.unwrap().meta_own.nr_children.value() == 0,
466 path.len() <= INC_LEVELS - 1,
467 path.len() == self.0.level,
468 ensures
469 self.view_rec(path) =~= set![];
470
471 pub open spec fn relate_region_pred(regions: MetaRegionOwners)
472 -> (spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool) {
473 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.relate_region(regions)
474 }
475
476 pub open spec fn relate_region(self, regions: MetaRegionOwners) -> bool
477 decreases INC_LEVELS - self.0.level when self.0.inv()
478 {
479 self.0.tree_predicate_map(self.0.value.path, Self::relate_region_pred(regions))
480 }
481
482 pub open spec fn path_tracked_pred(regions: MetaRegionOwners)
484 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
485 {
486 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
487 entry.meta_slot_paddr() is Some ==> {
488 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr().unwrap()))
489 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr().unwrap())].path_if_in_pt is Some
490 }
491 }
492 }
493
494 pub open spec fn relate_region_tracked_pred(regions: MetaRegionOwners)
495 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
496 {
497 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
498 &&& entry.meta_slot_paddr() is Some
499 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr().unwrap()))
500 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr().unwrap())].path_if_in_pt is Some
501 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr().unwrap())].path_if_in_pt.unwrap() == path
502 }
503 }
504
505 pub open spec fn path_correct_pred()
506 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
507 {
508 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| {
509 entry.path == path
510 }
511 }
512
513 pub open spec fn not_in_scope_pred()
514 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
515 {
516 |entry: EntryOwner<C>, _path: TreePath<NR_ENTRIES>| !entry.in_scope
517 }
518
519 pub proof fn tree_not_in_scope(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
522 requires
523 subtree.inv(),
524 ensures
525 subtree.tree_predicate_map(path, Self::not_in_scope_pred()),
526 decreases INC_LEVELS - subtree.level,
527 {
528 if subtree.level < INC_LEVELS - 1 {
530 assert forall |i: int|
531 0 <= i < subtree.children.len()
532 && (#[trigger] subtree.children[i]) is Some implies
533 subtree.children[i].unwrap().tree_predicate_map(
534 path.push_tail(i as usize), Self::not_in_scope_pred())
535 by {
536 Self::tree_not_in_scope(
537 subtree.children[i].unwrap(), path.push_tail(i as usize));
538 };
539 }
540 }
541
542 pub proof fn view_rec_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
548 requires
549 self.0.inv(),
550 path.len() <= INC_LEVELS - 1,
551 self.view_rec(path).contains(m),
552 ensures
553 m.page_size <= page_size((INC_LEVELS - path.len()) as PagingLevel),
554 decreases INC_LEVELS - path.len(),
555 {
556 admit()
557 }
558
559 pub proof fn view_rec_node_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
563 requires
564 self.0.inv(),
565 self.0.value.is_node(),
566 path.len() < INC_LEVELS - 1,
567 self.view_rec(path).contains(m),
568 ensures
569 m.page_size <= page_size(((INC_LEVELS - path.len()) - 1) as PagingLevel),
570 decreases INC_LEVELS - path.len(),
571 {
572 admit()
573 }
574
575 pub open spec fn is_prefix_of<const N: usize>(
577 prefix: TreePath<N>,
578 path: TreePath<N>,
579 ) -> bool {
580 &&& prefix.len() <= path.len()
581 &&& forall |i: int| 0 <= i < prefix.len() ==> prefix.index(i) == path.index(i)
582 }
583
584 pub proof fn prefix_transitive<const N: usize>(
586 p1: TreePath<N>,
587 p2: TreePath<N>,
588 p3: TreePath<N>,
589 )
590 requires
591 Self::is_prefix_of(p1, p2),
592 Self::is_prefix_of(p2, p3),
593 ensures
594 Self::is_prefix_of(p1, p3),
595 {
596 assert(p1.len() <= p3.len());
597 assert forall |i: int| 0 <= i < p1.len() implies p1.index(i) == p3.index(i) by {
598 assert(p1.index(i) == p2.index(i));
599 assert(p2.index(i) == p3.index(i));
600 };
601 }
602
603 pub proof fn prefix_push_different_indices(
604 prefix: TreePath<NR_ENTRIES>,
605 path: TreePath<NR_ENTRIES>,
606 i: usize,
607 j: usize,
608 )
609 requires
610 prefix.inv(),
611 path.inv(),
612 i != j,
613 Self::is_prefix_of(prefix.push_tail(i), path),
614 ensures
615 !Self::is_prefix_of(prefix.push_tail(j), path),
616 {
617 assert(path.index(prefix.len() as int) == i);
618 }
619
620 pub open spec fn is_at_pred(entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>)
621 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
622 {
623 |entry0: EntryOwner<C>, path0: TreePath<NR_ENTRIES>| {
624 path0 == path ==> entry0 == entry
625 }
626 }
627
628 pub open spec fn path_in_tree_pred(path: TreePath<NR_ENTRIES>)
629 -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool
630 {
631 |entry: EntryOwner<C>, path0: TreePath<NR_ENTRIES>|
632 Self::is_prefix_of(path0, path) ==>
633 !entry.is_node() ==>
634 path == path0
635 }
636
637 pub proof fn is_at_pred_eq(path: TreePath<NR_ENTRIES>, entry1: EntryOwner<C>, entry2: EntryOwner<C>)
638 requires
639 entry1.inv(),
640 OwnerSubtree::implies(Self::is_at_pred(entry1, path), Self::is_at_pred(entry2, path)),
641 ensures
642 entry1 == entry2,
643 {
644 assert(Self::is_at_pred(entry1, path)(entry1, path) ==>
645 Self::is_at_pred(entry2, path)(entry1, path));
646 }
647
648 pub proof fn is_at_holds_when_on_wrong_path(
649 subtree: OwnerSubtree<C>,
650 root_path: TreePath<NR_ENTRIES>,
651 dest_path: TreePath<NR_ENTRIES>,
652 entry: EntryOwner<C>,
653 )
654 requires
655 subtree.inv(),
656 dest_path.inv(),
657 !Self::is_prefix_of(root_path, dest_path),
658 root_path.len() <= INC_LEVELS - 1,
659 root_path.len() == subtree.level,
660 ensures
661 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry, dest_path)),
662 decreases INC_LEVELS - root_path.len()
663 {
664 if subtree.value.is_node() {
665 assert forall |i: int| 0 <= i < NR_ENTRIES implies
666 (#[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 {
667 Self::is_at_holds_when_on_wrong_path(subtree.children[i as int].unwrap(),
668 root_path.push_tail(i as usize), dest_path, entry);
669 };
670 }
671 }
672
673 pub proof fn path_in_tree_holds_when_on_wrong_path(
677 subtree: OwnerSubtree<C>,
678 root_path: TreePath<NR_ENTRIES>,
679 dest_path: TreePath<NR_ENTRIES>,
680 )
681 requires
682 subtree.inv(),
683 dest_path.inv(),
684 !Self::is_prefix_of(root_path, dest_path),
685 root_path.len() <= INC_LEVELS - 1,
686 root_path.len() == subtree.level,
687 ensures
688 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
689 decreases INC_LEVELS - root_path.len()
690 {
691 if subtree.value.is_node() {
692 assert forall |i: int| 0 <= i < NR_ENTRIES implies
693 (#[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 {
694 Self::path_in_tree_holds_when_on_wrong_path(subtree.children[i as int].unwrap(),
695 root_path.push_tail(i as usize), dest_path);
696 };
697 }
698 }
699
700 pub proof fn inv_implies_path_correct(
705 subtree: OwnerSubtree<C>,
706 path: TreePath<NR_ENTRIES>,
707 )
708 requires
709 subtree.inv(),
710 path.inv(),
711 path.len() <= INC_LEVELS - 1,
712 path.len() == subtree.level,
713 subtree.value.path == path,
714 ensures
715 subtree.tree_predicate_map(path, Self::path_correct_pred()),
716 decreases INC_LEVELS - path.len()
717 {
718 if subtree.level < INC_LEVELS - 1 {
719 assert forall|i: int| #![auto]
720 0 <= i < NR_ENTRIES && subtree.children[i] is Some implies
721 subtree.children[i].unwrap().tree_predicate_map(
722 path.push_tail(i as usize),
723 Self::path_correct_pred(),
724 ) by {
725 let child = subtree.children[i].unwrap();
726 assert(child.value.path == path.push_tail(i as usize)) by {
728 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::rel_children(subtree.value, i, Some(child.value)));
729 if subtree.value.is_node() {
730 assert(child.value.path == subtree.value.path.push_tail(i as usize));
731 } else {
732 assert(false);
734 }
735 };
736 assert(child.inv());
737 assert(child.level == subtree.level + 1);
738 assert((path.push_tail(i as usize)).len() == child.level) by {
739 path.push_tail_property_len(i as usize);
740 };
741 Self::inv_implies_path_correct(child, path.push_tail(i as usize));
742 };
743 }
744 }
745
746 pub axiom fn neq_old_from_path_disjoint(
754 subtree: OwnerSubtree<C>,
755 path_j: TreePath<NR_ENTRIES>,
756 old_entry: EntryOwner<C>,
757 regions: MetaRegionOwners,
758 )
759 requires
760 subtree.inv(),
761 subtree.value.path == path_j,
762 path_j.len() == subtree.level,
763 path_j.inv(),
764 path_j.len() <= INC_LEVELS - 1,
765 subtree.tree_predicate_map(path_j, Self::relate_region_pred(regions)),
766 subtree.tree_predicate_map(path_j, Self::path_tracked_pred(regions)),
767 old_entry.meta_slot_paddr() is Some,
768 old_entry.relate_region(regions),
769 regions.slot_owners[
770 frame_to_index(old_entry.meta_slot_paddr().unwrap())
771 ].path_if_in_pt is Some,
772 !Self::is_prefix_of(path_j, old_entry.path),
773 ensures
774 subtree.tree_predicate_map(
775 path_j,
776 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry),
777 );
778
779 pub proof fn is_at_eq_rec(
780 subtree: OwnerSubtree<C>,
781 root_path: TreePath<NR_ENTRIES>,
782 dest_path: TreePath<NR_ENTRIES>,
783 entry1: EntryOwner<C>,
784 entry2: EntryOwner<C>
785 )
786 requires
787 subtree.inv(),
788 dest_path.inv(),
789 root_path.inv(),
790 Self::is_prefix_of(root_path, dest_path),
791 root_path.len() <= INC_LEVELS - 1,
792 root_path.len() == subtree.level,
793 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
794 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry1, dest_path)),
795 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry2, dest_path)),
796 ensures
797 entry1 == entry2,
798 decreases INC_LEVELS - root_path.len()
799 {
800 if root_path == dest_path {
801 assert(subtree.value == entry1);
802 assert(subtree.value == entry2);
803 assert(entry1 == entry2);
804 } else if subtree.level == INC_LEVELS - 1 || !subtree.value.is_node() {
805 proof_from_false()
806 } else {
807 assert(root_path.len() < dest_path.len()) by {
808 assert(root_path.len() <= dest_path.len());
809 if root_path.len() == dest_path.len() {
810 assert(root_path =~= dest_path) by {
811 assert(root_path.0.len() == dest_path.0.len());
812 assert forall |i: int| 0 <= i < root_path.0.len() implies #[trigger] root_path.0[i] == dest_path.0[i] by {
813 assert(root_path.index(i) == dest_path.index(i));
814 };
815 };
816 assert(root_path == dest_path);
817 assert(false);
818 }
819 };
820 let i = dest_path.index(root_path.len() as int);
821 assert(0 <= i < NR_ENTRIES);
822 assert(subtree.children[i as int] is Some);
823 assert(Self::is_prefix_of(root_path.push_tail(i), dest_path));
824 Self::is_at_eq_rec(subtree.children[i as int].unwrap(), root_path.push_tail(i as usize),
825 dest_path, entry1, entry2);
826 }
827 }
828
829 pub proof fn view_rec_inversion(self,
830 path: TreePath<NR_ENTRIES>,
831 regions: MetaRegionOwners,
832 m: Mapping,
833 ) -> (entry: EntryOwner<C>)
834 requires
835 self.0.inv(),
836 path.len() == self.0.level,
837 self.view_rec(path).contains(m),
838 self.0.tree_predicate_map(path, Self::path_correct_pred()),
839 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
840 ensures
841 Self::is_prefix_of(path, entry.path),
842 regions.slot_owners[frame_to_index(m.pa_range.start)].path_if_in_pt == Some(entry.path),
843 m.va_range.start == vaddr(entry.path),
844 m.page_size == page_size((INC_LEVELS - entry.path.len()) as PagingLevel),
845 entry.is_frame(),
846 m.property == entry.frame.unwrap().prop,
847 self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path)),
848 self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path)),
849 entry.inv(),
850 decreases INC_LEVELS - path.len()
851 {
852 if self.0.value.is_frame() {
853 assert(Self::is_prefix_of(path, self.0.value.path));
854 assert(self.0.tree_predicate_map(path, Self::is_at_pred(self.0.value, self.0.value.path)));
855 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(self.0.value.path)));
856 self.0.value
857 } else if self.0.value.is_node() {
858 self.view_rec_contains(path, m);
859 let i = self.view_rec_contains_choose(path, m);
860 let entry = PageTableOwner(self.0.children[i].unwrap()).view_rec_inversion(path.push_tail(i as usize), regions, m);
861 Self::prefix_transitive(path, path.push_tail(i as usize), entry.path);
862 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path))) by {
863 assert forall |j: int| 0 <= j < NR_ENTRIES && #[trigger] self.0.children[j] is Some implies
864 self.0.children[j].unwrap().tree_predicate_map(path.push_tail(j as usize),
865 Self::is_at_pred(entry, entry.path))
866 by {
867 if j != i {
868 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path)) by {
869 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
870 }
871 Self::is_at_holds_when_on_wrong_path(self.0.children[j].unwrap(),
872 path.push_tail(j as usize), entry.path, entry);
873 }
874 };
875 };
876 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path))) by {
877 assert forall |j: int| 0 <= j < NR_ENTRIES && #[trigger] self.0.children[j] is Some implies
878 self.0.children[j].unwrap().tree_predicate_map(path.push_tail(j as usize),
879 Self::path_in_tree_pred(entry.path))
880 by {
881 if j != i {
882 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path)) by {
883 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
884 }
885 Self::path_in_tree_holds_when_on_wrong_path(self.0.children[j].unwrap(),
886 path.push_tail(j as usize), entry.path);
887 }
888 };
889 };
890 entry
891 } else {
892 proof_from_false()
893 }
894 }
895
896 pub proof fn view_rec_inversion_unique(self,
897 path: TreePath<NR_ENTRIES>,
898 regions: MetaRegionOwners,
899 m1: Mapping,
900 m2: Mapping,
901 )
902 requires
903 self.0.inv(),
904 path.len() <= INC_LEVELS - 1,
905 path.len() == self.0.level,
906 self.view_rec(path).contains(m1),
907 self.view_rec(path).contains(m2),
908 m1.pa_range.start == m2.pa_range.start,
909 m1.inv(),
910 m2.inv(),
911 self.0.tree_predicate_map(path, Self::path_tracked_pred(regions)),
912 self.0.tree_predicate_map(path, Self::path_correct_pred()),
913 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
914 ensures
915 m1 == m2,
916 {
917 let entry1 = self.view_rec_inversion(path, regions, m1);
918 let entry2 = self.view_rec_inversion(path, regions, m2);
919
920 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry1, entry1.path)));
921 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry2, entry2.path)));
922
923 Self::is_at_eq_rec(self.0, path, entry1.path, entry1, entry2);
924 }
925
926}
927
928impl<C: PageTableConfig> Inv for PageTableOwner<C> {
929 open spec fn inv(self) -> bool {
930 &&& self.0.inv()
931 &&& self.0.value.is_node()
932 &&& self.0.value.path.len() <= INC_LEVELS - 1
933 &&& self.0.value.path.inv()
934 &&& self.0.value.path.len() == self.0.level
935 &&& self.0.tree_predicate_map(self.0.value.path, Self::path_correct_pred())
936 }
937}
938
939impl<C: PageTableConfig> View for PageTableOwner<C> {
940 type V = PageTableView;
941
942 open spec fn view(&self) -> <Self as View>::V {
943 let mappings = self.view_rec(self.0.value.path);
944 PageTableView {
945 mappings
946 }
947 }
948}
949
950}