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::*;
9
10use vstd_extra::drop_tracking::*;
11use vstd_extra::ghost_tree::*;
12use vstd_extra::ownership::*;
13use vstd_extra::prelude::TreeNodeValue;
14
15use crate::mm::{
16 Paddr, PagingConstsTrait, PagingLevel, Vaddr, page_size,
17 page_table::{EntryOwner, EntryOwnerKind},
18};
19
20use crate::mm::frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED};
21use crate::mm::page_table::{PageTableEntryTrait, PageTableGuard};
22
23use crate::specs::arch::*;
24use crate::specs::mm::frame::{mapping::frame_to_index, meta_region_owners::MetaRegionOwners};
25use crate::specs::mm::page_table::cursor::page_size_lemmas::{
26 lemma_page_size_divides, lemma_page_size_ge_page_size, lemma_page_size_spec_values,
27};
28use crate::specs::mm::page_table::*;
29
30use core::ops::Deref;
31
32verus! {
33
34#[verifier::inline]
35pub open spec fn vaddr_shift_bits<const L: usize>(idx: int) -> nat
36 recommends
37 0 < L,
38 idx < L,
39{
40 (12 + 9 * (L - 1 - idx)) as nat
41}
42
43#[verifier::inline]
44pub open spec fn vaddr_shift<const L: usize>(idx: int) -> usize
45 recommends
46 0 < L,
47 idx < L,
48{
49 pow2(vaddr_shift_bits::<L>(idx)) as usize
50}
51
52#[verifier::inline]
53pub open spec fn vaddr_make<const L: usize>(idx: int, offset: usize) -> usize
54 recommends
55 0 < L,
56 idx < L,
57 0 <= offset < 512,
58{
59 (vaddr_shift::<L>(idx) * offset) as usize
60}
61
62pub open spec fn rec_vaddr(
63 path: TreePath<NR_ENTRIES>,
64 idx: int,
65) -> usizedecreases path.len() - idx,
71 when 0 <= idx <= path.len()
72{
73 if idx == path.len() {
74 0
75 } else {
76 let offset: usize = path.index(idx);
77 (vaddr_make::<NR_LEVELS>(idx, offset) + rec_vaddr(path, idx + 1)) as usize
78 }
79}
80
81pub open spec fn vaddr(path: TreePath<NR_ENTRIES>) -> usize {
82 rec_vaddr(path, 0)
83}
84
85pub open spec fn vaddr_at(path: TreePath<NR_ENTRIES>, leading_bits: int) -> usize {
92 (vaddr(path) + leading_bits * 0x1_0000_0000_0000int) as usize
93}
94
95pub open spec fn vaddr_of<C: PageTableConfig>(path: TreePath<NR_ENTRIES>) -> usize {
101 vaddr_at(path, C::LEADING_BITS_spec() as int)
102}
103
104#[verifier::rlimit(400)]
108pub proof fn lemma_vaddr_strict_bound(path: TreePath<NR_ENTRIES>)
109 requires
110 path.inv(),
111 path.len() <= INC_LEVELS - 1,
112 ensures
113 vaddr(path) < 0x1_0000_0000_0000int,
114{
115 broadcast use TreePath::index_satisfies_elem_inv;
116 broadcast use TreePath::push_tail_property;
117
118 lemma_page_size_spec_values();
119 vstd::arithmetic::power2::lemma2_to64();
120 vstd::arithmetic::power2::lemma2_to64_rest();
121 if path.len() == 0 {
122 assert(rec_vaddr(path, 0) == 0);
123 } else if path.len() == 1 {
124 let i0 = path.index(0);
125 assert(rec_vaddr(path, 1) == 0);
126 assert(rec_vaddr(path, 0) == vaddr_make::<NR_LEVELS>(0, i0) as usize);
127 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
128 assert(0x80_0000_0000usize * i0 < 0x1_0000_0000_0000int) by (nonlinear_arith)
129 requires
130 i0 < 512,
131 ;
132 } else if path.len() == 2 {
133 let i0 = path.index(0);
134 let i1 = path.index(1);
135 assert(rec_vaddr(path, 2) == 0);
136 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1) as usize);
137 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
138 1,
139 i1,
140 )) as usize);
141 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
142 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
143 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 < 0x1_0000_0000_0000int)
144 by (nonlinear_arith)
145 requires
146 i0 < 512,
147 i1 < 512,
148 ;
149 } else if path.len() == 3 {
150 let i0 = path.index(0);
151 let i1 = path.index(1);
152 let i2 = path.index(2);
153 assert(rec_vaddr(path, 3) == 0);
154 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2) as usize);
155 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
156 2,
157 i2,
158 )) as usize);
159 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
160 1,
161 i1,
162 ) + vaddr_make::<NR_LEVELS>(2, i2)) as usize);
163 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
164 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
165 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
166 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
167 < 0x1_0000_0000_0000int) by (nonlinear_arith)
168 requires
169 i0 < 512,
170 i1 < 512,
171 i2 < 512,
172 ;
173 } else {
174 assert(path.len() == 4);
175 let i0 = path.index(0);
176 let i1 = path.index(1);
177 let i2 = path.index(2);
178 let i3 = path.index(3);
179 assert(rec_vaddr(path, 4) == 0);
180 assert(rec_vaddr(path, 3) == vaddr_make::<NR_LEVELS>(3, i3) as usize);
181 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(
182 3,
183 i3,
184 )) as usize);
185 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
186 2,
187 i2,
188 ) + vaddr_make::<NR_LEVELS>(3, i3)) as usize);
189 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
190 1,
191 i1,
192 ) + vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(3, i3)) as usize);
193 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
194 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
195 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
196 assert(vaddr_make::<NR_LEVELS>(3, i3) == 0x1000usize * i3) by (compute);
197 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2 + 0x1000usize
198 * i3 < 0x1_0000_0000_0000int) by (nonlinear_arith)
199 requires
200 i0 < 512,
201 i1 < 512,
202 i2 < 512,
203 i3 < 512,
204 ;
205 }
206}
207
208pub proof fn lemma_vaddr_top_index_cell(path: TreePath<NR_ENTRIES>)
212 requires
213 path.inv(),
214 1 <= path.len() <= INC_LEVELS - 1,
215 ensures
216 (path.index(0)) * 0x80_0000_0000int <= vaddr(path),
217 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= (path.index(0) + 1)
218 * 0x80_0000_0000int,
219{
220 broadcast use TreePath::index_satisfies_elem_inv;
221
222 lemma_page_size_spec_values();
223 vstd::arithmetic::power2::lemma2_to64();
224 vstd::arithmetic::power2::lemma2_to64_rest();
225 let i0 = path.index(0);
226 if path.len() == 1 {
227 assert(rec_vaddr(path, 1) == 0);
228 assert(rec_vaddr(path, 0) == vaddr_make::<NR_LEVELS>(0, i0) as usize);
229 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
230 assert(page_size(4) == 0x80_0000_0000usize);
231 assert((0x80_0000_0000int * i0) + 0x80_0000_0000int == (i0 + 1) * 0x80_0000_0000int)
232 by (nonlinear_arith);
233 } else if path.len() == 2 {
234 let i1 = path.index(1);
235 assert(rec_vaddr(path, 2) == 0);
236 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1) as usize);
237 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
238 1,
239 i1,
240 )) as usize);
241 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
242 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
243 assert(page_size(3) == 0x4000_0000usize);
244 assert(0x80_0000_0000int * i0 <= 0x80_0000_0000int * i0 + 0x4000_0000int * i1)
245 by (nonlinear_arith);
246 assert(0x80_0000_0000int * i0 + 0x4000_0000int * i1 + 0x4000_0000int <= (i0 + 1)
247 * 0x80_0000_0000int) by (nonlinear_arith)
248 requires
249 i1 < 512,
250 ;
251 } else if path.len() == 3 {
252 let i1 = path.index(1);
253 let i2 = path.index(2);
254 assert(rec_vaddr(path, 3) == 0);
255 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2) as usize);
256 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
257 2,
258 i2,
259 )) as usize);
260 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
261 1,
262 i1,
263 ) + vaddr_make::<NR_LEVELS>(2, i2)) as usize);
264 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
265 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
266 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
267 assert(page_size(2) == 0x20_0000usize);
268 assert(0x80_0000_0000int * i0 <= 0x80_0000_0000int * i0 + 0x4000_0000int * i1 + 0x20_0000int
269 * i2) by (nonlinear_arith);
270 assert(0x80_0000_0000int * i0 + 0x4000_0000int * i1 + 0x20_0000int * i2 + 0x20_0000int <= (
271 i0 + 1) * 0x80_0000_0000int) by (nonlinear_arith)
272 requires
273 i1 < 512,
274 i2 < 512,
275 ;
276 } else {
277 assert(path.len() == 4);
278 let i1 = path.index(1);
279 let i2 = path.index(2);
280 let i3 = path.index(3);
281 assert(rec_vaddr(path, 4) == 0);
282 assert(rec_vaddr(path, 3) == vaddr_make::<NR_LEVELS>(3, i3) as usize);
283 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(
284 3,
285 i3,
286 )) as usize);
287 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
288 2,
289 i2,
290 ) + vaddr_make::<NR_LEVELS>(3, i3)) as usize);
291 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
292 1,
293 i1,
294 ) + vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(3, i3)) as usize);
295 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
296 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
297 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
298 assert(vaddr_make::<NR_LEVELS>(3, i3) == 0x1000usize * i3) by (compute);
299 assert(page_size(1) == 0x1000usize);
300 assert(0x80_0000_0000int * i0 <= 0x80_0000_0000int * i0 + 0x4000_0000int * i1 + 0x20_0000int
301 * i2 + 0x1000int * i3) by (nonlinear_arith);
302 assert(0x80_0000_0000int * i0 + 0x4000_0000int * i1 + 0x20_0000int * i2 + 0x1000int * i3
303 + 0x1000int <= (i0 + 1) * 0x80_0000_0000int) by (nonlinear_arith)
304 requires
305 i1 < 512,
306 i2 < 512,
307 i3 < 512,
308 ;
309 }
310}
311
312pub proof fn lemma_vaddr_of_eq_int<C: PageTableConfig>(path: TreePath<NR_ENTRIES>)
316 requires
317 path.inv(),
318 path.len() <= INC_LEVELS - 1,
319 ensures
320 vaddr_of::<C>(path) == vaddr(path) + C::LEADING_BITS_spec() as int * 0x1_0000_0000_0000int,
321{
322 C::lemma_page_table_config_constant_properties();
323 lemma_vaddr_strict_bound(path);
324 let lb = C::LEADING_BITS_spec() as int;
325 let v = vaddr(path) as int;
326 assert(lb * 0x1_0000_0000_0000int <= 0xffff_int * 0x1_0000_0000_0000int) by (nonlinear_arith)
328 requires
329 lb < 0x1_0000int,
330 lb >= 0,
331 ;
332 assert(v + lb * 0x1_0000_0000_0000int < 0x1_0000_0000_0000_0000int) by (nonlinear_arith)
333 requires
334 v < 0x1_0000_0000_0000int,
335 lb < 0x1_0000int,
336 lb >= 0,
337 ;
338}
339
340pub proof fn page_size_monotonic(a: PagingLevel, b: PagingLevel)
342 requires
343 1 <= a <= b <= NR_LEVELS + 1,
344 ensures
345 page_size(a) <= page_size(b),
346{
347 if a == b {
348 } else {
349 let ps_a = page_size(a);
350 let ps_b = page_size(b);
351
352 lemma_page_size_ge_page_size(a);
353 lemma_page_size_ge_page_size(b);
354
355 lemma_page_size_divides(a, b);
356 assert(ps_b % ps_a == 0);
357
358 assert(ps_a <= ps_b) by {
359 if ps_b < ps_a {
360 vstd::arithmetic::div_mod::lemma_small_mod(ps_b as nat, ps_a as nat);
361 assert(ps_b % ps_a == ps_b);
362 assert(ps_b % ps_a == 0);
363 assert(false);
364 }
365 }
366 }
367}
368
369pub proof fn sibling_paths_disjoint<C: PageTableConfig>(
376 prefix: TreePath<NR_ENTRIES>,
377 j: usize,
378 k: usize,
379 size: usize,
380)
381 requires
382 prefix.inv(),
383 prefix.len() < INC_LEVELS - 1,
384 j < NR_ENTRIES,
385 k < NR_ENTRIES,
386 j != k,
387 size == page_size((INC_LEVELS - prefix.len() - 1) as PagingLevel),
388 ensures
389 vaddr(prefix.push_tail(j)) + size <= vaddr(prefix.push_tail(k)) || vaddr(
390 prefix.push_tail(k),
391 ) + size <= vaddr(prefix.push_tail(j)),
392{
393 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, j);
394 PageTableOwner::<C>::lemma_vaddr_push_tail_eq(prefix, k);
395 let s = size as int;
396 let vp = vaddr(prefix) as int;
397 let vj = vaddr(prefix.push_tail(j)) as int;
398 let vk = vaddr(prefix.push_tail(k)) as int;
399 if j < k {
400 assert(vj + s <= vk) by (nonlinear_arith)
401 requires
402 vj == vp + j * s,
403 vk == vp + k * s,
404 j < k,
405 s >= 0,
406 ;
407 } else {
408 assert(vk + s <= vj) by (nonlinear_arith)
409 requires
410 vj == vp + j * s,
411 vk == vp + k * s,
412 k < j,
413 s >= 0,
414 ;
415 }
416}
417
418impl<C: PageTableConfig, const L: usize> TreeNodeValue<L> for EntryOwner<C> {
419 open spec fn default(lv: nat) -> Self {
420 Self {
421 kind: EntryOwnerKind::Absent,
422 path: TreePath::new(Seq::empty()),
423 parent_level: (INC_LEVELS - lv) as PagingLevel,
424 }
425 }
426
427 proof fn default_preserves_inv() {
428 }
429
430 open spec fn la_inv(self, lv: nat) -> bool {
431 self.is_node() ==> lv < L - 1
432 }
433
434 proof fn default_preserves_la_inv() {
435 }
436
437 open spec fn rel_children(self, i: int, child: Option<Self>) -> bool {
440 true
441 }
442
443 proof fn default_preserves_rel_children(self, lv: nat) {
444 }
445}
446
447pub const INC_LEVELS: usize = NR_LEVELS + 1;
448
449pub type OwnerSubtree<C> = Node<EntryOwner<C>, NR_ENTRIES, INC_LEVELS>;
459
460pub open spec fn allocated_empty_node_owner<C: PageTableConfig>(
469 owner: OwnerSubtree<C>,
470 level: PagingLevel,
471) -> bool {
472 &&& owner.inv()
473 &&& owner.value.is_node()
474 &&& owner.value.path == TreePath::<NR_ENTRIES>::new(Seq::empty())
475 &&& owner.value.parent_level == (level + 1) as PagingLevel
476 &&& owner.value.node().level
477 == level
478 &&& owner.level == (INC_LEVELS - level - 1) as nat
483 &&& owner.value.node().inv()
484 &&& !owner.value.node().children_perm.value().all(|child: C::E| child.is_present())
485 &&& forall|i: int|
486 #![auto]
487 0 <= i < NR_ENTRIES ==> {
488 &&& owner.children[i] is Some
489 &&& owner.children[i]->0.value.is_absent()
490 &&& owner.children[i]->0.value.inv()
491 &&& owner.children[i]->0.value.path == owner.value.path.push_tail(i as usize)
492 }
493 &&& forall|i: int|
494 #![auto]
495 0 <= i < NR_ENTRIES ==> owner.children[i]->0.value.match_pte(
496 owner.value.node().children_perm.value()[i],
497 owner.children[i]->0.value.parent_level,
498 )
499 &&& forall|i: int|
500 #![auto]
501 0 <= i < NR_ENTRIES ==> owner.children[i]->0.value.parent_level
502 == owner.value.node().level
503 &&& forall|j: int|
508 0 <= j < NR_ENTRIES ==> #[trigger] owner.value.node().children_perm.value()[j]
509 == C::E::new_absent_spec()
510}
511
512pub open spec fn allocated_empty_node_grandchildren_none<C: PageTableConfig>(
520 owner: OwnerSubtree<C>,
521) -> bool {
522 forall|i: int, j: int|
523 0 <= i < NR_ENTRIES && 0 <= j < NR_ENTRIES
524 ==> #[trigger] owner.children[i]->0.children[j] is None
525}
526
527pub proof fn rebase_freshly_allocated_children_at<C: PageTableConfig>(
532 tracked owner: &mut OwnerSubtree<C>,
533 new_path: TreePath<NR_ENTRIES>,
534 i: usize,
535)
536 requires
537 i <= NR_ENTRIES,
538 old(owner).children.len() == NR_ENTRIES,
539 new_path.inv(),
540 forall|j: int| i <= j < NR_ENTRIES ==> (#[trigger] old(owner).children[j]) is Some,
541 ensures
542 final(owner).value == old(owner).value,
543 final(owner).level == old(owner).level,
544 final(owner).children.len() == NR_ENTRIES,
545 forall|j: int|
546 0 <= j < i ==> (#[trigger] final(owner).children[j]) == old(owner).children[j],
547 forall|j: int|
548 i <= j < NR_ENTRIES ==> {
549 let c_old = old(owner).children[j]->0;
550 let c_new = (#[trigger] final(owner).children[j])->0;
551 &&& final(owner).children[j] is Some
552 &&& c_new.value == EntryOwner {
553 path: new_path.push_tail(j as usize),
554 ..c_old.value
555 }
556 &&& c_new.level == c_old.level
557 &&& c_new.children == c_old.children
558 },
559 decreases NR_ENTRIES - i,
560{
561 if i < NR_ENTRIES {
562 let tracked mut child_opt = owner.children.tracked_remove(i as int);
563 let tracked mut child = child_opt.tracked_unwrap();
564 child.value.path = new_path.push_tail(i);
565 owner.children.tracked_insert(i as int, Some(child));
566 rebase_freshly_allocated_children_at(owner, new_path, (i + 1) as usize);
567 }
568}
569
570pub proof fn rebase_freshly_allocated_children<C: PageTableConfig>(
580 tracked owner: &mut OwnerSubtree<C>,
581 new_path: TreePath<NR_ENTRIES>,
582)
583 requires
584 old(owner).children.len() == NR_ENTRIES,
585 new_path.inv(),
586 forall|i: int| 0 <= i < NR_ENTRIES ==> (#[trigger] old(owner).children[i]) is Some,
587 ensures
588 final(owner).value == old(owner).value,
589 final(owner).level == old(owner).level,
590 final(owner).children.len() == NR_ENTRIES,
591 forall|i: int|
592 0 <= i < NR_ENTRIES ==> {
593 let c_old = old(owner).children[i]->0;
594 let c_new = (#[trigger] final(owner).children[i])->0;
595 &&& final(owner).children[i] is Some
596 &&& c_new.value == EntryOwner {
597 path: new_path.push_tail(i as usize),
598 ..c_old.value
599 }
600 &&& c_new.level == c_old.level
601 &&& c_new.children == c_old.children
602 },
603{
604 rebase_freshly_allocated_children_at(owner, new_path, 0);
605}
606
607pub proof fn fresh_node_tree_predicate_map<C: PageTableConfig>(
616 node: OwnerSubtree<C>,
617 path: TreePath<NR_ENTRIES>,
618 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
619)
620 requires
621 node.inv(),
622 node.level < INC_LEVELS - 1,
623 f(node.value, path),
624 forall|i: int| 0 <= i < NR_ENTRIES ==> #[trigger] node.children[i] is Some,
625 forall|i: int, j: int|
626 0 <= i < NR_ENTRIES && 0 <= j < NR_ENTRIES
627 ==> #[trigger] node.children[i].unwrap().children[j] is None,
628 forall|i: int|
629 0 <= i < NR_ENTRIES ==> #[trigger] f(
630 node.children[i].unwrap().value,
631 path.push_tail(i as usize),
632 ),
633 ensures
634 node.tree_predicate_map(path, f),
635{
636 assert forall|i: int|
637 0 <= i < node.children.len()
638 && #[trigger] node.children[i] is Some implies node.children[i]->0.tree_predicate_map(
639 path.push_tail(i as usize),
640 f,
641 ) by {
642 node.child_some_properties(i as usize);
645 let child = node.children[i]->0;
646 assert(child.children.len() == NR_ENTRIES);
647 assert(forall|j: int|
648 0 <= j < child.children.len() ==> #[trigger] child.children[j] is None);
649 };
650}
651
652pub tracked struct PageTableOwner<C: PageTableConfig>(pub OwnerSubtree<C>);
659
660impl<C: PageTableConfig> PageTableOwner<C> {
661 pub open spec fn pt_edge_at(parent: OwnerSubtree<C>, i: int) -> bool {
663 &&& parent.children[i] is Some
664 &&& parent.children[i]->0.value.path.len() == parent.value.node().tree_level
665 + 1
666 &&& (parent.children[i]->0.value.match_pte(
674 parent.value.node().children_perm.value()[i],
675 parent.value.node().level,
676 ) || (parent.value.node().level == NR_LEVELS && C::LEADING_BITS_spec() == 0
677 && parent.children[i]->0.value.borrowed_match_pte(
678 parent.value.node().children_perm.value()[i],
679 parent.value.node().level,
680 )))
681 &&& parent.children[i]->0.value.path == parent.value.path.push_tail(i as usize)
682 &&& parent.children[i]->0.value.parent_level == parent.value.node().level
683 }
684
685 pub open spec fn pt_inv_at_depth(self, depth: nat) -> bool
689 decreases depth,
690 {
691 if depth == 0 {
692 true
693 } else if self.0.value.is_node() {
694 forall|i: int|
695 #![trigger self.0.children[i]]
696 0 <= i < NR_ENTRIES ==> Self::pt_edge_at(self.0, i) && PageTableOwner(
697 self.0.children[i]->0,
698 ).pt_inv_at_depth((depth - 1) as nat)
699 } else {
700 forall|i: int|
701 #![trigger self.0.children[i]]
702 0 <= i < NR_ENTRIES ==> self.0.children[i] is None
703 }
704 }
705
706 pub open spec fn pt_inv(self) -> bool {
711 &&& self.0.inv()
712 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level) as nat)
713 }
714
715 pub proof fn pt_inv_unroll(self, i: int)
716 requires
717 self.pt_inv(),
718 self.0.value.is_node(),
719 0 <= i < NR_ENTRIES,
720 ensures
721 Self::pt_edge_at(self.0, i),
722 PageTableOwner(self.0.children[i]->0).pt_inv(),
723 {
724 let depth = (INC_LEVELS - self.0.level) as nat;
727 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::la_inv(self.0.value, self.0.level));
728 }
729
730 pub proof fn pt_inv_non_node(self, i: int)
731 requires
732 self.pt_inv(),
733 !self.0.value.is_node(),
734 0 <= i < NR_ENTRIES,
735 ensures
736 self.0.children[i] is None,
737 {
738 let depth = (INC_LEVELS - self.0.level) as nat;
739 if depth == 0 {
740 assert(self.0.level >= INC_LEVELS);
741 }
742 }
743
744 pub proof fn non_node_pt_inv_at_depth(self, depth: nat)
748 requires
749 !self.0.value.is_node(),
750 forall|j: int| 0 <= j < NR_ENTRIES ==> #[trigger] self.0.children[j] is None,
751 ensures
752 self.pt_inv_at_depth(depth),
753 decreases depth,
754 {
755 }
756
757 #[verifier::spinoff_prover]
766 pub proof fn allocated_empty_node_pt_inv(owner: OwnerSubtree<C>)
767 requires
768 owner.inv(),
769 owner.value.is_node(),
770 owner.children.len() == NR_ENTRIES,
771 forall|i: int|
772 0 <= i < NR_ENTRIES ==> {
773 let c = #[trigger] owner.children[i];
774 &&& c is Some
775 &&& c->0.value.is_absent()
776 &&& c->0.value.path.len() == owner.value.node().tree_level + 1
777 &&& c->0.value.match_pte(
778 owner.value.node().children_perm.value()[i],
779 owner.value.node().level,
780 )
781 &&& c->0.value.path == owner.value.path.push_tail(i as usize)
782 &&& c->0.value.parent_level == owner.value.node().level
783 },
784 allocated_empty_node_grandchildren_none(owner),
785 ensures
786 PageTableOwner(owner).pt_inv(),
787 {
788 let depth = (INC_LEVELS - owner.level) as nat;
789 assert(<EntryOwner<C> as TreeNodeValue<INC_LEVELS>>::la_inv(owner.value, owner.level));
791 assert forall|i: int| 0 <= i < NR_ENTRIES implies #[trigger] Self::pt_edge_at(owner, i)
794 && PageTableOwner(owner.children[i].unwrap()).pt_inv_at_depth((depth - 1) as nat) by {
795 let child = owner.children[i].unwrap();
796 assert(Self::pt_edge_at(owner, i));
798 assert(child.inv());
802 assert(child.value.inv());
803 assert(child.value.inv_base());
804 assert(!child.value.is_node());
805 PageTableOwner(child).non_node_pt_inv_at_depth((depth - 1) as nat);
808 };
809 }
810
811 pub open spec fn top_level_indices_absent(self) -> bool {
816 let range = C::TOP_LEVEL_INDEX_RANGE_spec();
817 self.0.value.is_node() ==> forall|i: int|
818 #![trigger self.0.children[i]]
819 0 <= i < NR_ENTRIES && !(range.start <= i < range.end) ==> self.0.children[i] is Some
820 && self.0.children[i]->0.value.is_absent()
821 }
822
823 pub open spec fn view_rec_node_children(self, path: TreePath<NR_ENTRIES>) -> Seq<Set<Mapping>>
824 decreases INC_LEVELS - path.len(), 0nat,
825 when self.0.inv() && path.len() < INC_LEVELS - 1
826 {
827 self.0.children.map(
828 |i, child: Option<OwnerSubtree<C>>|
829 if child is Some {
830 PageTableOwner(child->0).view_rec(path.push_tail(i as usize))
831 } else {
832 Set::empty()
833 },
834 )
835 }
836
837 pub open spec fn view_rec(self, path: TreePath<NR_ENTRIES>) -> Set<Mapping>
838 decreases INC_LEVELS - path.len(), 1nat,
839 when self.0.inv() && path.len() <= INC_LEVELS - 1
840 {
841 if self.0.value.is_frame() {
842 let va = vaddr_of::<C>(path);
843 let pt_level = INC_LEVELS - path.len();
844 let page_size = page_size(pt_level as PagingLevel);
845
846 set![Mapping {
847 va_range: Range { start: va as int, end: va + page_size },
848 pa_range: Range {
849 start: self.0.value.frame().mapped_pa,
850 end: (self.0.value.frame().mapped_pa + page_size) as Paddr,
851 },
852 page_size: page_size,
853 property: self.0.value.frame().prop,
854 }]
855 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
856 self.view_rec_node_children(path).to_set().flatten()
857 } else {
858 set![]
859 }
860 }
861
862 pub broadcast proof fn lemma_view_rec_contains_intro(
863 self,
864 path: TreePath<NR_ENTRIES>,
865 m: Mapping,
866 i: int,
867 )
868 requires
869 self.0.inv(),
870 path.len() < INC_LEVELS - 1,
871 self.0.value.is_node(),
872 0 <= i < self.0.children.len(),
873 self.0.children[i] is Some,
874 #[trigger] PageTableOwner(self.0.children[i]->0).view_rec(
875 path.push_tail(i as usize),
876 ).contains(m),
877 ensures
878 self.view_rec(path).contains(m),
879 {
880 broadcast use vstd::seq_lib::group_seq_properties;
881
882 let mapped = self.view_rec_node_children(path);
883 assert(self.0.value.kind is Node);
884 assert(!self.0.value.is_frame());
885 assert(mapped[i].contains(m));
886 mapped.to_set_ensures();
887 assert(mapped.to_set().contains(mapped[i]));
888 mapped.to_set().lemma_flatten_contains(m);
889 }
890
891 pub broadcast proof fn lemma_view_rec_contains(self, path: TreePath<NR_ENTRIES>)
892 requires
893 self.0.inv(),
894 path.len() < INC_LEVELS - 1,
895 self.0.value.is_node(),
896 ensures
897 #![trigger self.view_rec(path)]
898 forall|m: Mapping|
899 #![trigger self.view_rec(path).contains(m)]
900 self.view_rec(path).contains(m) ==> exists|i: int|
901 #![trigger self.0.children[i]]
902 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
903 self.0.children[i]->0,
904 ).view_rec(path.push_tail(i as usize)).contains(m),
905 {
906 broadcast use vstd::seq_lib::group_seq_properties;
907
908 assert forall|m: Mapping| #[trigger] self.view_rec(path).contains(m) implies exists|i: int|
909 #![trigger self.0.children[i]]
910 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
911 self.0.children[i]->0,
912 ).view_rec(path.push_tail(i as usize)).contains(m) by {
913 let mapped = self.view_rec_node_children(path);
914 assert(self.0.value.kind is Node);
915 assert(!self.0.value.is_frame());
916 mapped.to_set().lemma_flatten_contains(m);
917 let elem_s = choose|elem_s: Set<Mapping>| #[trigger]
918 mapped.to_set().contains(elem_s) && elem_s.contains(m);
919 mapped.to_set_ensures();
920 assert(mapped.contains(elem_s));
921 let i = mapped.lemma_contains_to_index(elem_s);
922 if self.0.children[i] is Some {
923 assert(mapped[i] == PageTableOwner(self.0.children[i]->0).view_rec(
924 path.push_tail(i as usize),
925 ));
926 } else {
927 assert(mapped[i] == Set::<Mapping>::empty());
928 assert(false);
929 }
930 }
931 }
932
933 pub proof fn view_rec_contains_choose(self, path: TreePath<NR_ENTRIES>, m: Mapping) -> (i: int)
934 requires
935 self.0.inv(),
936 path.len() < INC_LEVELS - 1,
937 self.view_rec(path).contains(m),
938 self.0.value.is_node(),
939 ensures
940 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
941 self.0.children[i]->0,
942 ).view_rec(path.push_tail(i as usize)).contains(m),
943 {
944 broadcast use PageTableOwner::group_lemmas;
945
946 choose|i: int|
947 #![auto]
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 }
952
953 #[verifier::rlimit(400)]
955 pub proof fn lemma_vaddr_push_tail_eq(path: TreePath<NR_ENTRIES>, i: usize)
956 requires
957 path.inv(),
958 path.len() < INC_LEVELS - 1,
959 i < NR_ENTRIES,
960 ensures
961 vaddr(path.push_tail(i)) == vaddr(path) + i * page_size(
962 (INC_LEVELS - path.len() - 1) as PagingLevel,
963 ),
964 vaddr(path) + (i + 1) * page_size((INC_LEVELS - path.len() - 1) as PagingLevel)
965 <= usize::MAX,
966 {
967 broadcast use TreePath::push_tail_property;
968 broadcast use TreePath::index_satisfies_elem_inv;
969
970 lemma_page_size_spec_values();
971 vstd::arithmetic::power2::lemma2_to64();
972 vstd::arithmetic::power2::lemma2_to64_rest();
973 let pt = path.push_tail(i);
974 if path.len() >= 1 {
975 Self::lemma_vaddr_path_alignment_and_bound(path);
976 }
977 if path.len() == 0 {
978 assert(rec_vaddr(path, 0) == 0);
979 assert(pt.len() == 1);
980 assert(rec_vaddr(pt, 1) == 0);
981 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i) + 0) as usize);
982 assert(vaddr_make::<NR_LEVELS>(0, i) == 0x80_0000_0000usize * i) by (compute);
983 assert(page_size(4) == 0x80_0000_0000usize);
984 assert(0x80_0000_0000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
985 requires
986 i < 512,
987 ;
988 } else if path.len() == 1 {
989 let i0 = path.index(0);
990 assert(rec_vaddr(path, 1) == 0);
991 assert(rec_vaddr(path, 0) == vaddr_make::<NR_LEVELS>(0, i0) as usize);
992 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
993 assert(rec_vaddr(path, 0) == 0x80_0000_0000usize * i0);
994 assert(pt.len() == 2);
995 assert(pt.index(0) == i0);
996 assert(pt.index(1) == i);
997 assert(rec_vaddr(pt, 2) == 0);
998 assert(rec_vaddr(pt, 1) == vaddr_make::<NR_LEVELS>(1, i) as usize);
999 assert(vaddr_make::<NR_LEVELS>(1, i) == 0x4000_0000usize * i) by (compute);
1000 assert(rec_vaddr(pt, 0) == (0x80_0000_0000usize * i0) + 0x4000_0000usize * i);
1001 assert(page_size(3) == 0x4000_0000usize);
1002 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * (i + 1) <= usize::MAX)
1003 by (nonlinear_arith)
1004 requires
1005 i0 < 512,
1006 i < 512,
1007 ;
1008 } else if path.len() == 2 {
1009 let i0 = path.index(0);
1010 let i1 = path.index(1);
1011 assert(rec_vaddr(path, 2) == 0);
1012 assert(rec_vaddr(path, 1) == vaddr_make::<NR_LEVELS>(1, i1) as usize);
1013 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
1014 1,
1015 i1,
1016 )) as usize);
1017 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1018 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1019 assert(pt.len() == 3);
1020 assert(pt.index(0) == i0);
1021 assert(pt.index(1) == i1);
1022 assert(pt.index(2) == i);
1023 assert(rec_vaddr(pt, 3) == 0);
1024 assert(rec_vaddr(pt, 2) == vaddr_make::<NR_LEVELS>(2, i) as usize);
1025 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
1026 2,
1027 i,
1028 )) as usize);
1029 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
1030 1,
1031 i1,
1032 ) + vaddr_make::<NR_LEVELS>(2, i)) as usize);
1033 assert(vaddr_make::<NR_LEVELS>(2, i) == 0x20_0000usize * i) by (compute);
1034 assert(page_size(2) == 0x20_0000usize);
1035 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * (i + 1)
1036 <= usize::MAX) by (nonlinear_arith)
1037 requires
1038 i0 < 512,
1039 i1 < 512,
1040 i < 512,
1041 ;
1042 } else {
1043 assert(path.len() == 3);
1044 let i0 = path.index(0);
1045 let i1 = path.index(1);
1046 let i2 = path.index(2);
1047 assert(rec_vaddr(path, 3) == 0);
1048 assert(rec_vaddr(path, 2) == vaddr_make::<NR_LEVELS>(2, i2) as usize);
1049 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
1050 2,
1051 i2,
1052 )) as usize);
1053 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
1054 1,
1055 i1,
1056 ) + vaddr_make::<NR_LEVELS>(2, i2)) as usize);
1057 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1058 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1059 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
1060 assert(pt.len() == 4);
1061 assert(pt.index(0) == i0);
1062 assert(pt.index(1) == i1);
1063 assert(pt.index(2) == i2);
1064 assert(pt.index(3) == i);
1065 assert(rec_vaddr(pt, 4) == 0);
1066 assert(rec_vaddr(pt, 3) == vaddr_make::<NR_LEVELS>(3, i) as usize);
1067 assert(rec_vaddr(pt, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(
1068 3,
1069 i,
1070 )) as usize);
1071 assert(rec_vaddr(pt, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + vaddr_make::<NR_LEVELS>(
1072 2,
1073 i2,
1074 ) + vaddr_make::<NR_LEVELS>(3, i)) as usize);
1075 assert(rec_vaddr(pt, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + vaddr_make::<NR_LEVELS>(
1076 1,
1077 i1,
1078 ) + vaddr_make::<NR_LEVELS>(2, i2) + vaddr_make::<NR_LEVELS>(3, i)) as usize);
1079 assert(vaddr_make::<NR_LEVELS>(3, i) == 0x1000usize * i) by (compute);
1080 assert(page_size(1) == 0x1000usize);
1081 assert(0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
1082 + 0x1000usize * (i + 1) <= usize::MAX) by (nonlinear_arith)
1083 requires
1084 i0 < 512,
1085 i1 < 512,
1086 i2 < 512,
1087 i < 512,
1088 ;
1089 }
1090 }
1091
1092 pub proof fn view_rec_vaddr_range(self, path: TreePath<NR_ENTRIES>, m: Mapping)
1093 requires
1094 self.pt_inv(),
1095 path.inv(),
1096 path.len() <= INC_LEVELS - 1,
1097 path.len() == self.0.level,
1098 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1099 self.view_rec(path).contains(m),
1100 ensures
1101 vaddr_of::<C>(path) <= m.va_range.start,
1102 m.va_range.start < m.va_range.end,
1103 m.va_range.end <= vaddr_of::<C>(path) + page_size(
1104 (INC_LEVELS - path.len()) as PagingLevel,
1105 ),
1106 decreases INC_LEVELS - path.len(),
1107 {
1108 broadcast use PageTableOwner::group_lemmas;
1109
1110 lemma_page_size_spec_values();
1111 if self.0.value.is_frame() {
1112 Self::lemma_vaddr_path_alignment_and_bound(path);
1113 let frame = self.0.value.frame();
1114 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1115 let expected = Mapping {
1116 va_range: Range {
1117 start: vaddr_of::<C>(path) as int,
1118 end: vaddr_of::<C>(path) + page_size(pt_level),
1119 },
1120 pa_range: Range {
1121 start: frame.mapped_pa,
1122 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1123 },
1124 page_size: page_size(pt_level),
1125 property: frame.prop,
1126 };
1127 assert(self.view_rec(path) == set![expected]);
1128 assert(m == expected);
1129 assert(page_size(pt_level) > 0);
1130 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1131 let i = choose|i: int|
1132 #![trigger self.0.children[i]]
1133 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1134 self.0.children[i].unwrap(),
1135 ).view_rec(path.push_tail(i as usize)).contains(m);
1136 self.pt_inv_unroll(i);
1137 let child = PageTableOwner(self.0.children[i].unwrap());
1138 path.push_tail_preserves_inv(i as usize);
1139 path.push_tail_property_len(i as usize);
1140 child.view_rec_vaddr_range(path.push_tail(i as usize), m);
1141 Self::lemma_vaddr_push_tail_eq(path, i as usize);
1142
1143 let parent_ps = page_size((INC_LEVELS - path.len()) as PagingLevel) as int;
1144 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel) as int;
1145 vstd::arithmetic::power2::lemma2_to64();
1146 vstd::arithmetic::power2::lemma2_to64_rest();
1147 if path.len() == 0 {
1148 assert(parent_ps == 0x1_0000_0000_0000);
1149 assert(child_ps == 0x80_0000_0000);
1150 } else if path.len() == 1 {
1151 assert(parent_ps == 0x80_0000_0000);
1152 assert(child_ps == 0x4000_0000);
1153 } else if path.len() == 2 {
1154 assert(parent_ps == 0x4000_0000);
1155 assert(child_ps == 0x20_0000);
1156 } else {
1157 assert(path.len() == 3);
1158 assert(parent_ps == 0x20_0000);
1159 assert(child_ps == 0x1000);
1160 }
1161 assert(parent_ps == 512 * child_ps) by (nonlinear_arith)
1162 requires
1163 (parent_ps == 0x1_0000_0000_0000 && child_ps == 0x80_0000_0000) || (parent_ps
1164 == 0x80_0000_0000 && child_ps == 0x4000_0000) || (parent_ps == 0x4000_0000
1165 && child_ps == 0x20_0000) || (parent_ps == 0x20_0000 && child_ps == 0x1000),
1166 ;
1167 assert((i + 1) * child_ps <= 512 * child_ps) by (nonlinear_arith)
1168 requires
1169 0 <= i < 512,
1170 child_ps >= 0,
1171 ;
1172 assert(m.va_range.end <= vaddr_of::<C>(path.push_tail(i as usize)) + child_ps);
1173 assert(vaddr(path.push_tail(i as usize)) == vaddr(path) + i * child_ps);
1174 lemma_vaddr_of_eq_int::<C>(path);
1178 lemma_vaddr_of_eq_int::<C>(path.push_tail(i as usize));
1179 assert(vaddr_of::<C>(path.push_tail(i as usize)) == vaddr_of::<C>(path) + i * child_ps);
1180 assert(i * child_ps + child_ps == (i + 1) * child_ps) by (nonlinear_arith);
1181 assert(m.va_range.end <= vaddr_of::<C>(path) + (i + 1) * child_ps);
1182 assert(m.va_range.end <= vaddr_of::<C>(path) + parent_ps);
1183 }
1184 }
1185
1186 pub proof fn view_rec_top_index_va_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping, t: int)
1192 requires
1193 self.pt_inv(),
1194 path.inv(),
1195 1 <= path.len() <= INC_LEVELS - 1,
1196 path.len() == self.0.level,
1197 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1198 path.index(0) < t,
1199 self.view_rec(path).contains(m),
1200 ensures
1201 (path.index(0)) * 0x80_0000_0000int + C::LEADING_BITS_spec() * 0x1_0000_0000_0000int
1202 <= m.va_range.start,
1203 m.va_range.start < m.va_range.end,
1204 m.va_range.end <= t * 0x80_0000_0000int + C::LEADING_BITS_spec()
1205 * 0x1_0000_0000_0000int,
1206 {
1207 self.view_rec_vaddr_range(path, m);
1208 lemma_vaddr_of_eq_int::<C>(path);
1209 lemma_vaddr_top_index_cell(path);
1210 assert((path.index(0) + 1) * 0x80_0000_0000int <= t * 0x80_0000_0000int)
1217 by (nonlinear_arith)
1218 requires
1219 path.index(0) < t,
1220 ;
1221 }
1222
1223 pub proof fn pt_inv_implies_path_correct(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
1231 requires
1232 PageTableOwner(subtree).pt_inv(),
1233 subtree.value.path == path,
1234 ensures
1235 subtree.tree_predicate_map(path, Self::path_correct_pred()),
1236 decreases INC_LEVELS - subtree.level,
1237 {
1238 assert(subtree.children.len() == NR_ENTRIES);
1239 assert(Self::path_correct_pred()(subtree.value, path));
1241 if subtree.level < INC_LEVELS - 1 {
1242 assert forall|i: int|
1243 0 <= i < subtree.children.len() && (
1244 #[trigger] subtree.children[i]) is Some implies subtree.children[i].unwrap().tree_predicate_map(
1245 path.push_tail(i as usize), Self::path_correct_pred()) by {
1246 if subtree.value.is_node() {
1247 PageTableOwner(subtree).pt_inv_unroll(i);
1248 assert(subtree.children[i].unwrap().value.path == path.push_tail(i as usize));
1250 Self::pt_inv_implies_path_correct(
1251 subtree.children[i].unwrap(),
1252 path.push_tail(i as usize),
1253 );
1254 } else {
1255 PageTableOwner(subtree).pt_inv_non_node(i);
1257 }
1258 };
1259 }
1260 }
1261
1262 pub proof fn no_frame_with_path_rec(
1272 self,
1273 path: TreePath<NR_ENTRIES>,
1274 removed_path: TreePath<NR_ENTRIES>,
1275 ambient: Set<Mapping>,
1276 )
1277 requires
1278 self.pt_inv(),
1279 path.inv(),
1280 path.len() <= INC_LEVELS - 1,
1281 path.len() == self.0.level,
1282 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1283 self.0.value.path == path,
1284 self.0.tree_predicate_map(path, Self::path_correct_pred()),
1285 forall|mm: Mapping|
1286 #![trigger self.view_rec(path).contains(mm)]
1287 self.view_rec(path).contains(mm) ==> ambient.contains(mm),
1288 forall|mm: Mapping|
1289 #![trigger ambient.contains(mm)]
1290 ambient.contains(mm) ==> mm.va_range.start != vaddr_of::<C>(removed_path),
1291 ensures
1292 self.0.tree_predicate_map(
1293 path,
1294 |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1295 e.is_frame() ==> e.path != removed_path,
1296 ),
1297 decreases INC_LEVELS - path.len(),
1298 {
1299 broadcast use PageTableOwner::group_lemmas;
1300
1301 let g = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
1302 e.is_frame() ==> e.path != removed_path;
1303
1304 assert(Self::path_correct_pred()(self.0.value, path));
1306 assert(self.0.value.path == path);
1307
1308 if self.0.value.is_frame() {
1310 let frame = self.0.value.frame();
1311 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1312 let expected = Mapping {
1313 va_range: Range {
1314 start: vaddr_of::<C>(path) as int,
1315 end: vaddr_of::<C>(path) + page_size(pt_level),
1316 },
1317 pa_range: Range {
1318 start: frame.mapped_pa,
1319 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1320 },
1321 page_size: page_size(pt_level),
1322 property: frame.prop,
1323 };
1324 assert(self.view_rec(path) == set![expected]);
1325 assert(self.view_rec(path).contains(expected));
1326 assert(ambient.contains(expected));
1327 assert(vaddr_of::<C>(path) != vaddr_of::<C>(removed_path));
1328 assert(self.0.value.path != removed_path);
1329 }
1330 assert(g(self.0.value, path));
1331
1332 if self.0.level < INC_LEVELS - 1 {
1333 assert forall|i: int|
1334 0 <= i < self.0.children.len() && (
1335 #[trigger] self.0.children[i]) is Some implies self.0.children[i].unwrap().tree_predicate_map(
1336 path.push_tail(i as usize), g) by {
1337 if self.0.value.is_node() {
1338 self.pt_inv_unroll(i);
1339 let child = PageTableOwner(self.0.children[i].unwrap());
1340 path.push_tail_preserves_inv(i as usize);
1341 path.push_tail_property_len(i as usize);
1342 self.0.map_unroll_once(path, Self::path_correct_pred(), i);
1345 child.no_frame_with_path_rec(path.push_tail(i as usize), removed_path, ambient);
1346 } else {
1347 PageTableOwner(self.0).pt_inv_non_node(i);
1348 }
1349 };
1350 }
1351 assert(self.0.tree_predicate_map(path, g));
1352 }
1353
1354 pub proof fn view_rec_disjoint_vaddrs(
1355 self,
1356 path: TreePath<NR_ENTRIES>,
1357 m1: Mapping,
1358 m2: Mapping,
1359 )
1360 requires
1361 self.pt_inv(),
1362 path.inv(),
1363 path.len() <= INC_LEVELS - 1,
1364 path.len() == self.0.level,
1365 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1366 self.view_rec(path).contains(m1),
1367 self.view_rec(path).contains(m2),
1368 m1 != m2,
1369 ensures
1370 m1.va_range.end <= m2.va_range.start || m2.va_range.end <= m1.va_range.start,
1371 decreases INC_LEVELS - path.len(),
1372 {
1373 broadcast use PageTableOwner::group_lemmas;
1374 broadcast use group_set_properties;
1375
1376 if self.0.value.is_frame() {
1377 assert(self.view_rec(path).is_singleton());
1378 } else if self.0.value.is_node() {
1379 let i1 = self.view_rec_contains_choose(path, m1);
1380 let i2 = self.view_rec_contains_choose(path, m2);
1381
1382 path.push_tail_preserves_inv(i1 as usize);
1383 path.push_tail_preserves_inv(i2 as usize);
1384 path.push_tail_property_len(i1 as usize);
1385 path.push_tail_property_len(i2 as usize);
1386
1387 if i1 == i2 {
1388 self.pt_inv_unroll(i1);
1389 PageTableOwner(self.0.children[i1].unwrap()).view_rec_disjoint_vaddrs(
1390 path.push_tail(i1 as usize),
1391 m1,
1392 m2,
1393 );
1394 } else {
1395 self.pt_inv_unroll(i1);
1396 self.pt_inv_unroll(i2);
1397 let child_ps = page_size((INC_LEVELS - path.len() - 1) as PagingLevel);
1398 PageTableOwner(self.0.children[i1].unwrap()).view_rec_vaddr_range(
1399 path.push_tail(i1 as usize),
1400 m1,
1401 );
1402 PageTableOwner(self.0.children[i2].unwrap()).view_rec_vaddr_range(
1403 path.push_tail(i2 as usize),
1404 m2,
1405 );
1406 if i1 < i2 {
1407 sibling_paths_disjoint::<C>(path, i1 as usize, i2 as usize, child_ps);
1408 } else {
1409 sibling_paths_disjoint::<C>(path, i2 as usize, i1 as usize, child_ps);
1410 }
1411 lemma_vaddr_of_eq_int::<C>(path.push_tail(i1 as usize));
1415 lemma_vaddr_of_eq_int::<C>(path.push_tail(i2 as usize));
1416 }
1417 }
1418 }
1419
1420 pub proof fn view_rec_mapping_page_size(self, path: TreePath<NR_ENTRIES>)
1427 requires
1428 self.pt_inv(),
1429 path.len() <= INC_LEVELS - 1,
1430 path.len() == self.0.level,
1431 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1432 ensures
1433 forall|m: Mapping| #[trigger]
1434 self.view_rec(path).contains(m)
1435 ==> set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size),
1436 decreases INC_LEVELS - path.len(),
1437 {
1438 broadcast use PageTableOwner::group_lemmas;
1439
1440 if self.0.value.is_frame() {
1441 lemma_page_size_spec_values();
1442 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1443 assert forall|m: Mapping| #[trigger]
1444 self.view_rec(path).contains(
1445 m,
1446 ) implies set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size) by {
1447 let i = choose|i: int|
1448 #![trigger self.0.children[i]]
1449 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1450 self.0.children[i].unwrap(),
1451 ).view_rec(path.push_tail(i as usize)).contains(m);
1452 self.pt_inv_unroll(i);
1453 let child = self.0.children[i].unwrap();
1454 PageTableOwner(child).view_rec_mapping_page_size(path.push_tail(i as usize));
1455 };
1456 }
1457 }
1458
1459 #[verifier::rlimit(400)]
1466 proof fn lemma_vaddr_path_alignment_and_bound(path: TreePath<NR_ENTRIES>)
1467 requires
1468 path.inv(),
1469 path.len() <= INC_LEVELS - 1,
1470 1 <= INC_LEVELS - path.len() <= NR_LEVELS,
1471 ensures
1472 vaddr(path) % page_size((INC_LEVELS - path.len()) as PagingLevel) == 0,
1473 vaddr(path) + page_size((INC_LEVELS - path.len()) as PagingLevel) <= usize::MAX,
1474 {
1475 lemma_page_size_spec_values();
1476 vstd::arithmetic::power2::lemma2_to64();
1477 vstd::arithmetic::power2::lemma2_to64_rest();
1478 broadcast use TreePath::index_satisfies_elem_inv;
1479 if path.len() == 0 {
1491 assert(rec_vaddr(path, 0) == 0);
1492 } else if path.len() == 1 {
1493 let i0 = path.index(0);
1494 assert(rec_vaddr(path, 1) == 0);
1495 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1496 path,
1497 1,
1498 )) as usize);
1499 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1500 assert(rec_vaddr(path, 0) == 0x80_0000_0000usize * i0);
1501 assert(page_size(4) == 0x80_0000_0000usize);
1502 assert((0x80_0000_0000usize * i0) % 0x80_0000_0000 == 0) by (nonlinear_arith);
1503 assert(0x80_0000_0000usize * i0 + 0x80_0000_0000 <= usize::MAX) by (nonlinear_arith)
1504 requires
1505 i0 < 512,
1506 ;
1507 } else if path.len() == 2 {
1508 let i0 = path.index(0);
1509 let i1 = path.index(1);
1510 assert(rec_vaddr(path, 2) == 0);
1511 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(
1512 path,
1513 2,
1514 )) as usize);
1515 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1516 path,
1517 1,
1518 )) as usize);
1519 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1520 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1521 let s = 0x80_0000_0000usize * i0 + 0x4000_0000usize * i1;
1522 assert(rec_vaddr(path, 0) == s);
1523 assert(page_size(3) == 0x4000_0000usize);
1524 assert(s % 0x4000_0000 == 0) by (nonlinear_arith)
1525 requires
1526 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1,
1527 ;
1528 assert(s + 0x4000_0000 <= usize::MAX) by (nonlinear_arith)
1529 requires
1530 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1,
1531 i0 < 512,
1532 i1 < 512,
1533 ;
1534 } else if path.len() == 3 {
1535 let i0 = path.index(0);
1536 let i1 = path.index(1);
1537 let i2 = path.index(2);
1538 assert(rec_vaddr(path, 3) == 0);
1539 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + rec_vaddr(
1540 path,
1541 3,
1542 )) as usize);
1543 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(
1544 path,
1545 2,
1546 )) as usize);
1547 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1548 path,
1549 1,
1550 )) as usize);
1551 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1552 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1553 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
1554 let s = 0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2;
1555 assert(rec_vaddr(path, 0) == s);
1556 assert(page_size(2) == 0x20_0000usize);
1557 assert(s % 0x20_0000 == 0) by (nonlinear_arith)
1558 requires
1559 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2,
1560 ;
1561 assert(s + 0x20_0000 <= usize::MAX) by (nonlinear_arith)
1562 requires
1563 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2,
1564 i0 < 512,
1565 i1 < 512,
1566 i2 < 512,
1567 ;
1568 } else {
1569 assert(path.len() == 4);
1570 let i0 = path.index(0);
1571 let i1 = path.index(1);
1572 let i2 = path.index(2);
1573 let i3 = path.index(3);
1574 assert(rec_vaddr(path, 4) == 0);
1575 assert(rec_vaddr(path, 3) == (vaddr_make::<NR_LEVELS>(3, i3) + rec_vaddr(
1576 path,
1577 4,
1578 )) as usize);
1579 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, i2) + rec_vaddr(
1580 path,
1581 3,
1582 )) as usize);
1583 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, i1) + rec_vaddr(
1584 path,
1585 2,
1586 )) as usize);
1587 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, i0) + rec_vaddr(
1588 path,
1589 1,
1590 )) as usize);
1591 assert(vaddr_make::<NR_LEVELS>(0, i0) == 0x80_0000_0000usize * i0) by (compute);
1592 assert(vaddr_make::<NR_LEVELS>(1, i1) == 0x4000_0000usize * i1) by (compute);
1593 assert(vaddr_make::<NR_LEVELS>(2, i2) == 0x20_0000usize * i2) by (compute);
1594 assert(vaddr_make::<NR_LEVELS>(3, i3) == 0x1000usize * i3) by (compute);
1595 let s = (0x80_0000_0000usize * i0 + 0x4000_0000usize * i1 + 0x20_0000usize * i2
1596 + 0x1000usize * i3) as int;
1597 assert(rec_vaddr(path, 0) == s);
1598 assert(page_size(1) == 0x1000usize);
1599 assert(s % 0x1000 == 0) by (nonlinear_arith)
1600 requires
1601 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3,
1602 ;
1603 assert(s + 0x1000 <= usize::MAX) by (nonlinear_arith)
1604 requires
1605 s == 0x80_0000_0000 * i0 + 0x4000_0000 * i1 + 0x20_0000 * i2 + 0x1000 * i3,
1606 i0 < 512,
1607 i1 < 512,
1608 i2 < 512,
1609 i3 < 512,
1610 ;
1611 }
1612 }
1613
1614 pub proof fn view_rec_mapping_inv(self, path: TreePath<NR_ENTRIES>)
1623 requires
1624 self.pt_inv(),
1625 path.inv(),
1626 path.len() <= INC_LEVELS - 1,
1627 path.len() == self.0.level,
1628 self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel,
1629 ensures
1630 forall|m: Mapping| #[trigger] self.view_rec(path).contains(m) ==> m.inv(),
1631 decreases INC_LEVELS - path.len(),
1632 {
1633 broadcast use PageTableOwner::group_lemmas;
1634
1635 if self.0.value.is_frame() {
1636 lemma_page_size_spec_values();
1637 let frame = self.0.value.frame();
1638 let pt_level = (INC_LEVELS - path.len()) as PagingLevel;
1639 Self::lemma_vaddr_path_alignment_and_bound(path);
1640 let m = Mapping {
1641 va_range: Range {
1642 start: vaddr_of::<C>(path) as int,
1643 end: vaddr_of::<C>(path) + page_size(pt_level),
1644 },
1645 pa_range: Range {
1646 start: frame.mapped_pa,
1647 end: (frame.mapped_pa + page_size(pt_level)) as Paddr,
1648 },
1649 page_size: page_size(pt_level),
1650 property: frame.prop,
1651 };
1652 assert(self.view_rec(path) == set![m]);
1653 assert(set![4096usize, 2097152usize, 1073741824usize].contains(m.page_size));
1654 let ps = page_size(pt_level) as int;
1655 assert((frame.mapped_pa + ps) % ps == 0) by (nonlinear_arith)
1656 requires
1657 (frame.mapped_pa as int) % ps == 0,
1658 ps > 0,
1659 ;
1660 lemma_vaddr_of_eq_int::<C>(path);
1662 C::lemma_page_table_config_constant_properties();
1663 lemma_vaddr_strict_bound(path);
1664 let lb = C::LEADING_BITS_spec() as int;
1665 vstd::arithmetic::power2::lemma2_to64();
1666 vstd::arithmetic::power2::lemma2_to64_rest();
1667 assert(vaddr(path) as int % ps == 0);
1671 assert(lb * 0x1_0000_0000_0000int % ps == 0) by (nonlinear_arith)
1672 requires
1673 lb >= 0,
1674 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int),
1675 ;
1676 vstd::arithmetic::div_mod::lemma_mod_adds(
1677 vaddr(path) as int,
1678 lb * 0x1_0000_0000_0000int,
1679 ps,
1680 );
1681 assert((vaddr_of::<C>(path) as int) % ps == 0);
1682 assert((vaddr_of::<C>(path) + ps) % ps == 0) by (nonlinear_arith)
1683 requires
1684 (vaddr_of::<C>(path) as int) % ps == 0,
1685 ps > 0,
1686 ;
1687 let v = vaddr(path) as int;
1690 assert((v % ps) == 0);
1691 assert(v + ps <= 0x1_0000_0000_0000int) by (nonlinear_arith)
1692 requires
1693 v % ps == 0,
1694 v < 0x1_0000_0000_0000int,
1695 (ps == 0x1000int || ps == 0x20_0000int || ps == 0x4000_0000int),
1696 (0x1_0000_0000_0000int % ps == 0),
1697 ;
1698 assert(vaddr_of::<C>(path) + ps <= pow2(64)) by (nonlinear_arith)
1699 requires
1700 vaddr_of::<C>(path) == v + lb * 0x1_0000_0000_0000int,
1701 v + ps <= 0x1_0000_0000_0000int,
1702 lb < 0x1_0000int,
1703 lb >= 0,
1704 pow2(64) == 0x1_0000_0000_0000_0000int,
1705 ;
1706 assert(m.inv());
1707 } else if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
1708 assert forall|m: Mapping| #[trigger]
1709 self.view_rec(path).contains(m) implies m.inv() by {
1710 let i = choose|i: int|
1711 #![trigger self.0.children[i]]
1712 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1713 self.0.children[i].unwrap(),
1714 ).view_rec(path.push_tail(i as usize)).contains(m);
1715 self.pt_inv_unroll(i);
1716 let child = self.0.children[i].unwrap();
1717 path.push_tail_preserves_inv(i as usize);
1718 PageTableOwner(child).view_rec_mapping_inv(path.push_tail(i as usize));
1719 };
1720 }
1721 }
1722
1723 pub proof fn view_rec_absent_empty(self, path: TreePath<NR_ENTRIES>)
1725 requires
1726 self.0.inv(),
1727 self.0.value.is_absent(),
1728 path.len() <= INC_LEVELS - 1,
1729 ensures
1730 self.view_rec(path) == set![],
1731 {
1732 }
1733
1734 pub proof fn view_rec_nr_children_zero_empty(self, path: TreePath<NR_ENTRIES>)
1745 requires
1746 self.pt_inv(),
1747 self.0.value.is_node(),
1748 self.0.value.node().meta_own.nr_children.value() == 0,
1749 self.0.value.node().count_consistent(),
1750 path.len() <= INC_LEVELS - 1,
1751 path.len() == self.0.level,
1752 ensures
1753 self.view_rec(path) == set![],
1754 {
1755 if path.len() < INC_LEVELS - 1 {
1756 let cp = self.0.value.node().children_perm.value();
1757 assert(crate::specs::mm::page_table::node::owners::count_present(cp) == 0);
1759 self.lemma_view_rec_contains(path);
1760 assert forall|m: Mapping| self.view_rec(path).contains(m) implies false by {
1761 let i = choose|i: int|
1762 #![trigger self.0.children[i]]
1763 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
1764 self.0.children[i]->0,
1765 ).view_rec(path.push_tail(i as usize)).contains(m);
1766 self.pt_inv_unroll(i);
1767 if cp[i].is_present() {
1769 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_present(
1770 cp,
1771 cp.len() as int,
1772 i,
1773 );
1774 }
1775 assert(!cp[i].is_present());
1776 assert(self.0.children[i]->0.value.is_absent());
1780 assert(PageTableOwner(self.0.children[i]->0).view_rec(path.push_tail(i as usize))
1782 =~= set![]);
1783 };
1784 assert(self.view_rec(path) =~= set![]);
1785 }
1786 }
1787
1788 pub open spec fn metaregion_sound_pred(regions: MetaRegionOwners) -> (spec_fn(
1789 EntryOwner<C>,
1790 TreePath<NR_ENTRIES>,
1791 ) -> bool) {
1792 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions)
1793 }
1794
1795 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool
1796 decreases INC_LEVELS - self.0.level,
1797 when self.0.inv()
1798 {
1799 self.0.tree_predicate_map(self.0.value.path, Self::metaregion_sound_pred(regions))
1800 }
1801
1802 pub proof fn metaregion_sound_preserved_slot_owners_eq(
1807 self,
1808 r0: MetaRegionOwners,
1809 r1: MetaRegionOwners,
1810 )
1811 requires
1812 self.inv(),
1813 self.metaregion_sound(r0),
1814 r0.slot_owners == r1.slot_owners,
1815 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1816 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1817 ensures
1818 self.metaregion_sound(r1),
1819 {
1820 Self::metaregion_sound_preserved_slot_owners_eq_subtree(self.0, self.0.value.path, r0, r1);
1821 }
1822
1823 pub proof fn metaregion_sound_preserved_slot_owners_eq_subtree(
1825 subtree: OwnerSubtree<C>,
1826 path: TreePath<NR_ENTRIES>,
1827 r0: MetaRegionOwners,
1828 r1: MetaRegionOwners,
1829 )
1830 requires
1831 subtree.inv(),
1832 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r0)),
1833 r0.slot_owners == r1.slot_owners,
1834 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1835 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1836 ensures
1837 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r1)),
1838 decreases INC_LEVELS - subtree.level,
1839 {
1840 subtree.value.metaregion_sound_slot_owners_only(r0, r1);
1842 if subtree.level < INC_LEVELS - 1 {
1844 assert forall|i: int|
1845 #![trigger subtree.children[i]]
1846 0 <= i < NR_ENTRIES
1847 && subtree.children[i] is Some implies subtree.children[i].unwrap().tree_predicate_map(
1848 path.push_tail(i as usize), Self::metaregion_sound_pred(r1)) by {
1849 Self::metaregion_sound_preserved_slot_owners_eq_subtree(
1850 subtree.children[i].unwrap(),
1851 path.push_tail(i as usize),
1852 r0,
1853 r1,
1854 );
1855 }
1856 }
1857 }
1858
1859 pub proof fn metaregion_sound_preserved_one_slot_changed(
1865 self,
1866 r0: MetaRegionOwners,
1867 r1: MetaRegionOwners,
1868 changed_idx: usize,
1869 )
1870 requires
1871 self.inv(),
1872 self.metaregion_sound(r0),
1873 forall|i: usize|
1874 #![trigger r1.slot_owners[i]]
1875 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1876 r0.slot_owners.dom() == r1.slot_owners.dom(),
1877 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1878 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1879 self.0.tree_predicate_map(
1881 self.0.value.path,
1882 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1883 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr()->0)
1884 != changed_idx,
1885 ),
1886 self.0.tree_predicate_map(
1890 self.0.value.path,
1891 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1892 e.is_frame() && e.parent_level > 1 ==> {
1893 let pa = e.frame().mapped_pa;
1894 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1895 forall|j: usize|
1896 0 < j < nr_pages ==> {
1897 let sub_idx = #[trigger] frame_to_index(
1898 (pa + j * PAGE_SIZE) as usize,
1899 );
1900 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1901 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1902 != REF_COUNT_UNUSED
1903 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1904 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1905 <= REF_COUNT_MAX)
1906 }
1907 },
1908 ),
1909 ensures
1910 self.metaregion_sound(r1),
1911 {
1912 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1913 self.0,
1914 self.0.value.path,
1915 r0,
1916 r1,
1917 changed_idx,
1918 );
1919 }
1920
1921 pub proof fn metaregion_sound_preserved_one_slot_changed_subtree(
1922 subtree: OwnerSubtree<C>,
1923 path: TreePath<NR_ENTRIES>,
1924 r0: MetaRegionOwners,
1925 r1: MetaRegionOwners,
1926 changed_idx: usize,
1927 )
1928 requires
1929 subtree.inv(),
1930 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r0)),
1931 forall|i: usize|
1932 #![trigger r1.slot_owners[i]]
1933 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
1934 r0.slot_owners.dom() == r1.slot_owners.dom(),
1935 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
1936 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
1937 subtree.tree_predicate_map(
1938 path,
1939 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1940 e.meta_slot_paddr() is Some ==> frame_to_index(e.meta_slot_paddr()->0)
1941 != changed_idx,
1942 ),
1943 subtree.tree_predicate_map(
1944 path,
1945 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>|
1946 e.is_frame() && e.parent_level > 1 ==> {
1947 let pa = e.frame().mapped_pa;
1948 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1949 forall|j: usize|
1950 0 < j < nr_pages ==> {
1951 let sub_idx = #[trigger] frame_to_index(
1952 (pa + j * PAGE_SIZE) as usize,
1953 );
1954 sub_idx != changed_idx || (r1.slots.contains_key(sub_idx)
1955 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1956 != REF_COUNT_UNUSED
1957 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1958 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
1959 <= REF_COUNT_MAX)
1960 }
1961 },
1962 ),
1963 ensures
1964 subtree.tree_predicate_map(path, Self::metaregion_sound_pred(r1)),
1965 decreases INC_LEVELS - subtree.level,
1966 {
1967 subtree.value.metaregion_sound_one_slot_changed(r0, r1, changed_idx);
1968 if subtree.level < INC_LEVELS - 1 {
1969 assert forall|i: int|
1970 #![trigger subtree.children[i]]
1971 0 <= i < NR_ENTRIES
1972 && subtree.children[i] is Some implies subtree.children[i].unwrap().tree_predicate_map(
1973 path.push_tail(i as usize), Self::metaregion_sound_pred(r1)) by {
1974 Self::metaregion_sound_preserved_one_slot_changed_subtree(
1975 subtree.children[i].unwrap(),
1976 path.push_tail(i as usize),
1977 r0,
1978 r1,
1979 changed_idx,
1980 );
1981 }
1982 }
1983 }
1984
1985 pub open spec fn path_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
1988 EntryOwner<C>,
1989 TreePath<NR_ENTRIES>,
1990 ) -> bool {
1991 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1992 {
1993 entry.is_node() && entry.meta_slot_paddr() is Some ==> {
1995 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr()->0))
1996 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr()->0)].paths_in_pt
1997 == set![entry.path]
1998 }
1999 }
2000 }
2001
2002 pub open spec fn relate_region_tracked_pred(regions: MetaRegionOwners) -> spec_fn(
2003 EntryOwner<C>,
2004 TreePath<NR_ENTRIES>,
2005 ) -> bool {
2006 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
2007 {
2008 &&& entry.meta_slot_paddr() is Some
2009 &&& regions.slot_owners.contains_key(frame_to_index(entry.meta_slot_paddr()->0))
2010 &&& regions.slot_owners[frame_to_index(entry.meta_slot_paddr()->0)].paths_in_pt
2011 == set![path]
2012 }
2013 }
2014
2015 pub open spec fn path_correct_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
2016 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| { entry.path == path }
2017 }
2018
2019 pub open spec fn not_in_scope_pred() -> spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool {
2020 |entry: EntryOwner<C>, _path: TreePath<NR_ENTRIES>| true
2021 }
2022
2023 pub proof fn tree_not_in_scope(subtree: OwnerSubtree<C>, path: TreePath<NR_ENTRIES>)
2025 requires
2026 subtree.inv(),
2027 ensures
2028 subtree.tree_predicate_map(path, Self::not_in_scope_pred()),
2029 decreases INC_LEVELS - subtree.level,
2030 {
2031 if subtree.level < INC_LEVELS - 1 {
2033 assert forall|i: int|
2034 0 <= i < subtree.children.len() && (
2035 #[trigger] subtree.children[i]) is Some implies subtree.children[i].unwrap().tree_predicate_map(
2036 path.push_tail(i as usize), Self::not_in_scope_pred()) by {
2037 Self::tree_not_in_scope(subtree.children[i].unwrap(), path.push_tail(i as usize));
2038 };
2039 }
2040 }
2041
2042 pub proof fn view_rec_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
2045 requires
2046 self.0.inv(),
2047 path.len() <= INC_LEVELS - 1,
2048 self.view_rec(path).contains(m),
2049 ensures
2050 m.page_size <= page_size((INC_LEVELS - path.len()) as PagingLevel),
2051 decreases INC_LEVELS - path.len(),
2052 {
2053 broadcast use PageTableOwner::group_lemmas;
2054
2055 if self.0.value.is_node() && path.len() < INC_LEVELS - 1 {
2056 let i = choose|i: int|
2057 #![trigger self.0.children[i]]
2058 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
2059 self.0.children[i].unwrap(),
2060 ).view_rec(path.push_tail(i as usize)).contains(m);
2061 PageTableOwner(self.0.children[i].unwrap()).view_rec_page_size_bound(
2062 path.push_tail(i as usize),
2063 m,
2064 );
2065 page_size_monotonic(
2066 (INC_LEVELS - path.len() - 1) as PagingLevel,
2067 (INC_LEVELS - path.len()) as PagingLevel,
2068 );
2069 }
2070 }
2071
2072 pub proof fn view_rec_node_page_size_bound(self, path: TreePath<NR_ENTRIES>, m: Mapping)
2075 requires
2076 self.0.inv(),
2077 self.0.value.is_node(),
2078 path.len() < INC_LEVELS - 1,
2079 self.view_rec(path).contains(m),
2080 ensures
2081 m.page_size <= page_size(((INC_LEVELS - path.len()) - 1) as PagingLevel),
2082 decreases INC_LEVELS - path.len(),
2083 {
2084 broadcast use PageTableOwner::group_lemmas;
2085
2086 let i = choose|i: int|
2087 #![trigger self.0.children[i]]
2088 0 <= i < self.0.children.len() && self.0.children[i] is Some && PageTableOwner(
2089 self.0.children[i].unwrap(),
2090 ).view_rec(path.push_tail(i as usize)).contains(m);
2091 PageTableOwner(self.0.children[i].unwrap()).view_rec_page_size_bound(
2092 path.push_tail(i as usize),
2093 m,
2094 );
2095 }
2096
2097 pub open spec fn is_prefix_of<const N: usize>(prefix: TreePath<N>, path: TreePath<N>) -> bool {
2099 &&& prefix.len() <= path.len()
2100 &&& forall|i: int| 0 <= i < prefix.len() ==> prefix.index(i) == path.index(i)
2101 }
2102
2103 pub proof fn prefix_transitive<const N: usize>(
2105 p1: TreePath<N>,
2106 p2: TreePath<N>,
2107 p3: TreePath<N>,
2108 )
2109 requires
2110 Self::is_prefix_of(p1, p2),
2111 Self::is_prefix_of(p2, p3),
2112 ensures
2113 Self::is_prefix_of(p1, p3),
2114 {
2115 assert(p1.len() <= p3.len());
2116 assert forall|i: int| 0 <= i < p1.len() implies p1.index(i) == p3.index(i) by {
2117 assert(p1.index(i) == p2.index(i));
2118 assert(p2.index(i) == p3.index(i));
2119 };
2120 }
2121
2122 pub proof fn prefix_push_different_indices(
2123 prefix: TreePath<NR_ENTRIES>,
2124 path: TreePath<NR_ENTRIES>,
2125 i: usize,
2126 j: usize,
2127 )
2128 requires
2129 prefix.inv(),
2130 path.inv(),
2131 i != j,
2132 Self::is_prefix_of(prefix.push_tail(i), path),
2133 ensures
2134 !Self::is_prefix_of(prefix.push_tail(j), path),
2135 {
2136 assert(path.index(prefix.len() as int) == i);
2137 }
2138
2139 pub proof fn prefix_push_tail_implies_prefix<const N: usize>(
2140 prefix: TreePath<N>,
2141 path: TreePath<N>,
2142 i: usize,
2143 )
2144 requires
2145 prefix.inv(),
2146 path.inv(),
2147 0 <= i < N,
2148 Self::is_prefix_of(prefix.push_tail(i), path),
2149 ensures
2150 Self::is_prefix_of(prefix, path),
2151 {
2152 prefix.push_tail_property(i);
2153 assert(prefix.len() <= path.len());
2154 assert forall|j: int| 0 <= j < prefix.len() implies prefix.index(j) == path.index(j) by {
2155 assert(prefix.push_tail(i).index(j) == prefix.index(j));
2156 assert(prefix.push_tail(i).index(j) == path.index(j));
2157 };
2158 }
2159
2160 pub open spec fn is_at_pred(entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>) -> spec_fn(
2161 EntryOwner<C>,
2162 TreePath<NR_ENTRIES>,
2163 ) -> bool {
2164 |entry0: EntryOwner<C>, path0: TreePath<NR_ENTRIES>| { path0 == path ==> entry0 == entry }
2165 }
2166
2167 pub open spec fn path_in_tree_pred(path: TreePath<NR_ENTRIES>) -> spec_fn(
2168 EntryOwner<C>,
2169 TreePath<NR_ENTRIES>,
2170 ) -> bool {
2171 |entry: EntryOwner<C>, path0: TreePath<NR_ENTRIES>|
2172 Self::is_prefix_of(path0, path) ==> !entry.is_node() ==> path == path0
2173 }
2174
2175 pub proof fn is_at_pred_eq(
2176 path: TreePath<NR_ENTRIES>,
2177 entry1: EntryOwner<C>,
2178 entry2: EntryOwner<C>,
2179 )
2180 requires
2181 entry1.inv(),
2182 OwnerSubtree::implies(Self::is_at_pred(entry1, path), Self::is_at_pred(entry2, path)),
2183 ensures
2184 entry1 == entry2,
2185 {
2186 assert(Self::is_at_pred(entry1, path)(entry1, path) ==> Self::is_at_pred(entry2, path)(
2187 entry1,
2188 path,
2189 ));
2190 }
2191
2192 pub proof fn is_at_holds_when_on_wrong_path(
2193 subtree: OwnerSubtree<C>,
2194 root_path: TreePath<NR_ENTRIES>,
2195 dest_path: TreePath<NR_ENTRIES>,
2196 entry: EntryOwner<C>,
2197 )
2198 requires
2199 subtree.inv(),
2200 PageTableOwner(subtree).pt_inv(),
2201 dest_path.inv(),
2202 !Self::is_prefix_of(root_path, dest_path),
2203 root_path.len() <= INC_LEVELS - 1,
2204 root_path.len() == subtree.level,
2205 ensures
2206 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry, dest_path)),
2207 decreases INC_LEVELS - root_path.len(),
2208 {
2209 if subtree.level < INC_LEVELS - 1 {
2210 if subtree.value.is_node() {
2211 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2212 #[trigger] subtree.children[i as int]).unwrap().tree_predicate_map(
2213 root_path.push_tail(i as usize),
2214 Self::is_at_pred(entry, dest_path),
2215 ) by {
2216 PageTableOwner(subtree).pt_inv_unroll(i);
2217 Self::is_at_holds_when_on_wrong_path(
2218 subtree.children[i as int].unwrap(),
2219 root_path.push_tail(i as usize),
2220 dest_path,
2221 entry,
2222 );
2223 };
2224 } else {
2225 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2226 #[trigger] subtree.children[i as int]) is None by {
2227 PageTableOwner(subtree).pt_inv_non_node(i);
2228 };
2229 }
2230 }
2231 }
2232
2233 pub proof fn path_in_tree_holds_when_on_wrong_path(
2237 subtree: OwnerSubtree<C>,
2238 root_path: TreePath<NR_ENTRIES>,
2239 dest_path: TreePath<NR_ENTRIES>,
2240 )
2241 requires
2242 subtree.inv(),
2243 PageTableOwner(subtree).pt_inv(),
2244 dest_path.inv(),
2245 !Self::is_prefix_of(root_path, dest_path),
2246 root_path.len() <= INC_LEVELS - 1,
2247 root_path.len() == subtree.level,
2248 ensures
2249 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
2250 decreases INC_LEVELS - root_path.len(),
2251 {
2252 if subtree.level < INC_LEVELS - 1 {
2253 if subtree.value.is_node() {
2254 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2255 #[trigger] subtree.children[i as int]).unwrap().tree_predicate_map(
2256 root_path.push_tail(i as usize),
2257 Self::path_in_tree_pred(dest_path),
2258 ) by {
2259 PageTableOwner(subtree).pt_inv_unroll(i);
2260 Self::path_in_tree_holds_when_on_wrong_path(
2261 subtree.children[i as int].unwrap(),
2262 root_path.push_tail(i as usize),
2263 dest_path,
2264 );
2265 };
2266 } else {
2267 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2268 #[trigger] subtree.children[i as int]) is None by {
2269 PageTableOwner(subtree).pt_inv_non_node(i);
2270 };
2271 }
2272 }
2273 }
2274
2275 pub proof fn neq_old_from_path_disjoint(
2278 subtree: OwnerSubtree<C>,
2279 path_j: TreePath<NR_ENTRIES>,
2280 old_entry: EntryOwner<C>,
2281 regions: MetaRegionOwners,
2282 )
2283 requires
2284 subtree.inv(),
2285 subtree.value.path == path_j,
2286 path_j.len() == subtree.level,
2287 path_j.inv(),
2288 path_j.len() <= INC_LEVELS - 1,
2289 subtree.tree_predicate_map(path_j, Self::metaregion_sound_pred(regions)),
2290 subtree.tree_predicate_map(path_j, Self::path_correct_pred()),
2291 old_entry.is_node(),
2292 old_entry.meta_slot_paddr() is Some,
2293 regions.slot_owners[frame_to_index(old_entry.meta_slot_paddr()->0)].paths_in_pt
2294 == set![old_entry.path],
2295 !Self::is_prefix_of(path_j, old_entry.path),
2296 ensures
2297 subtree.tree_predicate_map(
2298 path_j,
2299 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry),
2300 ),
2301 decreases INC_LEVELS - subtree.level,
2302 {
2303 let f_sound = Self::metaregion_sound_pred(regions);
2304 let f_path = Self::path_correct_pred();
2305 let g = |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| e.meta_slot_paddr_neq(old_entry);
2306
2307 assert(g(subtree.value, path_j)) by {
2308 assert(f_sound(subtree.value, path_j));
2309 assert(f_path(subtree.value, path_j));
2310 assert(subtree.value.path == path_j);
2311 if subtree.value.meta_slot_paddr() is Some {
2312 let old_paddr = old_entry.meta_slot_paddr()->0;
2313 let entry_paddr = subtree.value.meta_slot_paddr()->0;
2314 if entry_paddr == old_paddr {
2315 let idx = frame_to_index(entry_paddr);
2316 let old_idx = frame_to_index(old_paddr);
2317 assert(idx == old_idx);
2318 if subtree.value.is_node() {
2319 assert(regions.slot_owners[idx].paths_in_pt == set![subtree.value.path]);
2320 } else if subtree.value.is_frame() {
2321 assert(regions.slot_owners[idx].paths_in_pt.contains(subtree.value.path));
2322 }
2323 assert(regions.slot_owners[idx].paths_in_pt == set![old_entry.path]);
2324 assert(set![old_entry.path].contains(subtree.value.path));
2325 assert(subtree.value.path == old_entry.path);
2326 assert(Self::is_prefix_of(path_j, old_entry.path));
2327 }
2328 }
2329 };
2330
2331 if subtree.level < INC_LEVELS - 1 {
2332 assert forall|i: int|
2333 0 <= i < subtree.children.len() && (
2334 #[trigger] subtree.children[i]) is Some implies subtree.children[i].unwrap().tree_predicate_map(
2335 path_j.push_tail(i as usize), g) by {
2336 let child = subtree.children[i].unwrap();
2337 let child_path = path_j.push_tail(i as usize);
2338 subtree.map_unroll_once(path_j, f_sound, i);
2339 subtree.map_unroll_once(path_j, f_path, i);
2340 path_j.push_tail_property(i as usize);
2341 assert(child_path.inv());
2342 assert(child_path.len() == child.level);
2343 assert(child.value.path == child_path);
2344 assert(!Self::is_prefix_of(child_path, old_entry.path)) by {
2345 if Self::is_prefix_of(child_path, old_entry.path) {
2346 Self::prefix_push_tail_implies_prefix(path_j, old_entry.path, i as usize);
2347 }
2348 };
2349 Self::neq_old_from_path_disjoint(child, child_path, old_entry, regions);
2350 };
2351 }
2352 }
2353
2354 pub proof fn is_at_eq_rec(
2355 subtree: OwnerSubtree<C>,
2356 root_path: TreePath<NR_ENTRIES>,
2357 dest_path: TreePath<NR_ENTRIES>,
2358 entry1: EntryOwner<C>,
2359 entry2: EntryOwner<C>,
2360 )
2361 requires
2362 subtree.inv(),
2363 PageTableOwner(subtree).pt_inv(),
2364 dest_path.inv(),
2365 root_path.inv(),
2366 Self::is_prefix_of(root_path, dest_path),
2367 root_path.len() <= INC_LEVELS - 1,
2368 root_path.len() == subtree.level,
2369 subtree.tree_predicate_map(root_path, Self::path_in_tree_pred(dest_path)),
2370 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry1, dest_path)),
2371 subtree.tree_predicate_map(root_path, Self::is_at_pred(entry2, dest_path)),
2372 ensures
2373 entry1 == entry2,
2374 decreases INC_LEVELS - root_path.len(),
2375 {
2376 if root_path == dest_path {
2377 assert(subtree.value == entry1);
2378 assert(subtree.value == entry2);
2379 } else if subtree.level == INC_LEVELS - 1 || !subtree.value.is_node() {
2380 proof_from_false()
2381 } else {
2382 assert(root_path.len() <= dest_path.len());
2383 if root_path.len() == dest_path.len() {
2384 assert(root_path.0.len() == dest_path.0.len());
2385 assert forall|i: int| 0 <= i < root_path.0.len() implies #[trigger] root_path.0[i]
2386 == dest_path.0[i] by {
2387 assert(root_path.index(i) == dest_path.index(i));
2388 };
2389 assert(root_path == dest_path);
2390 assert(false);
2391 }
2392 assert(root_path.len() < dest_path.len());
2393 let i = dest_path.index(root_path.len() as int);
2394 PageTableOwner(subtree).pt_inv_unroll(i as int);
2395 assert(Self::is_prefix_of(root_path.push_tail(i), dest_path));
2396 Self::is_at_eq_rec(
2397 subtree.children[i as int].unwrap(),
2398 root_path.push_tail(i as usize),
2399 dest_path,
2400 entry1,
2401 entry2,
2402 );
2403 }
2404 }
2405
2406 pub proof fn view_rec_inversion(
2407 self,
2408 path: TreePath<NR_ENTRIES>,
2409 regions: MetaRegionOwners,
2410 m: Mapping,
2411 ) -> (entry: EntryOwner<C>)
2412 requires
2413 self.pt_inv(),
2414 path.len() == self.0.level,
2415 self.view_rec(path).contains(m),
2416 self.0.tree_predicate_map(path, Self::path_correct_pred()),
2417 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
2418 ensures
2419 Self::is_prefix_of(path, entry.path),
2420 regions.slot_owners[frame_to_index(m.pa_range.start)].paths_in_pt == set![entry.path],
2421 m.va_range.start == vaddr_of::<C>(entry.path),
2422 m.page_size == page_size((INC_LEVELS - entry.path.len()) as PagingLevel),
2423 entry.is_frame(),
2424 m.property == entry.frame().prop,
2425 self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path)),
2426 self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path)),
2427 entry.inv(),
2428 decreases INC_LEVELS - path.len(),
2429 {
2430 broadcast use PageTableOwner::group_lemmas;
2431
2432 if self.0.value.is_frame() {
2433 assert(Self::is_prefix_of(path, self.0.value.path));
2434 if self.0.level < INC_LEVELS - 1 {
2435 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
2438 #[trigger] self.0.children[i]) is None by {
2439 self.pt_inv_non_node(i);
2440 };
2441 }
2442 assert(self.0.tree_predicate_map(
2443 path,
2444 Self::is_at_pred(self.0.value, self.0.value.path),
2445 ));
2446 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(self.0.value.path)));
2447 self.0.value
2448 } else if self.0.value.is_node() {
2449 let i = self.view_rec_contains_choose(path, m);
2450 self.pt_inv_unroll(i);
2451 let entry = PageTableOwner(self.0.children[i].unwrap()).view_rec_inversion(
2452 path.push_tail(i as usize),
2453 regions,
2454 m,
2455 );
2456 Self::prefix_transitive(path, path.push_tail(i as usize), entry.path);
2457 assert forall|j: int|
2458 0 <= j < NR_ENTRIES
2459 && #[trigger] self.0.children[j] is Some implies self.0.children[j].unwrap().tree_predicate_map(
2460 path.push_tail(j as usize), Self::is_at_pred(entry, entry.path)) by {
2461 if j != i {
2462 self.pt_inv_unroll(j);
2463 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
2464 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path));
2465 Self::is_at_holds_when_on_wrong_path(
2466 self.0.children[j].unwrap(),
2467 path.push_tail(j as usize),
2468 entry.path,
2469 entry,
2470 );
2471 }
2472 };
2473 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry, entry.path)));
2474
2475 assert forall|j: int|
2476 0 <= j < NR_ENTRIES
2477 && #[trigger] self.0.children[j] is Some implies self.0.children[j].unwrap().tree_predicate_map(
2478 path.push_tail(j as usize), Self::path_in_tree_pred(entry.path)) by {
2479 if j != i {
2480 self.pt_inv_unroll(j);
2481 Self::prefix_push_different_indices(path, entry.path, i as usize, j as usize);
2482 assert(!Self::is_prefix_of(path.push_tail(j as usize), entry.path));
2483 Self::path_in_tree_holds_when_on_wrong_path(
2484 self.0.children[j].unwrap(),
2485 path.push_tail(j as usize),
2486 entry.path,
2487 );
2488 }
2489 };
2490 assert(self.0.tree_predicate_map(path, Self::path_in_tree_pred(entry.path)));
2491 entry
2492 } else {
2493 proof_from_false()
2494 }
2495 }
2496
2497 pub proof fn view_rec_inversion_unique(
2498 self,
2499 path: TreePath<NR_ENTRIES>,
2500 regions: MetaRegionOwners,
2501 m1: Mapping,
2502 m2: Mapping,
2503 )
2504 requires
2505 self.pt_inv(),
2506 path.len() <= INC_LEVELS - 1,
2507 path.len() == self.0.level,
2508 self.view_rec(path).contains(m1),
2509 self.view_rec(path).contains(m2),
2510 m1.pa_range.start == m2.pa_range.start,
2511 m1.inv(),
2512 m2.inv(),
2513 self.0.tree_predicate_map(path, Self::path_tracked_pred(regions)),
2514 self.0.tree_predicate_map(path, Self::path_correct_pred()),
2515 self.0.tree_predicate_map(path, Self::relate_region_tracked_pred(regions)),
2516 ensures
2517 m1 == m2,
2518 {
2519 let entry1 = self.view_rec_inversion(path, regions, m1);
2520 let entry2 = self.view_rec_inversion(path, regions, m2);
2521
2522 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry1, entry1.path)));
2523 assert(self.0.tree_predicate_map(path, Self::is_at_pred(entry2, entry2.path)));
2524
2525 let idx = frame_to_index(m1.pa_range.start);
2527 assert(regions.slot_owners[idx].paths_in_pt == set![entry1.path]);
2528 assert(regions.slot_owners[idx].paths_in_pt == set![entry2.path]);
2529 assert(set![entry1.path].contains(entry2.path));
2530 assert(entry1.path == entry2.path);
2531
2532 Self::is_at_eq_rec(self.0, path, entry1.path, entry1, entry2);
2533 }
2534
2535 pub broadcast group group_lemmas {
2536 PageTableOwner::lemma_view_rec_contains,
2537 PageTableOwner::lemma_view_rec_contains_intro,
2538 }
2539}
2540
2541impl<C: PageTableConfig> Inv for PageTableOwner<C> {
2542 open spec fn inv(self) -> bool {
2543 &&& self.0.inv()
2544 &&& self.pt_inv_at_depth((INC_LEVELS - self.0.level) as nat)
2545 &&& self.0.value.is_node()
2546 &&& self.0.value.path.len() <= INC_LEVELS - 1
2547 &&& self.0.value.path.inv()
2548 &&& self.0.value.path.len() == self.0.level
2549 &&& self.0.value.parent_level == (INC_LEVELS - self.0.level) as PagingLevel
2550 &&& self.0.value.node().tree_level == self.0.value.path.len()
2551 &&& self.0.tree_predicate_map(self.0.value.path, Self::path_correct_pred())
2552 }
2553}
2554
2555impl<C: PageTableConfig> View for PageTableOwner<C> {
2556 type V = PageTableView;
2557
2558 open spec fn view(&self) -> <Self as View>::V {
2559 let mappings = self.view_rec(self.0.value.path);
2560 PageTableView { mappings }
2561 }
2562}
2563
2564}