1use vstd::prelude::*;
2
3use vstd::{set::lemma_set_choose_len, set_lib::*};
4use vstd_extra::{arithmetic::*, ghost_tree::*, ownership::*};
5
6use crate::specs::{
7 arch::{MAX_PADDR, NR_ENTRIES, NR_LEVELS, PAGE_SIZE},
8 mm::page_table::{Mapping, cursor::owners::*, owners::PageTableOwner, vaddr_range_spec},
9};
10
11use crate::arch::mm::PagingConsts;
12use crate::mm::{
13 Paddr, PagingConstsTrait, PagingLevel, Vaddr, page_prop::PageProperty, page_size, page_table::*,
14};
15
16verus! {
17
18broadcast use group_ghost_tree_lemmas;
19
20impl<C: PageTableConfig> CursorView<C> {
21 proof fn lemma_split_index_inv(m: Mapping, new_size: usize, k: int)
22 requires
23 m.inv(),
24 new_size > 0,
25 m.page_size % new_size == 0,
26 set![4096usize, 2097152, 1073741824].contains(new_size),
27 m.va_range.start % new_size as int == 0,
28 0 <= k < m.page_size as int / new_size as int,
29 ensures
30 Self::split_index(m, new_size, k as usize).inv(),
31 m.va_range.start <= Self::split_index(m, new_size, k as usize).va_range.start,
32 Self::split_index(m, new_size, k as usize).va_range.end <= m.va_range.end,
33 {
34 let ps = m.page_size as int;
35 let ns = new_size as int;
36 let count = ps / ns;
37 let sub = Self::split_index(m, new_size, k as usize);
38
39 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ps, ns);
40 assert(ps == count * ns) by {
41 vstd::arithmetic::mul::lemma_mul_is_commutative(ns, count);
42 };
43 vstd::arithmetic::mul::lemma_mul_inequality(k + 1, count, ns);
44 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(ns, k, 1);
45
46 vstd::arithmetic::div_mod::lemma_mod_mod(m.pa_range.start as int, ns, count);
47 assert((m.pa_range.start as int) % ns == 0);
48 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(k, ns);
49 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(k + 1, ns);
50 vstd_extra::arithmetic::lemma_mod_0_add(m.pa_range.start as int, k * ns, ns);
51 vstd_extra::arithmetic::lemma_mod_0_add(m.pa_range.start as int, (k + 1) * ns, ns);
52 vstd_extra::arithmetic::lemma_mod_0_add(m.va_range.start, k * ns, ns);
53 vstd_extra::arithmetic::lemma_mod_0_add(m.va_range.start, (k + 1) * ns, ns);
54
55 assert(sub.inv());
56 }
57
58 pub proof fn split_if_mapped_huge_spec_preserves_present(v: Self, new_size: usize)
62 requires
63 v.inv(),
64 v.present(),
65 new_size > 0,
66 v.query_mapping().page_size > 0,
67 v.query_mapping().page_size % new_size == 0,
68 ensures
69 v.split_if_mapped_huge_spec(new_size).present(),
70 {
71 let cur_va = v.cur_va;
72 let m = v.query_mapping();
73 let ps = m.page_size;
74
75 assert(v.mappings.contains(m) && m.va_range.start <= cur_va && cur_va < m.va_range.end) by {
76 let f = v.mappings.filter(
77 |m2: Mapping| m2.va_range.start <= v.cur_va < m2.va_range.end,
78 );
79 vstd::set::lemma_set_choose_len(f);
80 };
81 assert(m.inv());
82
83 let diff: int = cur_va - m.va_range.start;
84 let ki: int = diff / new_size as int;
85 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(diff, new_size as int);
86
87 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ps as int, new_size as int);
88 assert(ki < ps as int / new_size as int) by {
89 if ki >= ps as int / new_size as int {
90 vstd::arithmetic::mul::lemma_mul_inequality(
91 ps as int / new_size as int,
92 ki,
93 new_size as int,
94 );
95 }
96 };
97
98 let sub = Self::split_index(m, new_size, ki as usize);
99
100 assert(ki * new_size >= 0);
101 assert((ki + 1) * new_size <= ps) by {
102 vstd::arithmetic::mul::lemma_mul_inequality(
103 ki + 1,
104 ps as int / new_size as int,
105 new_size as int,
106 );
107 };
108
109 vstd::arithmetic::mul::lemma_mul_is_distributive_add(new_size as int, ki, 1 as int);
110
111 let new_self = v.split_if_mapped_huge_spec(new_size);
112 let domain = Set::<int>::range(0int, ps as int / new_size as int);
113 assert(domain.contains(ki));
114
115 let new_filter = new_self.mappings.filter(
116 |m2: Mapping| m2.va_range.start <= new_self.cur_va < m2.va_range.end,
117 );
118 vstd::set::lemma_set_contains_len(new_filter, sub);
119 }
120
121 pub proof fn split_if_mapped_huge_spec_decreases_page_size(v: Self, new_size: usize)
128 requires
129 v.inv(),
130 v.present(),
131 new_size > 0,
132 v.query_mapping().page_size > new_size,
133 v.query_mapping().page_size % new_size == 0,
134 ensures
135 v.split_if_mapped_huge_spec(new_size).present(),
136 v.split_if_mapped_huge_spec(new_size).query_mapping().page_size
137 < v.query_mapping().page_size,
138 {
139 Self::split_if_mapped_huge_spec_preserves_present(v, new_size);
140
141 let cur_va = v.cur_va;
142 let m = v.query_mapping();
143 let new_self = v.split_if_mapped_huge_spec(new_size);
144 let m2 = new_self.query_mapping();
145 let ps = m.page_size;
146
147 assert(v.mappings.contains(m) && m.va_range.start <= cur_va && cur_va < m.va_range.end) by {
148 let f = v.mappings.filter(
149 |m2: Mapping| m2.va_range.start <= v.cur_va < m2.va_range.end,
150 );
151 vstd::set::lemma_set_choose_len(f);
152 };
153
154 assert(new_self.mappings.contains(m2) && m2.va_range.start <= cur_va && cur_va
155 < m2.va_range.end) by {
156 let f = new_self.mappings.filter(
157 |m3: Mapping| m3.va_range.start <= new_self.cur_va < m3.va_range.end,
158 );
159 vstd::set::lemma_set_choose_len(f);
160 };
161
162 if v.mappings.contains(m2) && m2 != m {
163 assert(false);
164 }
165 let new_mappings = Set::<int>::range(0int, ps as int / new_size as int).map(
166 |n: int| Self::split_index(m, new_size, n as usize),
167 );
168 let k = choose|k: int|
169 0 <= k < ps as int / new_size as int && #[trigger] Self::split_index(
170 m,
171 new_size,
172 k as usize,
173 ) == m2;
174 }
175
176 #[verifier::rlimit(80)]
182 #[verifier::spinoff_prover]
183 pub proof fn split_if_mapped_huge_spec_preserves_inv(v: Self, new_size: usize)
184 requires
185 v.inv(),
186 v.present(),
187 new_size > 0,
188 v.query_mapping().page_size > new_size,
189 v.query_mapping().page_size % new_size == 0,
190 set![4096usize, 2097152, 1073741824].contains(new_size),
191 ensures
192 v.split_if_mapped_huge_spec(new_size).inv(),
193 {
194 let cur_va = v.cur_va;
195 let m = v.query_mapping();
196 let ps = m.page_size;
197 let ns: int = new_size as int;
198 let count: int = ps as int / ns;
199
200 assert(v.mappings.contains(m) && m.va_range.start <= cur_va && cur_va < m.va_range.end) by {
202 let f = v.mappings.filter(
203 |m2: Mapping| m2.va_range.start <= v.cur_va < m2.va_range.end,
204 );
205 vstd::set::lemma_set_choose_len(f);
206 };
207 assert(m.inv());
208 assert(m.va_range.start % new_size as int == 0) by {
209 vstd::arithmetic::mul::lemma_mul_is_commutative(count, ns);
210 vstd::arithmetic::div_mod::lemma_mod_mod(m.va_range.start as int, ns, count);
211 };
212
213 let domain = Set::<int>::range(0int, count);
214 let new_mappings = domain.map(|n: int| Self::split_index(m, new_size, n as usize));
215 let new_self = v.split_if_mapped_huge_spec(new_size);
216
217 assert forall|m2: Mapping| #[trigger] new_self.mappings.contains(m2) implies m2.inv() by {
218 if v.mappings.contains(m2) && m2 != m {
219 } else {
220 let k = choose|k: int|
221 0 <= k < count && #[trigger] Self::split_index(m, new_size, k as usize) == m2;
222 Self::lemma_split_index_inv(m, new_size, k);
223 }
224 };
225
226 assert forall|m2: Mapping| #[trigger] new_self.mappings.contains(m2) implies {
227 &&& vaddr_range_spec::<C>().start <= m2.va_range.start
228 &&& m2.va_range.end <= vaddr_range_spec::<C>().end + 1
229 } by {
230 if v.mappings.contains(m2) && m2 != m {
231 } else {
232 let k = choose|k: int|
233 0 <= k < count && #[trigger] Self::split_index(m, new_size, k as usize) == m2;
234 Self::lemma_split_index_inv(m, new_size, k);
235 }
236 };
237 }
238
239 pub broadcast proof fn lemma_split_while_huge_preserves_cur_va(self, size: usize)
241 requires
242 self.inv(),
243 size >= PAGE_SIZE,
244 ensures
245 #[trigger] self.split_while_huge(size).cur_va == self.cur_va,
246 decreases
247 if self.present() {
248 self.query_mapping().page_size as int
249 } else {
250 0
251 },
252 {
253 if self.present() {
254 let m = self.query_mapping();
255 if m.page_size > size {
256 let new_size = m.page_size / NR_ENTRIES;
257 let new_self = self.split_if_mapped_huge_spec(new_size);
258 let f = self.mappings.filter(
260 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
261 );
262 vstd::set::lemma_set_choose_len(f);
263 assert(m.inv());
264 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
266 if m.page_size != 2097152 && m.page_size != 1073741824 {
267 assert(false);
268 }
269 };
270 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
271
272 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
273 Self::lemma_split_while_huge_preserves_cur_va(new_self, size);
274 }
275 }
276 }
277
278 pub proof fn lemma_split_while_huge_preserves_inv(self, size: usize)
280 requires
281 self.inv(),
282 size >= PAGE_SIZE,
283 ensures
284 self.split_while_huge(size).inv(),
285 decreases
286 if self.present() {
287 self.query_mapping().page_size as int
288 } else {
289 0
290 },
291 {
292 if self.present() {
293 let m = self.query_mapping();
294 if m.page_size > size {
295 let new_size = m.page_size / NR_ENTRIES;
296 let new_self = self.split_if_mapped_huge_spec(new_size);
297 let f = self.mappings.filter(
299 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
300 );
301 vstd::set::lemma_set_choose_len(f);
302 assert(m.inv());
303 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
304 if m.page_size != 2097152 && m.page_size != 1073741824 {
305 assert(false);
306 }
307 };
308 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
309 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
310 new_self.lemma_split_while_huge_preserves_inv(size);
311 }
312 }
313 }
314
315 pub proof fn split_while_huge_compose(self, s1: usize, s2: usize)
319 requires
320 self.inv(),
321 s1 >= PAGE_SIZE,
322 s2 <= s1,
323 ensures
324 self.split_while_huge(s2) == self.split_while_huge(s1).split_while_huge(s2),
325 decreases
326 if self.present() {
327 self.query_mapping().page_size as int
328 } else {
329 0
330 },
331 {
332 if !self.present() {
333 return;
334 }
335 let m = self.query_mapping();
336 if m.page_size <= s1 {
337 return;
338 }
339 let new_size = m.page_size / NR_ENTRIES;
340 let f = self.mappings.filter(
341 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
342 );
343 vstd::set::lemma_set_choose_len(f);
344 assert(m.inv());
345 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
346 if m.page_size == 2097152 {
347 } else {
348 }
349 };
350 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
351 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
352 self.split_if_mapped_huge_spec(new_size).split_while_huge_compose(s1, s2);
353 }
354
355 pub proof fn split_while_huge_idempotent(self, size: usize)
358 requires
359 self.inv(),
360 size >= PAGE_SIZE,
361 ensures
362 self.split_while_huge(size).split_while_huge(size) == self.split_while_huge(size),
363 {
364 self.split_while_huge_compose(size, size);
365 }
366
367 pub proof fn split_while_huge_noop_implies_page_size_le(self, size: usize)
370 requires
371 self.inv(),
372 size >= PAGE_SIZE,
373 self.split_while_huge(size) == self,
374 self.present(),
375 ensures
376 self.query_mapping().page_size <= size,
377 {
378 let m = self.query_mapping();
379 if m.page_size > size {
380 let new_size = m.page_size / NR_ENTRIES;
381 let f = self.mappings.filter(
382 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
383 );
384 vstd::set::lemma_set_choose_len(f);
385 assert(m.inv());
386 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
387 if m.page_size == 2097152 {
388 } else if m.page_size == 1073741824 {
389 } else {
390 assert(false);
391 }
392 };
393 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
394 let new_self = self.split_if_mapped_huge_spec(new_size);
395 new_self.split_while_huge_refinement(size, m);
396 let p = choose|p: Mapping| #[trigger]
397 new_self.mappings.contains(p) && p.va_range.start <= m.va_range.start
398 && m.va_range.end <= p.va_range.end && m.pa_range.start == (p.pa_range.start + (
399 m.va_range.start - p.va_range.start)) as Paddr && m.property == p.property;
400 if self.mappings.contains(p) {
401 } else {
402 let new_mappings = Set::<int>::range(
403 0int,
404 m.page_size as int / new_size as int,
405 ).map(|n: int| Self::split_index(m, new_size, n as usize));
406 let k = choose|k: int|
407 0 <= k < m.page_size as int / new_size as int && #[trigger] Self::split_index(
408 m,
409 new_size,
410 k as usize,
411 ) == p;
412 }
413 }
414 }
415
416 pub proof fn split_while_huge_one_step(self, size: usize)
426 requires
427 self.inv(),
428 self.present(),
429 self.query_mapping().page_size > size,
430 self.query_mapping().page_size / NR_ENTRIES == size,
431 self.query_mapping().page_size % size == 0,
432 set![4096usize, 2097152, 1073741824].contains(size),
433 ensures
434 self.split_while_huge(size).mappings == self.split_if_mapped_huge_spec(size).mappings,
435 {
436 let m = self.query_mapping();
437 let new_size = m.page_size / NR_ENTRIES;
438 let f0 = self.mappings.filter(
439 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
440 );
441 vstd::set::lemma_set_choose_len(f0);
442 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
443 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
444 let new_self = self.split_if_mapped_huge_spec(new_size);
445
446 assert(new_self.query_mapping().page_size == new_size) by {
447 let new_m = new_self.query_mapping();
448 let f = new_self.mappings.filter(
449 |m2: Mapping| m2.va_range.start <= new_self.cur_va < m2.va_range.end,
450 );
451 vstd::set::lemma_set_choose_len(f);
452 if self.mappings.contains(new_m) && new_m != m {
453 assert(false);
454 }
455 let new_mappings = Set::<int>::range(0int, m.page_size as int / new_size as int).map(
456 |n: int| Self::split_index(m, new_size, n as usize),
457 );
458 };
459 assert(new_self.split_while_huge(size) == new_self);
460 }
461
462 pub proof fn split_if_mapped_huge_spec_locality(self, new_size: usize, m2: Mapping)
465 requires
466 self.inv(),
467 self.present(),
468 new_size > 0,
469 self.query_mapping().page_size % new_size == 0,
470 Mapping::disjoint_vaddrs(m2, self.query_mapping()),
471 ensures
472 self.split_if_mapped_huge_spec(new_size).mappings.contains(m2)
473 == self.mappings.contains(m2),
474 {
475 let m = self.query_mapping();
476 let size = m.page_size;
477 let new_mappings = Set::<int>::range(0int, (size / new_size) as int).map(
478 |n: int| Self::split_index(m, new_size, n as usize),
479 );
480
481 let f = self.mappings.filter(
483 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
484 );
485 vstd::set::lemma_set_choose_len(f);
486 assert(m.inv());
487
488 assert(!new_mappings.contains(m2)) by {
489 if new_mappings.contains(m2) {
490 let k = choose|k: int|
491 0 <= k < size as int / new_size as int && #[trigger] Self::split_index(
492 m,
493 new_size,
494 k as usize,
495 ) == m2;
496 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(size as int, new_size as int);
497 vstd::arithmetic::mul::lemma_mul_inequality(
498 (k + 1) as int,
499 size as int / new_size as int,
500 new_size as int,
501 );
502 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
503 new_size as int,
504 k,
505 1int,
506 );
507 }
508 };
509 }
510
511 #[verifier::rlimit(80)]
518 pub proof fn split_while_huge_locality(self, size: usize, m2: Mapping)
519 requires
520 self.inv(),
521 size >= PAGE_SIZE,
522 self.mappings.contains(m2),
523 !(m2.va_range.start <= self.cur_va < m2.va_range.end),
524 ensures
525 self.split_while_huge(size).mappings.contains(m2),
526 decreases
527 if self.present() {
528 self.query_mapping().page_size as int
529 } else {
530 0
531 },
532 {
533 if self.present() {
534 let m = self.query_mapping();
535 if m.page_size > size {
536 let new_size = m.page_size / NR_ENTRIES;
537 let f = self.mappings.filter(
539 |m3: Mapping| m3.va_range.start <= self.cur_va < m3.va_range.end,
540 );
541 vstd::set::lemma_set_choose_len(f);
542 assert(m.inv());
543 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
545 if m.page_size != 2097152 && m.page_size != 1073741824 {
546 assert(false);
547 }
548 };
549 let new_self = self.split_if_mapped_huge_spec(new_size);
550 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
551 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
552 new_self.split_while_huge_locality(size, m2);
553 }
554 }
555 }
556
557 #[verifier::rlimit(120)]
565 pub proof fn split_while_huge_locality_absent(self, size: usize, m2: Mapping)
566 requires
567 self.inv(),
568 size >= PAGE_SIZE,
569 !self.mappings.contains(m2),
570 self.present() ==> Mapping::disjoint_vaddrs(m2, self.query_mapping()),
571 ensures
572 !self.split_while_huge(size).mappings.contains(m2),
573 decreases
574 if self.present() {
575 self.query_mapping().page_size as int
576 } else {
577 0
578 },
579 {
580 if self.present() {
581 let m = self.query_mapping();
582 if m.page_size > size {
583 let new_size = m.page_size / NR_ENTRIES;
584 let f = self.mappings.filter(
586 |m3: Mapping| m3.va_range.start <= self.cur_va < m3.va_range.end,
587 );
588 vstd::set::lemma_set_choose_len(f);
589 assert(m.inv());
591 assert(m.page_size % new_size == 0) by {
592 assert(2097152usize % (2097152usize / 512usize) == 0) by (compute_only);
593 assert(1073741824usize % (1073741824usize / 512usize) == 0) by (compute_only);
594 };
595 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
596 if m.page_size != 2097152 && m.page_size != 1073741824 {
597 assert(false);
598 }
599 };
600 let new_self = self.split_if_mapped_huge_spec(new_size);
601 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
602 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
603 assert(new_self.present() ==> Mapping::disjoint_vaddrs(
604 m2,
605 new_self.query_mapping(),
606 )) by {
607 if new_self.present() {
608 let new_m = new_self.query_mapping();
609 let nf = new_self.mappings.filter(
610 |m3: Mapping| m3.va_range.start <= new_self.cur_va < m3.va_range.end,
611 );
612 vstd::set::lemma_set_choose_len(nf);
613 if self.mappings.contains(new_m) && new_m != m {
614 assert(false);
615 }
616 let new_mappings = Set::<int>::range(
617 0int,
618 m.page_size as int / new_size as int,
619 ).map(|n: int| Self::split_index(m, new_size, n as usize));
620 let k = choose|k: int|
621 0 <= k < m.page_size as int / new_size as int
622 && #[trigger] Self::split_index(m, new_size, k as usize) == new_m;
623 }
624 };
625 new_self.split_while_huge_locality_absent(size, m2);
626 }
627 }
628 }
629
630 pub proof fn split_if_mapped_huge_spec_refinement(self, new_size: usize, e: Mapping)
635 requires
636 self.inv(),
637 self.present(),
638 new_size > 0,
639 self.query_mapping().page_size > new_size,
640 self.query_mapping().page_size % new_size == 0,
641 self.split_if_mapped_huge_spec(new_size).mappings.contains(e),
642 ensures
643 self.mappings.contains(e) || {
644 let parent = self.query_mapping();
645 &&& self.mappings.contains(parent)
646 &&& parent.va_range.start <= e.va_range.start
647 &&& e.va_range.end <= parent.va_range.end
648 &&& e.pa_range.start == (parent.pa_range.start + (e.va_range.start
649 - parent.va_range.start)) as Paddr
650 &&& e.property == parent.property
651 },
652 {
653 let qm = self.query_mapping();
654 let ps = qm.page_size;
655 let ns: int = new_size as int;
656 let count: int = ps as int / ns;
657 let new_self = self.split_if_mapped_huge_spec(new_size);
658 let domain = Set::<int>::range(0int, count);
659 let new_mappings = domain.map(|n: int| Self::split_index(qm, new_size, n as usize));
660
661 let f = self.mappings.filter(
663 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
664 );
665 vstd::set::lemma_set_choose_len(f);
666 assert(qm.inv());
667
668 if self.mappings.remove(qm).contains(e) {
669 } else {
670 let k = choose|k: int|
671 0 <= k < count && #[trigger] Self::split_index(qm, new_size, k as usize) == e;
672
673 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(ps as int, ns);
674
675 vstd::arithmetic::mul::lemma_mul_inequality(k + 1, count, ns);
676 }
677 }
678
679 pub proof fn split_while_huge_refinement(self, size: usize, m: Mapping)
680 requires
681 self.inv(),
682 size >= PAGE_SIZE,
683 self.split_while_huge(size).mappings.contains(m),
684 ensures
685 self.mappings.contains(m) || exists|parent: Mapping| #[trigger]
686 self.mappings.contains(parent) && parent.va_range.start <= m.va_range.start
687 && m.va_range.end <= parent.va_range.end && m.pa_range.start == (
688 parent.pa_range.start + (m.va_range.start - parent.va_range.start)) as Paddr
689 && m.property == parent.property,
690 decreases
691 if self.present() {
692 self.query_mapping().page_size as int
693 } else {
694 0
695 },
696 {
697 if self.present() {
698 let qm = self.query_mapping();
699 if qm.page_size > size {
700 let new_size = qm.page_size / NR_ENTRIES;
701 let new_self = self.split_if_mapped_huge_spec(new_size);
702
703 let f = self.mappings.filter(
704 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
705 );
706 vstd::set::lemma_set_choose_len(f);
707 assert(qm.inv());
708 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
709 if qm.page_size != 2097152 && qm.page_size != 1073741824 {
710 assert(false);
711 }
712 };
713 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
714 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
715
716 new_self.split_while_huge_refinement(size, m);
717
718 if new_self.mappings.contains(m) {
719 } else {
720 let p = choose|p: Mapping| #[trigger]
721 new_self.mappings.contains(p) && p.va_range.start <= m.va_range.start
722 && m.va_range.end <= p.va_range.end && m.pa_range.start == (
723 p.pa_range.start + (m.va_range.start - p.va_range.start)) as Paddr
724 && m.property == p.property;
725 if !self.mappings.contains(p) {
726 }
727 }
728 }
729 }
730 }
731
732 pub proof fn split_while_huge_preserves_empty_prefix(
734 self,
735 split_view: CursorView<C>,
736 size: usize,
737 m: Mapping,
738 )
739 requires
740 self.inv(),
741 size >= PAGE_SIZE,
742 self.cur_va <= split_view.cur_va,
743 self.cur_va < split_view.cur_va ==> !self.present(),
744 self.mappings.filter(|m2: Mapping| self.cur_va <= m2.va_range.start < split_view.cur_va)
745 == Set::<Mapping>::empty(),
746 self.split_while_huge(size).mappings.contains(m),
747 self.cur_va <= m.va_range.start < split_view.cur_va,
748 ensures
749 self.mappings.contains(m),
750 {
751 }
752
753 pub proof fn split_while_huge_disjoint(self, size: usize, other: Set<Mapping>)
763 requires
764 self.inv(),
765 size >= PAGE_SIZE,
766 forall|m: Mapping, x: Mapping| #[trigger]
767 self.mappings.contains(m) && #[trigger] other.contains(x)
768 ==> Mapping::disjoint_vaddrs(m, x),
769 ensures
770 self.split_while_huge(size).mappings.disjoint(other),
771 decreases
772 if self.present() {
773 self.query_mapping().page_size as int
774 } else {
775 0
776 },
777 {
778 if !self.present() {
779 assert forall|x: Mapping|
781 #![trigger other.contains(x)]
782 other.contains(x) implies !self.split_while_huge(size).mappings.contains(x) by {
783 if self.mappings.contains(x) {
784 assert(x.inv());
785 }
786 };
787 return;
788 }
789 let m = self.query_mapping();
790 if m.page_size <= size {
791 assert forall|x: Mapping|
792 #![trigger other.contains(x)]
793 other.contains(x) implies !self.split_while_huge(size).mappings.contains(x) by {
794 if self.mappings.contains(x) {
795 assert(x.inv());
796 }
797 };
798 return;
799 }
800 let new_size = m.page_size / NR_ENTRIES;
801
802 let f = self.mappings.filter(
804 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
805 );
806 vstd::set::lemma_set_choose_len(f);
807 assert(m.inv());
808
809 assert(set![4096usize, 2097152, 1073741824].contains(new_size)) by {
810 if m.page_size == 2097152 {
811 } else if m.page_size == 1073741824 {
812 } else {
813 assert(false);
814 }
815 };
816 Self::split_if_mapped_huge_spec_preserves_inv(self, new_size);
817 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
818 let new_self = self.split_if_mapped_huge_spec(new_size);
819
820 assert forall|m2: Mapping, x: Mapping| #[trigger]
822 new_self.mappings.contains(m2) && #[trigger] other.contains(
823 x,
824 ) implies Mapping::disjoint_vaddrs(m2, x) by {
825 if self.mappings.contains(m2) {
826 } else {
828 let new_mappings = Set::<int>::range(
830 0int,
831 m.page_size as int / new_size as int,
832 ).map(|n: int| Self::split_index(m, new_size, n as usize));
833 let k = choose|k: int|
834 0 <= k < m.page_size as int / new_size as int && #[trigger] Self::split_index(
835 m,
836 new_size,
837 k as usize,
838 ) == m2;
839 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(
840 m.page_size as int,
841 new_size as int,
842 );
843 }
844 };
845
846 new_self.split_while_huge_disjoint(size, other);
847 }
848}
849
850impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
851 proof fn query_mapping_from_subtree(self, qm: Mapping)
856 requires
857 self.inv(),
858 self.in_locked_range(),
859 self@.inv(),
860 self@.present(),
861 qm == self@.query_mapping(),
862 ensures
863 PageTableOwner(self.cur_subtree()).view_rec(self.cur_subtree().value().path).contains(
864 qm,
865 ),
866 {
867 let f = self@.mappings.filter(
868 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
869 );
870 lemma_set_choose_len(f);
871 self.mapping_covering_cur_va_from_cur_subtree(qm);
872 }
873
874 pub proof fn split_while_huge_node_noop(self)
875 requires
876 self.inv(),
877 self.in_locked_range(),
878 self.cur_entry_owner().is_node(),
879 self.level > 1,
880 ensures
881 self@.split_while_huge(page_size((self.level - 1) as PagingLevel)) == self@,
882 {
883 self.view_preserves_inv();
884 if self@.present() {
885 let subtree = self.cur_subtree();
886 let path = subtree.value().path;
887 let qm = self@.query_mapping();
888 self.query_mapping_from_subtree(qm);
889 PageTableOwner(subtree).view_rec_node_page_size_bound(path, qm);
890 }
891 }
892
893 pub proof fn split_while_huge_absent_noop(self, size: usize)
896 requires
897 self.inv(),
898 self.in_locked_range(),
899 self.cur_entry_owner().is_absent(),
900 ensures
901 self@.split_while_huge(size) == self@,
902 {
903 self.view_preserves_inv();
904 self.cur_entry_absent_not_present();
905 }
906
907 pub proof fn split_while_huge_at_level_noop(self)
908 requires
909 self.inv(),
910 self.in_locked_range(),
911 ensures
912 self@.split_while_huge(page_size(self.level as PagingLevel)) == self@,
913 {
914 self.view_preserves_inv();
915 if self@.present() {
916 self.cur_subtree_inv();
917 let subtree = self.cur_subtree();
918 let path = subtree.value().path;
919 let qm = self@.query_mapping();
920 self.query_mapping_from_subtree(qm);
921 PageTableOwner(subtree).view_rec_page_size_bound(path, qm);
922 }
923 }
924
925 pub proof fn map_branch_frame_split_while_huge(
935 self,
936 owner0: Self,
937 owner_before_frame: Self,
938 level_before_frame: int,
939 )
940 requires
941 self.inv(),
942 owner0.inv(),
943 owner_before_frame.inv(),
944 1 <= level_before_frame - 1,
945 level_before_frame <= NR_LEVELS,
946 self.level == (level_before_frame - 1) as u8,
947 owner_before_frame@ == owner0@.split_while_huge(
948 page_size(level_before_frame as PagingLevel),
949 ),
950 self@ == owner_before_frame@.split_if_mapped_huge_spec(
951 page_size((level_before_frame - 1) as PagingLevel),
952 ),
953 owner_before_frame@.present(),
958 owner_before_frame@.query_mapping().page_size == page_size(
959 level_before_frame as PagingLevel,
960 ),
961 {
962 owner0.view_preserves_inv();
963 owner_before_frame.view_preserves_inv();
964 }
965
966 pub proof fn find_next_split_push_equals_split_while_huge(self, old_view: CursorView<C>)
969 requires
970 self.inv(),
971 old_view.inv(),
972 self.cur_entry_owner().is_frame(),
973 self@.cur_va == old_view.cur_va,
974 old_view.present(),
975 old_view.query_mapping().page_size > page_size(self.level as PagingLevel),
976 old_view.query_mapping().page_size / NR_ENTRIES == page_size(self.level as PagingLevel),
977 old_view.query_mapping().page_size % page_size(self.level as PagingLevel) == 0,
978 self@.mappings =~= old_view.split_if_mapped_huge_spec(
979 page_size(self.level as PagingLevel),
980 ).mappings,
981 ensures
982 self@.mappings == old_view.split_while_huge(
983 page_size(self.level as PagingLevel),
984 ).mappings,
985 {
986 let ps = page_size(self.level as PagingLevel);
987 let m = old_view.query_mapping();
988 let f = old_view.mappings.filter(
989 |m2: Mapping| m2.va_range.start <= old_view.cur_va < m2.va_range.end,
990 );
991 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
992 old_view.split_while_huge_one_step(ps);
993 }
994
995 pub proof fn split_while_huge_cur_va_independent(
1003 v1: CursorView<C>,
1004 v2: CursorView<C>,
1005 size: usize,
1006 )
1007 requires
1008 v1.inv(),
1009 v2.inv(),
1010 v1.mappings =~= v2.mappings,
1011 v1.cur_va <= v2.cur_va,
1012 v1.mappings.filter(
1014 |m: Mapping| v1.cur_va <= m.va_range.start && m.va_range.start < v2.cur_va,
1015 ) =~= Set::<Mapping>::empty(),
1016 !v1.present() && v2.present() ==> v2.query_mapping().page_size <= size,
1022 v1.cur_va < v2.cur_va ==> !v1.present(),
1025 ensures
1026 v1.split_while_huge(size).mappings == v2.split_while_huge(size).mappings,
1027 {
1028 }
1029}
1030
1031}