1#![allow(hidden_glob_reexports)]
2
3pub mod cursor;
4pub mod mapping_set_lemmas;
5pub mod node;
6mod owners;
7pub mod vaddr_range_proofs;
8mod view;
9
10pub use cursor::*;
11pub use node::*;
12pub use owners::*;
13pub use view::*;
14
15use core::ops::Range;
16
17use align_ext::AlignExt;
18
19use vstd::prelude::*;
20use vstd::std_specs::range::RangeInclusiveView;
21
22use vstd::arithmetic::power2::{lemma_pow2_adds, lemma2_to64, lemma2_to64_rest, pow2};
23use vstd_extra::{arithmetic::*, ghost_tree::TreePath, ownership::*, prelude::*};
24
25use crate::specs::arch::*;
26
27use crate::mm::{
28 PagingConsts, PagingConstsTrait, PagingLevel, Vaddr, kspace::KernelPtConfig,
29 nr_subpage_per_huge, page_size, page_table::PageTableConfig, vm_space::UserPtConfig,
30};
31
32verus! {
33
34#[verifier::inline]
35pub open spec fn nr_pte_index_bits_spec<C: PagingConstsTrait>() -> usize {
36 nr_subpage_per_huge::<C>().ilog2() as usize
37}
38
39#[verifier::inline]
40pub open spec fn pte_index_bit_offset_spec<C: PagingConstsTrait>(level: PagingLevel) -> usize {
41 (C::BASE_PAGE_SIZE().ilog2() + nr_pte_index_bits_spec::<C>() * (level - 1)) as usize
42}
43
44#[verifier::inline]
45pub open spec fn top_level_index_width_spec<C: PageTableConfig>() -> usize {
46 (C::ADDRESS_WIDTH_spec() - pte_index_bit_offset_spec::<C>(C::NR_LEVELS())) as usize
47}
48
49#[verusfmt::skip]
56pub open spec fn vaddr_range_spec<C: PageTableConfig>() -> RangeInclusiveView<Vaddr> {
57 let off = pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat;
58 let lb = C::LEADING_BITS_spec() as int;
59 let base = lb * 0x1_0000_0000_0000int;
60 let start = (base + (C::TOP_LEVEL_INDEX_RANGE().start) * pow2(off)) as usize;
61 let end = (base + (C::TOP_LEVEL_INDEX_RANGE().end) * pow2(off) - 1) as usize;
62 RangeInclusiveView { start, end, exhausted: false }
63}
64
65pub open spec fn is_valid_range_spec<C: PageTableConfig>(r: Range<Vaddr>) -> bool {
66 let va_range = vaddr_range_spec::<C>();
67 (r.start == 0 && r.end == 0) || (va_range.start <= r.start && r.end - 1 <= va_range.end)
68}
69
70pub(crate) proof fn lemma_vaddr_range_spec_user()
73 ensures
74 vaddr_range_spec::<UserPtConfig>().start == 0,
75 vaddr_range_spec::<UserPtConfig>().end == 0x0000_7FFF_FFFF_FFFF,
76{
77 assert(<UserPtConfig as PageTableConfig>::LEADING_BITS_spec() == 0);
78 lemma_arch_specific_consts_properties::<PagingConsts>();
79}
80
81pub(crate) proof fn lemma_vaddr_range_spec_kernel()
84 ensures
85 vaddr_range_spec::<KernelPtConfig>().start == 0xFFFF_8000_0000_0000,
86 vaddr_range_spec::<KernelPtConfig>().end == 0xFFFF_FFFF_FFFF_FFFF,
87{
88 lemma_arch_specific_consts_properties::<PagingConsts>();
89}
90
91pub ghost struct AbstractVaddr {
103 pub offset: int,
104 pub index: Map<int, int>,
105 pub leading_bits: int,
106}
107
108impl Inv for AbstractVaddr {
109 open spec fn inv(self) -> bool {
110 &&& 0 <= self.offset
111 < PAGE_SIZE
112 &&& self.index.dom() =~= Set::<int>::range(0, NR_LEVELS as int)
114 &&& forall|i: int|
115 #![trigger self.index.contains_key(i)]
116 0 <= i < NR_LEVELS ==> {
117 &&& self.index.contains_key(i)
118 &&& 0 <= self.index[i] < NR_ENTRIES
119 }
120 &&& 0 <= self.leading_bits < 0x1_0000int
122 }
123}
124
125impl AbstractVaddr {
126 pub open spec fn from_vaddr(va: Vaddr) -> Self {
131 AbstractVaddr {
132 offset: (va % PAGE_SIZE) as int,
133 index: Map::new(
134 Set::<int>::range(0, NR_LEVELS as int),
135 |i: int| ((va / pow2((12 + 9 * i) as nat) as usize) % NR_ENTRIES) as int,
136 ),
137 leading_bits: (va as int / 0x1_0000_0000_0000int),
138 }
139 }
140
141 pub proof fn from_vaddr_wf(va: Vaddr)
142 ensures
143 AbstractVaddr::from_vaddr(va).inv(),
144 {
145 let abs = AbstractVaddr::from_vaddr(va);
146 assert forall|i: int| #![trigger abs.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
147 &&& abs.index.contains_key(i)
148 &&& 0 <= abs.index[i]
149 &&& abs.index[i] < NR_ENTRIES
150 } by {};
151 let va_i = va as int;
152 assert(0 <= abs.leading_bits < 0x1_0000int) by (nonlinear_arith)
153 requires
154 abs.leading_bits == va_i / 0x1_0000_0000_0000int,
155 0 <= va_i < 0x1_0000_0000_0000_0000int,
156 ;
157 }
158
159 pub open spec fn to_vaddr(self) -> Vaddr {
162 (self.offset + self.to_vaddr_indices(0) + self.leading_bits
163 * 0x1_0000_0000_0000int) as Vaddr
164 }
165
166 pub open spec fn to_vaddr_indices(self, start: int) -> int
168 decreases NR_LEVELS - start,
169 when start <= NR_LEVELS
170 {
171 if start >= NR_LEVELS {
172 0
173 } else {
174 self.index[start] * pow2((12 + 9 * start) as nat) + self.to_vaddr_indices(start + 1)
175 }
176 }
177
178 pub open spec fn reflect(self, va: Vaddr) -> bool {
180 self == Self::from_vaddr(va)
181 }
182
183 pub broadcast proof fn reflect_prop(self, va: Vaddr)
186 requires
187 self.inv(),
188 self.reflect(va),
189 ensures
190 #[trigger] self.to_vaddr() == va,
191 #[trigger] Self::from_vaddr(va) == self,
192 {
193 Self::from_vaddr_to_vaddr_roundtrip(va);
197 }
198
199 pub proof fn from_vaddr_to_vaddr_roundtrip(va: Vaddr)
205 ensures
206 Self::from_vaddr(va).to_vaddr() == va,
207 {
208 vstd::arithmetic::power2::lemma2_to64();
209 vstd::arithmetic::power2::lemma2_to64_rest();
210 let abs = Self::from_vaddr(va);
211 assert(abs.to_vaddr_indices(4) == 0);
212 assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) + abs.to_vaddr_indices(4));
213 assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) + abs.to_vaddr_indices(3));
214 assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) + abs.to_vaddr_indices(2));
215 assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) + abs.to_vaddr_indices(1));
216 assert(va == (va % 4096usize) + ((va / 4096usize) % 512usize) * 4096usize + ((va
217 / 0x20_0000usize) % 512usize) * 0x20_0000usize + ((va / 0x4000_0000usize) % 512usize)
218 * 0x4000_0000usize + ((va / 0x80_0000_0000usize) % 512usize) * 0x80_0000_0000usize + (va
219 / 0x1_0000_0000_0000usize) * 0x1_0000_0000_0000usize) by (bit_vector);
220 }
221
222 pub broadcast proof fn reflect_from_vaddr(va: Vaddr)
224 ensures
225 #[trigger] Self::from_vaddr(va).reflect(va),
226 #[trigger] Self::from_vaddr(va).inv(),
227 {
228 Self::from_vaddr_wf(va);
229 }
230
231 pub broadcast proof fn reflect_to_vaddr(self)
233 requires
234 self.inv(),
235 ensures
236 #[trigger] self.reflect(self.to_vaddr()),
237 {
238 Self::to_vaddr_from_vaddr_roundtrip(self);
239 }
240
241 pub proof fn to_vaddr_from_vaddr_roundtrip(abs: Self)
244 requires
245 abs.inv(),
246 ensures
247 Self::from_vaddr(abs.to_vaddr()) == abs,
248 {
249 vstd::arithmetic::power2::lemma2_to64();
250 vstd::arithmetic::power2::lemma2_to64_rest();
251 abs.to_vaddr_bounded();
252 assert(abs.to_vaddr_indices(4) == 0);
253 assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) + abs.to_vaddr_indices(4));
254 assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) + abs.to_vaddr_indices(3));
255 assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) + abs.to_vaddr_indices(2));
256 assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) + abs.to_vaddr_indices(1));
257
258 assert(abs.index.contains_key(0));
259 assert(abs.index.contains_key(1));
260 assert(abs.index.contains_key(2));
261 assert(abs.index.contains_key(3));
262 let i0 = abs.index[0] as usize;
263 let i1 = abs.index[1] as usize;
264 let i2 = abs.index[2] as usize;
265 let i3 = abs.index[3] as usize;
266 let o = abs.offset as usize;
267 let tb = abs.leading_bits as usize;
268 let va = abs.to_vaddr();
269 assert(va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
270 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize);
271
272 assert(va % 4096usize == o) by (bit_vector)
273 requires
274 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
275 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
276 o < 4096usize,
277 i0 < 512usize,
278 i1 < 512usize,
279 i2 < 512usize,
280 i3 < 512usize,
281 tb < 0x1_0000usize,
282 ;
283 assert((va / 4096usize) % 512usize == i0) by (bit_vector)
284 requires
285 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
286 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
287 o < 4096usize,
288 i0 < 512usize,
289 i1 < 512usize,
290 i2 < 512usize,
291 i3 < 512usize,
292 tb < 0x1_0000usize,
293 ;
294 assert((va / 0x20_0000usize) % 512usize == i1) by (bit_vector)
295 requires
296 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
297 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
298 o < 4096usize,
299 i0 < 512usize,
300 i1 < 512usize,
301 i2 < 512usize,
302 i3 < 512usize,
303 tb < 0x1_0000usize,
304 ;
305 assert((va / 0x4000_0000usize) % 512usize == i2) by (bit_vector)
306 requires
307 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
308 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
309 o < 4096usize,
310 i0 < 512usize,
311 i1 < 512usize,
312 i2 < 512usize,
313 i3 < 512usize,
314 tb < 0x1_0000usize,
315 ;
316 assert((va / 0x80_0000_0000usize) % 512usize == i3) by (bit_vector)
317 requires
318 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
319 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
320 o < 4096usize,
321 i0 < 512usize,
322 i1 < 512usize,
323 i2 < 512usize,
324 i3 < 512usize,
325 tb < 0x1_0000usize,
326 ;
327 assert(va / 0x1_0000_0000_0000usize == tb) by (bit_vector)
328 requires
329 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
330 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
331 o < 4096usize,
332 i0 < 512usize,
333 i1 < 512usize,
334 i2 < 512usize,
335 i3 < 512usize,
336 tb < 0x1_0000usize,
337 ;
338
339 let back = Self::from_vaddr(va);
340 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] back.index[i]
341 == abs.index[i] by {
342 if i == 0 {
343 } else if i == 1 {
344 } else if i == 2 {
345 } else if i == 3 {
346 }
347 }
348 assert(back.index == abs.index);
349 }
350
351 pub broadcast proof fn reflect_eq(self, other: Self, va: Vaddr)
353 requires
354 #[trigger] self.reflect(va),
355 #[trigger] other.reflect(va),
356 ensures
357 self == other,
358 {
359 }
360
361 pub open spec fn align_down(self, level: int) -> Self
362 decreases level,
363 when level >= 1
364 {
365 if level == 1 {
366 AbstractVaddr { offset: 0, ..self }
367 } else {
368 let tmp = self.align_down(level - 1);
369 AbstractVaddr { index: tmp.index.insert(level - 2, 0), ..tmp }
370 }
371 }
372
373 proof fn lemma_zero_offset_preserves_inv(self)
374 requires
375 self.inv(),
376 ensures
377 (AbstractVaddr { offset: 0, ..self }).inv(),
378 {
379 let new = AbstractVaddr { offset: 0, ..self };
380 assert(new.index == self.index);
381 assert forall|i: int| #![trigger new.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
382 &&& new.index.contains_key(i)
383 &&& 0 <= new.index[i] < NR_ENTRIES
384 } by {
385 assert(self.index.contains_key(i));
386 }
387 }
388
389 pub proof fn lemma_insert_preserves_inv(self, index: int, value: int)
391 requires
392 self.inv(),
393 0 <= index < NR_LEVELS,
394 0 <= value < NR_ENTRIES,
395 ensures
396 (AbstractVaddr { index: self.index.insert(index, value), ..self }).inv(),
397 {
398 let new = AbstractVaddr { index: self.index.insert(index, value), ..self };
399 assert(new.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
400 assert forall|i: int| #![trigger new.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
401 &&& new.index.contains_key(i)
402 &&& 0 <= new.index[i] < NR_ENTRIES
403 } by {
404 if i != index {
405 assert(self.index.contains_key(i));
406 }
407 }
408 }
409
410 proof fn lemma_insert_zero_preserves_inv(self, index: int)
411 requires
412 self.inv(),
413 0 <= index < NR_LEVELS,
414 ensures
415 (AbstractVaddr { index: self.index.insert(index, 0), ..self }).inv(),
416 {
417 self.lemma_insert_preserves_inv(index, 0);
418 }
419
420 pub proof fn align_down_inv(self, level: int)
421 requires
422 1 <= level <= NR_LEVELS,
423 self.inv(),
424 ensures
425 self.align_down(level).inv(),
426 forall|i: int|
427 level <= i < NR_LEVELS ==> #[trigger] self.index[i - 1] == self.align_down(
428 level,
429 ).index[i - 1],
430 decreases level,
431 {
432 if level == 1 {
433 self.lemma_zero_offset_preserves_inv();
434
435 } else {
436 let tmp = self.align_down(level - 1);
437 self.align_down_inv(level - 1);
438 tmp.lemma_insert_zero_preserves_inv(level - 2);
439 }
440 }
441
442 pub proof fn align_down_leading_bits(self, level: int)
443 requires
444 1 <= level <= NR_LEVELS,
445 ensures
446 self.align_down(level).leading_bits == self.leading_bits,
447 decreases level,
448 {
449 if level > 1 {
450 self.align_down_leading_bits(level - 1);
451 }
452 }
453
454 pub proof fn align_down_shape(self, level: int)
455 requires
456 1 <= level <= NR_LEVELS,
457 self.inv(),
458 ensures
459 self.align_down(level).inv(),
460 self.align_down(level).offset == 0,
461 forall|i: int| 0 <= i < level - 1 ==> #[trigger] self.align_down(level).index[i] == 0,
462 forall|i: int|
463 level - 1 <= i < NR_LEVELS ==> #[trigger] self.align_down(level).index[i]
464 == self.index[i],
465 decreases level,
466 {
467 self.align_down_inv(level);
468 if level == 1 {
469 } else {
470 let tmp = self.align_down(level - 1);
471 self.align_down_shape(level - 1);
472 let new = self.align_down(level);
473
474 assert forall|i: int| #![trigger new.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
475 &&& new.index.contains_key(i)
476 &&& 0 <= new.index[i]
477 &&& new.index[i] < NR_ENTRIES
478 } by {
479 if i != level - 2 {
480 }
481 }
482 }
483 }
484
485 pub proof fn to_vaddr_indices_drop_zero_range(self, from: int, to: int)
486 requires
487 self.inv(),
488 0 <= from <= to <= NR_LEVELS,
489 forall|i: int| from <= i < to ==> self.index[i] == 0,
490 ensures
491 self.to_vaddr_indices(from) == self.to_vaddr_indices(to),
492 decreases to - from,
493 {
494 if from < to {
495 self.to_vaddr_indices_drop_zero_range(from + 1, to);
496 }
497 }
498
499 pub proof fn to_vaddr_indices_eq_if_indices_eq(self, other: Self, start: int)
500 requires
501 self.inv(),
502 other.inv(),
503 0 <= start <= NR_LEVELS,
504 forall|i: int| start <= i < NR_LEVELS ==> self.index[i] == other.index[i],
505 ensures
506 self.to_vaddr_indices(start) == other.to_vaddr_indices(start),
507 decreases NR_LEVELS - start,
508 {
509 if start < NR_LEVELS {
510 self.to_vaddr_indices_eq_if_indices_eq(other, start + 1);
511 }
512 }
513
514 pub proof fn align_down_to_vaddr_eq_if_upper_indices_eq(self, other: Self, level: int)
519 requires
520 1 <= level <= NR_LEVELS,
521 self.inv(),
522 other.inv(),
523 forall|i: int| level - 1 <= i < NR_LEVELS ==> self.index[i] == other.index[i],
525 self.leading_bits == other.leading_bits,
527 ensures
528 self.align_down(level).to_vaddr() == other.align_down(level).to_vaddr(),
529 decreases level,
530 {
531 let lhs = self.align_down(level);
532 let rhs = other.align_down(level);
533
534 self.align_down_shape(level);
535 other.align_down_shape(level);
536 self.align_down_leading_bits(level);
537 other.align_down_leading_bits(level);
538
539 lhs.to_vaddr_indices_drop_zero_range(0, level - 1);
540 rhs.to_vaddr_indices_drop_zero_range(0, level - 1);
541 lhs.to_vaddr_indices_eq_if_indices_eq(rhs, level - 1);
542 assert(lhs.leading_bits == rhs.leading_bits);
543 }
544
545 proof fn align_down_to_vaddr_arith(self, level: int)
549 requires
550 self.inv(),
551 1 <= level <= NR_LEVELS,
552 ensures
553 self.align_down(level).to_vaddr() as int % page_size(level as PagingLevel) as int == 0,
554 0 <= self.to_vaddr() - self.align_down(level).to_vaddr(),
555 self.to_vaddr() - self.align_down(level).to_vaddr() < page_size(level as PagingLevel),
556 {
557 let aligned = self.align_down(level);
558 vstd::arithmetic::power2::lemma2_to64();
559 vstd::arithmetic::power2::lemma2_to64_rest();
560 lemma_page_size_spec_values();
561 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
562
563 self.align_down_shape(level);
564 self.align_down_leading_bits(level);
565 self.to_vaddr_bounded();
566 aligned.to_vaddr_bounded();
567
568 aligned.to_vaddr_indices_drop_zero_range(0, level - 1);
570 aligned.to_vaddr_indices_eq_if_indices_eq(self, level - 1);
571
572 let o = self.offset;
574 let lb = self.leading_bits;
575 assert(self.index.contains_key(0));
576 assert(self.index.contains_key(1));
577 assert(self.index.contains_key(2));
578 assert(self.index.contains_key(3));
579 let i0 = self.index[0];
580 let i1 = self.index[1];
581 let i2 = self.index[2];
582 let i3 = self.index[3];
583 assert(self.to_vaddr_indices(4) == 0);
584 assert(self.to_vaddr_indices(3) == i3 * 0x80_0000_0000int);
585 assert(self.to_vaddr_indices(2) == i2 * 0x4000_0000int + i3 * 0x80_0000_0000int);
586 assert(self.to_vaddr_indices(1) == i1 * 0x20_0000int + i2 * 0x4000_0000int + i3
587 * 0x80_0000_0000int);
588 assert(self.to_vaddr_indices(0) == i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int
589 + i3 * 0x80_0000_0000int);
590
591 let va = self.to_vaddr() as int;
592 let av = aligned.to_vaddr() as int;
593 let ps = page_size(level as PagingLevel) as int;
594
595 assert(va == o + self.to_vaddr_indices(0) + lb * 0x1_0000_0000_0000int);
597 assert(av == 0 + self.to_vaddr_indices(level - 1) + lb * 0x1_0000_0000_0000int);
598
599 let diff = va - av;
601 if level == 1 {
602 assert(ps == 0x1000);
603 assert(diff == o);
604 assert(av % ps == 0) by (nonlinear_arith)
605 requires
606 av == i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int + i3
607 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
608 ps == 0x1000,
609 ;
610 } else if level == 2 {
611 assert(ps == 0x20_0000);
612 assert(diff == o + i0 * 0x1000int);
613 assert(0 <= diff < ps) by (nonlinear_arith)
614 requires
615 diff == o + i0 * 0x1000int,
616 0 <= o < 4096,
617 0 <= i0 < 512,
618 ps == 0x20_0000,
619 ;
620 assert(av % ps == 0) by (nonlinear_arith)
621 requires
622 av == i1 * 0x20_0000int + i2 * 0x4000_0000int + i3 * 0x80_0000_0000int + lb
623 * 0x1_0000_0000_0000int,
624 ps == 0x20_0000,
625 ;
626 } else if level == 3 {
627 assert(ps == 0x4000_0000);
628 assert(diff == o + i0 * 0x1000int + i1 * 0x20_0000int);
629 assert(0 <= diff < ps) by (nonlinear_arith)
630 requires
631 diff == o + i0 * 0x1000int + i1 * 0x20_0000int,
632 0 <= o < 4096,
633 0 <= i0 < 512,
634 0 <= i1 < 512,
635 ps == 0x4000_0000,
636 ;
637 assert(av % ps == 0) by (nonlinear_arith)
638 requires
639 av == i2 * 0x4000_0000int + i3 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
640 ps == 0x4000_0000,
641 ;
642 } else {
643 assert(ps == 0x80_0000_0000);
644 assert(diff == o + i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int);
645 assert(0 <= diff < ps) by (nonlinear_arith)
646 requires
647 diff == o + i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int,
648 0 <= o < 4096,
649 0 <= i0 < 512,
650 0 <= i1 < 512,
651 0 <= i2 < 512,
652 ps == 0x80_0000_0000,
653 ;
654 assert(av % ps == 0) by (nonlinear_arith)
655 requires
656 av == i3 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
657 ps == 0x80_0000_0000,
658 ;
659 }
660 }
661
662 pub proof fn align_down_to_vaddr_nat_align_down(self, level: int)
666 requires
667 self.inv(),
668 1 <= level <= NR_LEVELS,
669 ensures
670 self.align_down(level).to_vaddr() as nat == nat_align_down(
671 self.to_vaddr() as nat,
672 page_size(level as PagingLevel) as nat,
673 ),
674 {
675 self.align_down_to_vaddr_arith(level);
676
677 let va = self.to_vaddr() as int;
678 let av = self.align_down(level).to_vaddr() as int;
679 let ps = page_size(level as PagingLevel) as int;
680
681 assert(av % ps == 0);
682 assert(va - av < ps);
683
684 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(av, ps);
688 assert(av == ps * (av / ps)) by {
689 assert(av % ps == 0);
690 };
691 assert(va == ps * (av / ps) + (va - av));
692 vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(av / ps, va - av, ps);
693 assert((ps * (av / ps) + (va - av)) % ps == (va - av) % ps);
694 assert(va % ps == (va - av) % ps);
695 vstd::arithmetic::div_mod::lemma_small_mod((va - av) as nat, ps as nat);
696 assert((va - av) % ps == va - av);
697 assert(va % ps == va - av);
698 }
699
700 pub proof fn align_down_concrete(self, level: int)
701 requires
702 self.inv(),
703 1 <= level <= NR_LEVELS,
704 ensures
705 self.align_down(level).reflect(
706 nat_align_down(
707 self.to_vaddr() as nat,
708 page_size(level as PagingLevel) as nat,
709 ) as Vaddr,
710 ),
711 {
712 let aligned = self.align_down(level);
713 self.align_down_shape(level);
714 self.align_down_to_vaddr_nat_align_down(level);
715 aligned.reflect_to_vaddr();
716 let nad = nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat);
719 self.to_vaddr_bounded();
720 assert(nad as Vaddr == aligned.to_vaddr());
721 }
722
723 pub proof fn same_node_indices_match(
729 va1: Vaddr,
730 va2: Vaddr,
731 node_start: Vaddr,
732 level: PagingLevel,
733 )
734 requires
735 1 <= level,
736 level < NR_LEVELS,
737 node_start <= va1,
738 va1 < node_start + page_size((level + 1) as PagingLevel),
739 node_start <= va2,
740 va2 < node_start + page_size((level + 1) as PagingLevel),
741 node_start as nat % page_size((level + 1) as PagingLevel) as nat == 0,
742 ensures
743 forall|i: int|
744 #![auto]
745 level <= i < NR_LEVELS ==> Self::from_vaddr(va1).index[i] == Self::from_vaddr(
746 va2,
747 ).index[i],
748 {
749 vstd::arithmetic::power2::lemma2_to64();
750 vstd::arithmetic::power2::lemma2_to64_rest();
751 lemma_page_size_spec_values();
752 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
753
754 let ns = node_start;
755
756 if level == 1 {
761 assert((va1 / 0x20_0000usize) % 512 == (va2 / 0x20_0000usize) % 512) by (bit_vector)
762 requires
763 va1 >= ns,
764 va1 < ns + 0x20_0000usize,
765 va2 >= ns,
766 va2 < ns + 0x20_0000usize,
767 ns % 0x20_0000usize == 0usize,
768 ;
769 assert((va1 / 0x4000_0000usize) % 512 == (va2 / 0x4000_0000usize) % 512) by (bit_vector)
770 requires
771 va1 >= ns,
772 va1 < ns + 0x20_0000usize,
773 va2 >= ns,
774 va2 < ns + 0x20_0000usize,
775 ns % 0x20_0000usize == 0usize,
776 ;
777 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
778 by (bit_vector)
779 requires
780 va1 >= ns,
781 va1 < ns + 0x20_0000usize,
782 va2 >= ns,
783 va2 < ns + 0x20_0000usize,
784 ns % 0x20_0000usize == 0usize,
785 ;
786 } else if level == 2 {
787 assert((va1 / 0x4000_0000usize) % 512 == (va2 / 0x4000_0000usize) % 512) by (bit_vector)
788 requires
789 va1 >= ns,
790 va1 < ns + 0x4000_0000usize,
791 va2 >= ns,
792 va2 < ns + 0x4000_0000usize,
793 ns % 0x4000_0000usize == 0usize,
794 ;
795 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
796 by (bit_vector)
797 requires
798 va1 >= ns,
799 va1 < ns + 0x4000_0000usize,
800 va2 >= ns,
801 va2 < ns + 0x4000_0000usize,
802 ns % 0x4000_0000usize == 0usize,
803 ;
804 } else {
805 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
807 by (bit_vector)
808 requires
809 va1 >= ns,
810 va1 < ns + 0x80_0000_0000usize,
811 va2 >= ns,
812 va2 < ns + 0x80_0000_0000usize,
813 ns % 0x80_0000_0000usize == 0usize,
814 ;
815 }
816
817 assert forall|i: int| level <= i < NR_LEVELS implies Self::from_vaddr(va1).index[i]
820 == Self::from_vaddr(va2).index[i] by {
821 let abs1 = Self::from_vaddr(va1);
822 let abs2 = Self::from_vaddr(va2);
823 assert(abs1.index.contains_key(i));
824 assert(abs2.index.contains_key(i));
825 if i == 1 {
826 assert(pow2((12 + 9 * i) as nat) as usize == 0x20_0000);
827 } else if i == 2 {
828 assert(pow2((12 + 9 * i) as nat) as usize == 0x4000_0000);
829 } else {
830 assert(pow2((12 + 9 * i) as nat) as usize == 0x80_0000_0000);
831 }
832 }
833 }
834
835 pub proof fn lemma_same_node_leading_bits_match(
839 va1: Vaddr,
840 va2: Vaddr,
841 node_start: Vaddr,
842 level: PagingLevel,
843 )
844 requires
845 1 <= level,
846 level <= NR_LEVELS,
847 node_start <= va1,
848 va1 - node_start < page_size((level + 1) as PagingLevel),
849 node_start <= va2,
850 va2 - node_start < page_size((level + 1) as PagingLevel),
851 node_start as nat % page_size((level + 1) as PagingLevel) as nat == 0,
852 ensures
853 Self::from_vaddr(va1).leading_bits == Self::from_vaddr(va2).leading_bits,
854 {
855 lemma_page_size_spec_values();
856 let ns = node_start;
857 if level == 1 {
858 assert(va1 / 0x1_0000_0000_0000usize == va2 / 0x1_0000_0000_0000usize) by (bit_vector)
859 requires
860 va1 >= ns,
861 va1 - ns < 0x20_0000usize,
862 va2 >= ns,
863 va2 - ns < 0x20_0000usize,
864 ns % 0x20_0000usize == 0usize,
865 ;
866 } else if level == 2 {
867 assert(va1 / 0x1_0000_0000_0000usize == va2 / 0x1_0000_0000_0000usize) by (bit_vector)
868 requires
869 va1 >= ns,
870 va1 - ns < 0x4000_0000usize,
871 va2 >= ns,
872 va2 - ns < 0x4000_0000usize,
873 ns % 0x4000_0000usize == 0usize,
874 ;
875 } else if level == 3 {
876 assert(va1 / 0x1_0000_0000_0000usize == va2 / 0x1_0000_0000_0000usize) by (bit_vector)
877 requires
878 va1 >= ns,
879 va1 - ns < 0x80_0000_0000usize,
880 va2 >= ns,
881 va2 - ns < 0x80_0000_0000usize,
882 ns % 0x80_0000_0000usize == 0usize,
883 ;
884 } else {
885 assert(level == 4);
886 assert(va1 / 0x1_0000_0000_0000usize == va2 / 0x1_0000_0000_0000usize) by (bit_vector)
887 requires
888 va1 >= ns,
889 va1 - ns < 0x1_0000_0000_0000usize,
890 va2 >= ns,
891 va2 - ns < 0x1_0000_0000_0000usize,
892 ns % 0x1_0000_0000_0000usize == 0usize,
893 ;
894 }
895 }
896
897 pub proof fn same_page_aligned_vaddrs_equal(va1: Vaddr, va2: Vaddr, page_start: Vaddr)
898 requires
899 page_start <= va1,
900 va1 - page_start < PAGE_SIZE,
901 page_start <= va2,
902 va2 - page_start < PAGE_SIZE,
903 va1 % PAGE_SIZE == 0,
904 va2 % PAGE_SIZE == 0,
905 page_start % PAGE_SIZE == 0,
906 ensures
907 va1 == va2,
908 {
909 assert(va1 == va2) by (bit_vector)
910 requires
911 page_start <= va1,
912 va1 - page_start < 4096usize,
913 page_start <= va2,
914 va2 - page_start < 4096usize,
915 va1 % 4096usize == 0usize,
916 va2 % 4096usize == 0usize,
917 page_start % 4096usize == 0usize,
918 PAGE_SIZE == 4096usize,
919 ;
920 }
921
922 pub open spec fn align_up(self, level: int) -> Self {
923 let lower_aligned = self.align_down(level);
924 lower_aligned.next_index(level)
925 }
926
927 pub proof fn align_up_concrete_sound(self, level: int)
931 requires
932 self.inv(),
933 1 <= level <= NR_LEVELS,
934 self.index[level - 1] + 1 < NR_ENTRIES,
935 ensures
936 self.align_up(level).reflect(
937 (nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
938 + page_size(level as PagingLevel) as nat) as Vaddr,
939 ),
940 {
941 let aligned = self.align_down(level);
942 self.align_down_shape(level);
943 self.align_down_to_vaddr_nat_align_down(level);
944 aligned.index_increment_adds_page_size(level);
945
946 let advanced = AbstractVaddr {
947 index: aligned.index.insert(level - 1, aligned.index[level - 1] + 1),
948 ..aligned
949 };
950 assert(aligned.next_index(level) == advanced);
951 assert(self.align_up(level) == advanced);
952
953 assert(advanced.inv()) by {
954 assert(advanced.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
955 assert forall|i: int|
956 #![trigger advanced.index.contains_key(i)]
957 0 <= i < NR_LEVELS implies {
958 &&& advanced.index.contains_key(i)
959 &&& 0 <= advanced.index[i]
960 &&& advanced.index[i] < NR_ENTRIES
961 } by {
962 assert(aligned.index.contains_key(i));
963 }
964 };
965 advanced.reflect_to_vaddr();
966 }
967
968 pub proof fn aligned_align_down_is_self(self, level: int)
974 requires
975 self.inv(),
976 1 <= level <= NR_LEVELS,
977 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat == 0,
978 ensures
979 self.align_down(level) == self,
980 {
981 let aligned = self.align_down(level);
982 let va = self.to_vaddr() as nat;
983 let ps = page_size(level as PagingLevel) as nat;
984
985 self.align_down_shape(level);
986 self.align_down_to_vaddr_nat_align_down(level);
987 lemma_page_size_ge_page_size(level as PagingLevel);
988 vstd_extra::arithmetic::lemma_nat_align_down_sound(va, ps);
989 self.to_vaddr_bounded();
990
991 assert(nat_align_down(va, ps) == va);
993 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self);
998 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(aligned);
999 }
1002
1003 #[verifier::spinoff_prover]
1011 pub proof fn aligned_align_up_advances(self, level: int)
1012 requires
1013 self.inv(),
1014 1 <= level <= NR_LEVELS,
1015 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat == 0,
1016 self.to_vaddr() + page_size(level as PagingLevel) <= usize::MAX,
1020 ensures
1021 self.align_up(level).inv(),
1022 self.align_up(level).to_vaddr() == self.to_vaddr() + page_size(level as PagingLevel),
1023 decreases NR_LEVELS + 1 - level,
1024 {
1025 vstd::arithmetic::power2::lemma2_to64();
1026 vstd::arithmetic::power2::lemma2_to64_rest();
1027 lemma_page_size_spec_values();
1028 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1029 lemma_page_size_ge_page_size(level as PagingLevel);
1030
1031 self.aligned_align_down_is_self(level);
1032 if self.index[level - 1] + 1 < NR_ENTRIES {
1035 self.index_increment_adds_page_size(level);
1037 let advanced = AbstractVaddr {
1040 index: self.index.insert(level - 1, self.index[level - 1] + 1),
1041 ..self
1042 };
1043 assert(self.next_index(level) == advanced);
1044 assert(self.align_up(level) == advanced);
1045 assert(advanced.inv()) by {
1046 assert(advanced.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
1047 assert forall|i: int|
1048 #![trigger advanced.index.contains_key(i)]
1049 0 <= i < NR_LEVELS implies {
1050 &&& advanced.index.contains_key(i)
1051 &&& 0 <= advanced.index[i]
1052 &&& advanced.index[i] < NR_ENTRIES
1053 } by {
1054 assert(self.index.contains_key(i));
1055 }
1056 };
1057 } else {
1058 assert(self.index.contains_key(level - 1));
1060 assert(self.index[level - 1] < NR_ENTRIES); assert(self.index[level - 1] + 1 >= NR_ENTRIES); assert(self.index[level - 1] == NR_ENTRIES - 1);
1063
1064 if level < NR_LEVELS {
1065 self.align_up_carry(level);
1066 let prev_aligned = self.align_down(level + 1);
1069 self.align_down_shape(level + 1);
1070 self.align_down_to_vaddr_nat_align_down(level + 1);
1071 self.align_down_leading_bits(level + 1);
1072 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1073 self.to_vaddr_bounded();
1074 prev_aligned.to_vaddr_bounded();
1075
1076 let ps1 = page_size((level + 1) as PagingLevel) as nat;
1078 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.to_vaddr() as nat, ps1);
1079 assert(prev_aligned.to_vaddr() as nat % ps1 == 0);
1080
1081 let ps = page_size(level as PagingLevel) as int;
1083 assert(ps1 == NR_ENTRIES * ps) by {
1084 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
1085 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
1086 (level + 1) as PagingLevel);
1087 };
1088
1089 assert forall|i: int| 0 <= i < level - 1 implies self.index[i] == 0 by {
1093 assert(self.index.contains_key(i));
1094 };
1095 self.to_vaddr_indices_drop_zero_range(0, level - 1);
1096 prev_aligned.to_vaddr_indices_drop_zero_range(0, level);
1097 prev_aligned.to_vaddr_indices_eq_if_indices_eq(self, level);
1098
1099 assert(self.index.contains_key(level - 1));
1100 if level == 1 {
1101 assert(ps == 0x1000);
1102 assert(pow2(12nat) == ps);
1103 } else if level == 2 {
1104 assert(ps == 0x20_0000);
1105 assert(pow2(21nat) == ps);
1106 } else if level == 3 {
1107 assert(ps == 0x4000_0000);
1108 assert(pow2(30nat) == ps);
1109 }
1110 assert(self.to_vaddr_indices(level - 1) == self.index[level - 1] * ps
1111 + self.to_vaddr_indices(level));
1112 assert(self.to_vaddr_indices(level - 1) == (NR_ENTRIES - 1) * ps
1113 + self.to_vaddr_indices(level));
1114
1115 assert(prev_aligned.offset == 0);
1117 assert(prev_aligned.leading_bits == self.leading_bits);
1118 assert(self.offset == 0);
1119
1120 assert(prev_aligned.to_vaddr() + (NR_ENTRIES - 1) * ps == self.to_vaddr());
1121
1122 assert(prev_aligned.to_vaddr() + ps1 == self.to_vaddr() + ps) by (nonlinear_arith)
1124 requires
1125 prev_aligned.to_vaddr() + (NR_ENTRIES - 1) * ps == self.to_vaddr(),
1126 ps1 == NR_ENTRIES * ps,
1127 ;
1128 assert(prev_aligned.to_vaddr() + page_size((level + 1) as PagingLevel)
1129 <= usize::MAX);
1130
1131 prev_aligned.aligned_align_up_advances(level + 1);
1132 prev_aligned.aligned_align_down_is_self(level + 1);
1133
1134 assert(self.align_up(level + 1) == prev_aligned.align_up(level + 1));
1137
1138 } else {
1145 assert(level == NR_LEVELS);
1148 self.align_down_shape(NR_LEVELS as int);
1156 self.to_vaddr_bounded();
1157 assert forall|i: int| 0 <= i < NR_LEVELS - 1 implies self.index[i] == 0 by {
1158 assert(self.index.contains_key(i));
1159 assert(self.align_down(NR_LEVELS as int).index[i] == 0);
1160 };
1161 self.to_vaddr_indices_drop_zero_range(0, NR_LEVELS - 1);
1162 assert(self.index.contains_key(NR_LEVELS - 1));
1163 let ps_top = page_size(NR_LEVELS as PagingLevel) as int;
1164 assert(ps_top == 0x80_0000_0000);
1165 assert(self.to_vaddr_indices(NR_LEVELS as int) == 0);
1166 assert(self.to_vaddr_indices(NR_LEVELS - 1) == self.index[NR_LEVELS - 1] * ps_top);
1167 assert(self.to_vaddr_indices(0) == (NR_ENTRIES - 1) * ps_top);
1168 assert(self.offset == 0);
1169 assert(self.to_vaddr() == (NR_ENTRIES - 1) * ps_top + self.leading_bits
1170 * 0x1_0000_0000_0000int);
1171 assert(NR_ENTRIES * ps_top == 0x1_0000_0000_0000int) by (compute);
1172 assert(self.leading_bits + 1 < 0x1_0000) by (nonlinear_arith)
1174 requires
1175 self.to_vaddr() == (NR_ENTRIES - 1) * ps_top + self.leading_bits
1176 * 0x1_0000_0000_0000int,
1177 self.to_vaddr() + ps_top <= usize::MAX,
1178 ps_top == 0x80_0000_0000,
1179 NR_ENTRIES * ps_top == 0x1_0000_0000_0000int,
1180 0 <= self.leading_bits < 0x1_0000,
1181 usize::MAX == 0xffff_ffff_ffff_ffffusize,
1182 ;
1183
1184 let advanced_top = AbstractVaddr {
1190 index: self.index.insert(NR_LEVELS - 1, 0),
1191 leading_bits: self.leading_bits + 1,
1192 ..self
1193 };
1194 assert(self.next_index(NR_LEVELS as int) == advanced_top);
1195 assert(self.align_up(NR_LEVELS as int) == advanced_top);
1196
1197 assert(advanced_top.inv()) by {
1198 assert(advanced_top.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
1199 assert forall|i: int|
1200 #![trigger advanced_top.index.contains_key(i)]
1201 0 <= i < NR_LEVELS implies {
1202 &&& advanced_top.index.contains_key(i)
1203 &&& 0 <= advanced_top.index[i]
1204 &&& advanced_top.index[i] < NR_ENTRIES
1205 } by {
1206 assert(self.index.contains_key(i));
1207 }
1208 };
1209
1210 self.to_vaddr_bounded();
1220 advanced_top.to_vaddr_bounded();
1221 let ps = page_size(NR_LEVELS as PagingLevel) as int;
1222 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
1223 assert(ps == 0x80_0000_0000);
1225
1226 self.align_down_shape(NR_LEVELS as int);
1229 assert forall|i: int| 0 <= i < NR_LEVELS - 1 implies self.index[i] == 0 by {
1230 assert(self.index.contains_key(i));
1231 assert(self.align_down(NR_LEVELS as int).index[i] == 0);
1232 };
1233 self.to_vaddr_indices_drop_zero_range(0, NR_LEVELS - 1);
1234 assert(self.index.contains_key(NR_LEVELS - 1));
1235 assert(self.to_vaddr_indices(NR_LEVELS - 1) == self.index[NR_LEVELS - 1] * ps
1236 + self.to_vaddr_indices(NR_LEVELS as int));
1237 assert(self.to_vaddr_indices(NR_LEVELS as int) == 0);
1238 assert(self.to_vaddr_indices(0) == (NR_ENTRIES - 1) * ps);
1239
1240 assert(advanced_top.offset == 0);
1242 assert forall|i: int| 0 <= i < NR_LEVELS implies advanced_top.index[i] == 0 by {
1243 assert(self.index.contains_key(i));
1244 };
1245 advanced_top.to_vaddr_indices_drop_zero_range(0, NR_LEVELS as int);
1246 assert(advanced_top.to_vaddr_indices(0) == 0);
1247
1248 assert(advanced_top.leading_bits == self.leading_bits + 1);
1253 assert(advanced_top.to_vaddr() == (self.leading_bits + 1) * 0x1_0000_0000_0000int);
1254 assert(self.to_vaddr() == (NR_ENTRIES - 1) * ps + self.leading_bits
1255 * 0x1_0000_0000_0000int);
1256 assert(NR_ENTRIES * ps == 0x1_0000_0000_0000int) by (compute);
1257 assert(advanced_top.to_vaddr() == self.to_vaddr() + ps) by (nonlinear_arith)
1258 requires
1259 advanced_top.to_vaddr() == (self.leading_bits + 1) * 0x1_0000_0000_0000int,
1260 self.to_vaddr() == (NR_ENTRIES - 1) * ps + self.leading_bits
1261 * 0x1_0000_0000_0000int,
1262 NR_ENTRIES * ps == 0x1_0000_0000_0000int,
1263 ;
1264 }
1265 }
1266 }
1267
1268 pub proof fn align_up_advances_general(self, level: int)
1275 requires
1276 self.inv(),
1277 1 <= level <= NR_LEVELS,
1278 nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1282 + page_size(level as PagingLevel) as nat <= usize::MAX as nat,
1283 ensures
1284 self.align_up(level).inv(),
1285 self.align_up(level).to_vaddr() as nat == nat_align_down(
1286 self.to_vaddr() as nat,
1287 page_size(level as PagingLevel) as nat,
1288 ) + page_size(level as PagingLevel) as nat,
1289 {
1290 let aligned = self.align_down(level);
1291 let ps = page_size(level as PagingLevel) as nat;
1292
1293 self.align_down_shape(level);
1294 self.align_down_to_vaddr_nat_align_down(level);
1295 lemma_page_size_ge_page_size(level as PagingLevel);
1296 self.to_vaddr_bounded();
1297 aligned.to_vaddr_bounded();
1298 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.to_vaddr() as nat, ps);
1299
1300 assert(aligned.to_vaddr() as nat % ps == 0);
1303
1304 assert(aligned.to_vaddr() + page_size(level as PagingLevel) <= usize::MAX);
1306
1307 aligned.aligned_align_up_advances(level);
1309
1310 aligned.aligned_align_down_is_self(level);
1316 assert(self.align_up(level) == aligned.align_up(level));
1317 }
1318
1319 pub proof fn align_diff_sound(self, level: int)
1321 requires
1322 1 <= level <= NR_LEVELS,
1323 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat != 0,
1324 ensures
1325 nat_align_up(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1326 == nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1327 + page_size(level as PagingLevel),
1328 {
1329 }
1331
1332 pub proof fn align_up_carry(self, level: int)
1335 requires
1336 self.inv(),
1337 1 <= level,
1338 level < NR_LEVELS,
1339 self.index[level - 1] == NR_ENTRIES - 1,
1340 ensures
1341 self.align_up(level) == self.align_up(level + 1),
1342 decreases NR_LEVELS - level,
1343 {
1344 self.align_down_shape(level);
1345 self.align_down_shape(level + 1);
1346 assert(self.align_down(level).index.insert(level - 1, 0) == self.align_down(
1347 level + 1,
1348 ).index);
1349 }
1350
1351 pub open spec fn next_index(self, level: int) -> Self
1352 decreases NR_LEVELS - level,
1353 when 1 <= level <= NR_LEVELS
1354 {
1355 let index = self.index[level - 1];
1356 let next_index = index + 1;
1357 if next_index == NR_ENTRIES && level < NR_LEVELS {
1358 let next_va = Self { index: self.index.insert(level - 1, 0), ..self };
1359 next_va.next_index(level + 1)
1360 } else if next_index == NR_ENTRIES && level == NR_LEVELS {
1361 Self {
1363 index: self.index.insert(level - 1, 0),
1364 leading_bits: self.leading_bits + 1,
1365 ..self
1366 }
1367 } else {
1368 Self { index: self.index.insert(level - 1, next_index), ..self }
1369 }
1370 }
1371
1372 pub open spec fn wrapped(self, start_level: int, level: int) -> bool
1373 decreases NR_LEVELS - level,
1374 when 1 <= start_level <= level <= NR_LEVELS
1375 {
1376 &&& self.next_index(start_level).index[level - 1] == 0 ==> {
1377 &&& self.index[level - 1] + 1 == NR_ENTRIES
1378 &&& if level < NR_LEVELS {
1379 self.wrapped(start_level, level + 1)
1380 } else {
1381 true
1382 }
1383 }
1384 &&& self.next_index(start_level).index[level - 1] != 0 ==> self.index[level - 1] + 1
1385 < NR_ENTRIES
1386 }
1387
1388 pub proof fn use_wrapped(self, start_level: int, level: int)
1389 requires
1390 1 <= start_level <= level < NR_LEVELS,
1391 self.wrapped(start_level, level),
1392 self.next_index(start_level).index[level - 1] == 0,
1393 ensures
1394 self.index[level - 1] + 1 == NR_ENTRIES,
1395 {
1396 }
1397
1398 pub proof fn wrapped_unwrap(self, start_level: int, level: int)
1399 requires
1400 1 <= start_level <= level < NR_LEVELS,
1401 self.wrapped(start_level, level),
1402 self.next_index(start_level).index[level - 1] == 0,
1403 ensures
1404 self.wrapped(start_level, level + 1),
1405 {
1406 }
1407
1408 pub proof fn wrapped_after_carry_equiv(self, start_level: int, level: int)
1409 requires
1410 self.inv(),
1411 1 <= start_level < level <= NR_LEVELS,
1412 self.index[start_level - 1] + 1 == NR_ENTRIES,
1413 ensures
1414 ({
1415 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1416 self.wrapped(start_level, level) == next_va.wrapped(start_level + 1, level)
1417 }),
1418 decreases NR_LEVELS - level,
1419 {
1420 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1421 if level < NR_LEVELS {
1422 self.wrapped_after_carry_equiv(start_level, level + 1);
1423 }
1424 }
1425
1426 pub proof fn wrapped_index_nonzero(self, start_level: int, level: int)
1428 requires
1429 1 <= start_level <= level <= NR_LEVELS,
1430 self.wrapped(start_level, level),
1431 self.index[level - 1] + 1 < NR_ENTRIES,
1432 ensures
1433 self.next_index(start_level).index[level - 1] != 0,
1434 {
1435 if self.next_index(start_level).index[level - 1] == 0 {
1436 if level < NR_LEVELS {
1437 self.use_wrapped(start_level, level);
1438 }
1439 }
1440 }
1441
1442 pub proof fn wrapped_nonzero_at_level(
1444 abs_va_down: Self,
1445 abs_next_va: Self,
1446 start_level: int,
1447 level: int,
1448 owner_index_at_level: int,
1449 )
1450 requires
1451 1 <= start_level <= level <= NR_LEVELS,
1452 abs_va_down.wrapped(start_level, level),
1453 abs_va_down.next_index(start_level) == abs_next_va,
1454 abs_va_down.index[level - 1] == owner_index_at_level,
1455 owner_index_at_level == 0,
1456 ensures
1457 abs_next_va.index[level - 1] != 0,
1458 {
1459 abs_va_down.wrapped_index_nonzero(start_level, level);
1460 }
1461
1462 pub proof fn wrapped_nonzero_at_level_general(
1466 abs_va_down: Self,
1467 abs_next_va: Self,
1468 start_level: int,
1469 level: int,
1470 owner_index_at_level: int,
1471 )
1472 requires
1473 1 <= start_level <= level <= NR_LEVELS,
1474 abs_va_down.wrapped(start_level, level),
1475 abs_va_down.next_index(start_level) == abs_next_va,
1476 abs_va_down.index[level - 1] == owner_index_at_level,
1477 owner_index_at_level + 1 < NR_ENTRIES,
1478 ensures
1479 abs_next_va.index[level - 1] != 0,
1480 {
1481 abs_va_down.wrapped_index_nonzero(start_level, level);
1482 }
1483
1484 #[verifier::spinoff_prover]
1485 pub proof fn next_index_preserves_lower_indices(self, start_level: int, lower_level: int)
1486 requires
1487 self.inv(),
1488 1 <= lower_level < start_level <= NR_LEVELS,
1489 ensures
1490 self.next_index(start_level).index[lower_level - 1] == self.index[lower_level - 1],
1491 decreases NR_LEVELS - start_level,
1492 {
1493 let index = self.index[start_level - 1];
1494 let next_index = index + 1;
1495 if next_index == NR_ENTRIES && start_level < NR_LEVELS {
1496 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1497 assert(next_va.inv()) by {
1498 assert(next_va.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
1499 assert forall|i: int|
1500 #![trigger next_va.index.contains_key(i)]
1501 0 <= i < NR_LEVELS implies {
1502 &&& next_va.index.contains_key(i)
1503 &&& 0 <= next_va.index[i]
1504 &&& next_va.index[i] < NR_ENTRIES
1505 } by {
1506 assert(self.index.contains_key(i));
1507 }
1508 };
1509 next_va.next_index_preserves_lower_indices(start_level + 1, lower_level);
1510 } else if next_index == NR_ENTRIES && start_level == NR_LEVELS {
1511 }
1512 }
1513
1514 pub proof fn next_index_wrap_condition(self, level: int)
1515 requires
1516 self.inv(),
1517 1 <= level <= NR_LEVELS,
1518 ensures
1519 self.wrapped(level, level),
1520 decreases NR_LEVELS - level,
1521 {
1522 let index = self.index[level - 1];
1523 let next_index = index + 1;
1524 if next_index == NR_ENTRIES {
1525 if level < NR_LEVELS {
1526 let next_va = Self { index: self.index.insert(level - 1, 0), ..self };
1527 self.lemma_insert_zero_preserves_inv(level - 1);
1528 next_va.next_index_wrap_condition(level + 1);
1529 self.wrapped_after_carry_equiv(level, level + 1);
1530 next_va.next_index_preserves_lower_indices(level + 1, level);
1531 }
1532 } else {
1533 assert(self.index.contains_key(level - 1));
1534 }
1535 }
1536
1537 pub open spec fn compute_vaddr(self) -> Vaddr {
1550 self.rec_compute_vaddr(0)
1551 }
1552
1553 pub open spec fn rec_compute_vaddr(self, i: int) -> Vaddr
1555 decreases NR_LEVELS - i,
1556 when 0 <= i <= NR_LEVELS
1557 {
1558 if i >= NR_LEVELS {
1559 self.offset as Vaddr
1560 } else {
1561 let shift = page_size((i + 1) as PagingLevel);
1562 (self.index[i] * shift + self.rec_compute_vaddr(i + 1)) as Vaddr
1563 }
1564 }
1565
1566 pub open spec fn to_path(self, level: int) -> TreePath<NR_ENTRIES>
1576 recommends
1577 0 <= level < NR_LEVELS,
1578 {
1579 TreePath(self.rec_to_path(NR_LEVELS - 1, level))
1580 }
1581
1582 pub open spec fn rec_to_path(self, abstract_level: int, bottom_level: int) -> Seq<int>
1586 decreases abstract_level - bottom_level,
1587 when bottom_level <= abstract_level
1588 {
1589 if abstract_level < bottom_level {
1590 seq![]
1591 } else if abstract_level == bottom_level {
1592 seq![self.index[abstract_level]]
1594 } else {
1595 seq![self.index[abstract_level]].add(self.rec_to_path(abstract_level - 1, bottom_level))
1597 }
1598 }
1599
1600 #[verifier::rlimit(200)]
1606 pub proof fn to_path_vaddr(self, level: int)
1607 requires
1608 self.inv(),
1609 0 <= level < NR_LEVELS,
1610 ensures
1611 vaddr(self.to_path(level)) == self.align_down(level + 1).compute_vaddr(),
1612 {
1613 self.to_path_inv(level);
1614 self.to_path_len(level);
1615 lemma_page_size_spec_level1();
1616 vstd::arithmetic::power2::lemma2_to64();
1617 vstd::arithmetic::power2::lemma2_to64_rest();
1618 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
1619 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1620 let path = self.to_path(level);
1621 if level == 3 {
1622 let aligned = self.align_down(4);
1623 self.align_down_shape(4);
1624 self.to_path_index(3, 0);
1625 path.lemma_index_satisfies_elem_inv(0);
1626 assert(vaddr(path) == path[0] * 0x80_0000_0000usize) by {
1627 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, path[0] as usize)
1628 + rec_vaddr(path, 1)) as usize);
1629 };
1630 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1631 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1632 + aligned.rec_compute_vaddr(4)) as Vaddr);
1633 };
1634 assert(aligned.rec_compute_vaddr(2) == self.index[3] * 0x80_0000_0000usize) by {
1635 assert(aligned.rec_compute_vaddr(2) == (aligned.index[2] * page_size(3)
1636 + aligned.rec_compute_vaddr(3)) as Vaddr);
1637 };
1638 assert(aligned.rec_compute_vaddr(1) == self.index[3] * 0x80_0000_0000usize) by {
1639 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1640 + aligned.rec_compute_vaddr(2)) as Vaddr);
1641 };
1642 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1643 + aligned.rec_compute_vaddr(1)) as Vaddr);
1644 assert(vaddr(path) == aligned.compute_vaddr());
1645 } else if level == 2 {
1646 let aligned = self.align_down(3);
1647 self.align_down_shape(3);
1648 self.to_path_index(2, 0);
1649 self.to_path_index(2, 1);
1650 path.lemma_index_satisfies_elem_inv(0);
1651 path.lemma_index_satisfies_elem_inv(1);
1652 assert(vaddr(path) == path[0] * 0x80_0000_0000usize + path[1] * 0x4000_0000usize) by {
1653 assert(vaddr(path) == rec_vaddr(path, 0));
1654 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path[1] as usize)
1655 + rec_vaddr(path, 2)) as usize);
1656 };
1657 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1658 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1659 + aligned.rec_compute_vaddr(4)) as Vaddr);
1660 };
1661 assert(aligned.rec_compute_vaddr(1) == self.index[2] * 0x4000_0000usize + self.index[3]
1662 * 0x80_0000_0000usize) by {
1663 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1664 + aligned.rec_compute_vaddr(2)) as Vaddr);
1665 };
1666 assert(vaddr(path) == aligned.compute_vaddr());
1667 } else if level == 1 {
1668 let aligned = self.align_down(2);
1669 self.align_down_shape(2);
1670 self.to_path_index(1, 0);
1671 self.to_path_index(1, 1);
1672 self.to_path_index(1, 2);
1673 path.lemma_index_satisfies_elem_inv(0);
1674 path.lemma_index_satisfies_elem_inv(1);
1675 path.lemma_index_satisfies_elem_inv(2);
1676 assert(vaddr(path) == path[0] * 0x80_0000_0000usize + path[1] * 0x4000_0000usize
1677 + path[2] * 0x20_0000usize) by {
1678 assert(vaddr(path) == rec_vaddr(path, 0));
1679 assert(rec_vaddr(path, 3) == 0);
1680 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, path[2] as usize)
1681 + rec_vaddr(path, 3)) as usize);
1682 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path[1] as usize)
1683 + rec_vaddr(path, 2)) as usize);
1684 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, path[0] as usize)
1685 + rec_vaddr(path, 1)) as usize);
1686 assert(vaddr_make::<NR_LEVELS>(0, path[0] as usize) == 0x80_0000_0000usize
1687 * path[0]) by (compute);
1688 assert(vaddr_make::<NR_LEVELS>(1, path[1] as usize) == 0x4000_0000usize * path[1])
1689 by (compute);
1690 assert(vaddr_make::<NR_LEVELS>(2, path[2] as usize) == 0x20_0000usize * path[2])
1691 by (compute);
1692 };
1693 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1694 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1695 + aligned.rec_compute_vaddr(4)) as Vaddr);
1696 };
1697 assert(aligned.rec_compute_vaddr(1) == self.index[1] * 0x20_0000usize + self.index[2]
1698 * 0x4000_0000usize + self.index[3] * 0x80_0000_0000usize) by {
1699 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1700 + aligned.rec_compute_vaddr(2)) as Vaddr);
1701 };
1702 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1703 + aligned.rec_compute_vaddr(1)) as Vaddr);
1704 assert(vaddr(path) == aligned.compute_vaddr());
1705 } else {
1706 let aligned = self.align_down(1);
1707 self.align_down_shape(1);
1708 self.to_path_index(0, 0);
1709 self.to_path_index(0, 1);
1710 self.to_path_index(0, 2);
1711 self.to_path_index(0, 3);
1712 path.lemma_index_satisfies_elem_inv(0);
1713 path.lemma_index_satisfies_elem_inv(1);
1714 path.lemma_index_satisfies_elem_inv(2);
1715 path.lemma_index_satisfies_elem_inv(3);
1716 assert(vaddr(path) == path[0] * 0x80_0000_0000usize + path[1] * 0x4000_0000usize
1717 + path[2] * 0x20_0000usize + path[3] * 0x1000usize) by {
1718 assert(vaddr(path) == rec_vaddr(path, 0));
1719 assert(rec_vaddr(path, 4) == 0);
1720 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, path[2] as usize)
1721 + rec_vaddr(path, 3)) as usize);
1722 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path[1] as usize)
1723 + rec_vaddr(path, 2)) as usize);
1724 assert(vaddr_make::<NR_LEVELS>(0, path[0] as usize) == 0x80_0000_0000usize
1725 * path[0]) by (compute);
1726 assert(vaddr_make::<NR_LEVELS>(1, path[1] as usize) == 0x4000_0000usize * path[1])
1727 by (compute);
1728 assert(vaddr_make::<NR_LEVELS>(2, path[2] as usize) == 0x20_0000usize * path[2])
1729 by {
1730 assert(vaddr_shift_bits::<NR_LEVELS>(2) == 21nat) by (compute);
1731 assert(pow2(21nat) == 0x20_0000) by (compute);
1732 }
1733 assert(vaddr_make::<NR_LEVELS>(3, path[3] as usize) == 0x1000usize * path[3])
1734 by (compute);
1735 };
1736 assert(aligned.rec_compute_vaddr(4) == 0);
1737 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1738 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1739 + aligned.rec_compute_vaddr(4)) as Vaddr);
1740 };
1741 assert(aligned.rec_compute_vaddr(2) == self.index[2] * 0x4000_0000usize + self.index[3]
1742 * 0x80_0000_0000usize);
1743 assert(aligned.compute_vaddr() == self.index[0] * 0x1000usize + self.index[1]
1744 * 0x20_0000usize + self.index[2] * 0x4000_0000usize + self.index[3]
1745 * 0x80_0000_0000usize) by {
1746 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1747 + aligned.rec_compute_vaddr(1)) as Vaddr);
1748 };
1749 assert(vaddr(path) == aligned.compute_vaddr());
1750 }
1751 }
1752
1753 pub proof fn rec_compute_vaddr_is_to_vaddr_indices(self, start: int)
1757 requires
1758 self.inv(),
1759 0 <= start <= NR_LEVELS,
1760 ensures
1761 self.rec_compute_vaddr(start) == self.to_vaddr_indices(start) + self.offset,
1762 decreases NR_LEVELS - start,
1763 {
1764 vstd::arithmetic::power2::lemma2_to64();
1765 vstd::arithmetic::power2::lemma2_to64_rest();
1766 lemma_page_size_spec_values();
1767 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1768 self.to_vaddr_indices_gap_bound(start);
1769 if start < NR_LEVELS {
1770 self.rec_compute_vaddr_is_to_vaddr_indices(start + 1);
1771 self.to_vaddr_indices_gap_bound(start + 1);
1772 assert(self.index.contains_key(start));
1773 if start == 0 {
1777 assert(page_size(1) == pow2(12nat) as usize);
1778 } else if start == 1 {
1779 assert(page_size(2) == pow2(21nat) as usize);
1780 } else if start == 2 {
1781 assert(page_size(3) == pow2(30nat) as usize);
1782 } else {
1783 assert(page_size(4) == pow2(39nat) as usize);
1784 }
1785 }
1786 }
1787
1788 pub proof fn to_vaddr_is_compute_vaddr(self)
1795 requires
1796 self.inv(),
1797 ensures
1798 self.to_vaddr() == self.compute_vaddr() + self.leading_bits * 0x1_0000_0000_0000int,
1799 {
1800 self.to_vaddr_bounded();
1801 self.rec_compute_vaddr_is_to_vaddr_indices(0);
1802 }
1803
1804 pub proof fn to_vaddr_indices_gap_bound(self, start: int)
1805 requires
1806 self.inv(),
1807 0 <= start <= NR_LEVELS,
1808 ensures
1809 0 <= self.to_vaddr_indices(start),
1810 self.to_vaddr_indices(start) + pow2((12 + 9 * start) as nat) <= pow2(
1811 (12 + 9 * NR_LEVELS) as nat,
1812 ),
1813 decreases NR_LEVELS - start,
1814 {
1815 vstd::arithmetic::power2::lemma2_to64();
1816 vstd::arithmetic::power2::lemma2_to64_rest();
1817 vstd::arithmetic::power2::lemma_pow2_pos((12 + 9 * start) as nat);
1818 if start == NR_LEVELS {
1819 } else {
1820 let shift = pow2((12 + 9 * start) as nat) as int;
1821 let next_shift = pow2((12 + 9 * (start + 1)) as nat) as int;
1822 let top = pow2((12 + 9 * NR_LEVELS) as nat) as int;
1823 self.to_vaddr_indices_gap_bound(start + 1);
1824 assert(self.index.contains_key(start));
1825 vstd::arithmetic::power2::lemma_pow2_adds((12 + 9 * start) as nat, 9nat);
1826 vstd::arithmetic::mul::lemma_mul_inequality(self.index[start] + 1, 0x200int, shift);
1827 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1828 shift,
1829 self.index[start],
1830 1,
1831 );
1832 }
1833 }
1834
1835 pub proof fn to_vaddr_bounded(self)
1836 requires
1837 self.inv(),
1838 ensures
1839 0 <= self.offset + self.to_vaddr_indices(0) < 0x1_0000_0000_0000int,
1840 self.to_vaddr() == self.offset + self.to_vaddr_indices(0) + self.leading_bits
1841 * 0x1_0000_0000_0000int,
1842 self.offset + self.to_vaddr_indices(0) + self.leading_bits * 0x1_0000_0000_0000int
1843 < 0x1_0000_0000_0000_0000int,
1844 {
1845 vstd::arithmetic::power2::lemma2_to64();
1846 vstd::arithmetic::power2::lemma2_to64_rest();
1847 self.to_vaddr_indices_gap_bound(0);
1848 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
1849 assert(self.leading_bits * 0x1_0000_0000_0000int + 0x1_0000_0000_0000int <= 0x1_0000
1850 * 0x1_0000_0000_0000int) by (nonlinear_arith)
1851 requires
1852 0 <= self.leading_bits < 0x1_0000int,
1853 ;
1854 assert(0x1_0000 * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int) by (compute);
1855 }
1856
1857 #[verifier::spinoff_prover]
1858 pub proof fn index_increment_adds_page_size(self, level: int)
1859 requires
1860 self.inv(),
1861 1 <= level <= NR_LEVELS,
1862 self.index[level - 1] + 1 < NR_ENTRIES,
1863 ensures
1864 (Self {
1865 index: self.index.insert(level - 1, self.index[level - 1] + 1),
1866 ..self
1867 }).to_vaddr() == self.to_vaddr() + page_size(level as PagingLevel),
1868 {
1869 let new_va = Self {
1870 index: self.index.insert(level - 1, self.index[level - 1] + 1),
1871 ..self
1872 };
1873 assert forall|i: int| #![trigger new_va.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
1874 &&& new_va.index.contains_key(i)
1875 &&& 0 <= new_va.index[i]
1876 &&& new_va.index[i] < NR_ENTRIES
1877 } by {
1878 assert(self.index.contains_key(i));
1879 };
1880 self.to_vaddr_bounded();
1881 new_va.to_vaddr_bounded();
1882 assert(new_va.to_vaddr() - self.to_vaddr() == new_va.to_vaddr_indices(0)
1883 - self.to_vaddr_indices(0));
1884 vstd::arithmetic::power2::lemma2_to64();
1885 vstd::arithmetic::power2::lemma2_to64_rest();
1886 if level == 1 {
1887 lemma_page_size_spec_level1();
1888 new_va.to_vaddr_indices_eq_if_indices_eq(self, 1);
1889 assert((self.index[0] + 1) * 0x1000 == self.index[0] * 0x1000 + 0x1000)
1890 by (nonlinear_arith);
1891 } else if level == 2 {
1892 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1893 new_va.to_vaddr_indices_eq_if_indices_eq(self, 2);
1894 assert(self.to_vaddr_indices(0) == self.index[0] * pow2(12nat) + self.to_vaddr_indices(
1895 1,
1896 ));
1897 assert((self.index[1] + 1) * 0x20_0000 == self.index[1] * 0x20_0000 + 0x20_0000)
1898 by (nonlinear_arith);
1899 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x20_0000);
1900 } else if level == 3 {
1901 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1902 new_va.to_vaddr_indices_eq_if_indices_eq(self, 3);
1903 assert(self.index.contains_key(2));
1904 assert(new_va.index.contains_key(2));
1905 assert((12 + 9 * 2) as nat == 30nat) by (compute);
1906 assert((self.index[2] + 1) * 0x4000_0000 == self.index[2] * 0x4000_0000 + 0x4000_0000)
1907 by (nonlinear_arith);
1908 assert(new_va.to_vaddr_indices(2) == self.to_vaddr_indices(2) + 0x4000_0000);
1909 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x4000_0000);
1910 } else {
1911 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1912 new_va.to_vaddr_indices_eq_if_indices_eq(self, 4);
1913 assert(self.to_vaddr_indices(1) == self.index[1] * pow2(21nat) + self.to_vaddr_indices(
1914 2,
1915 ));
1916 assert(self.to_vaddr_indices(2) == self.index[2] * pow2(30nat) + self.to_vaddr_indices(
1917 3,
1918 ));
1919 assert((self.index[3] + 1) * 0x80_0000_0000 == self.index[3] * 0x80_0000_0000
1920 + 0x80_0000_0000) by (nonlinear_arith);
1921 assert(new_va.to_vaddr_indices(3) == self.to_vaddr_indices(3) + 0x80_0000_0000);
1922 assert(new_va.to_vaddr_indices(2) == self.to_vaddr_indices(2) + 0x80_0000_0000);
1923 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x80_0000_0000);
1924 }
1925 }
1926
1927 pub proof fn to_path_len(self, level: int)
1929 requires
1930 0 <= level < NR_LEVELS,
1931 ensures
1932 self.to_path(level).len() == NR_LEVELS - level,
1933 {
1934 self.rec_to_path_len(NR_LEVELS - 1, level);
1935 }
1936
1937 proof fn rec_to_path_len(self, abstract_level: int, bottom_level: int)
1938 requires
1939 bottom_level <= abstract_level,
1940 ensures
1941 self.rec_to_path(abstract_level, bottom_level).len() == abstract_level - bottom_level
1942 + 1,
1943 decreases abstract_level - bottom_level,
1944 {
1945 if abstract_level > bottom_level {
1950 self.rec_to_path_len(abstract_level - 1, bottom_level);
1951 }
1952 }
1955
1956 pub proof fn to_path_inv(self, level: int)
1958 requires
1959 self.inv(),
1960 0 <= level < NR_LEVELS,
1961 ensures
1962 self.to_path(level).inv(),
1963 {
1964 self.to_path_len(level);
1965 assert forall|i: int| 0 <= i < self.to_path(level).len() implies TreePath::<
1966 NR_ENTRIES,
1967 >::elem_inv(#[trigger] self.to_path(level)[i]) by {
1968 let j = NR_LEVELS - 1 - i;
1969 self.to_path_index(level, i);
1970 assert(self.index.contains_key(j));
1971 };
1972 }
1973}
1974
1975impl AbstractVaddr {
1977 proof fn rec_vaddr_eq_if_indices_eq(
1978 path1: TreePath<NR_ENTRIES>,
1979 path2: TreePath<NR_ENTRIES>,
1980 idx: int,
1981 )
1982 requires
1983 path1.inv(),
1984 path2.inv(),
1985 path1.len() == path2.len(),
1986 0 <= idx <= path1.len(),
1987 forall|i: int| idx <= i < path1.len() ==> path1[i] == path2[i],
1988 ensures
1989 rec_vaddr(path1, idx) == rec_vaddr(path2, idx),
1990 decreases path1.len() - idx,
1991 {
1992 if idx < path1.len() {
1993 path1.lemma_index_satisfies_elem_inv(idx);
1994 path2.lemma_index_satisfies_elem_inv(idx);
1995 Self::rec_vaddr_eq_if_indices_eq(path1, path2, idx + 1);
1996 }
1997 }
1998
1999 pub proof fn path_matches_vaddr(self, path: TreePath<NR_ENTRIES>)
2002 requires
2003 self.inv(),
2004 path.inv(),
2005 path.len() <= NR_LEVELS,
2006 forall|i: int| 0 <= i < path.len() ==> path[i] == self.index[NR_LEVELS - 1 - i],
2007 ensures
2008 vaddr(path) == self.align_down(NR_LEVELS - path.len() + 1).compute_vaddr()
2009 - self.align_down(NR_LEVELS - path.len() + 1).offset,
2010 {
2011 lemma_arch_specific_consts_properties::<crate::mm::PagingConsts>();
2012 if path.len() == 0 {
2013 let aligned = self.align_down(5);
2014 self.align_down_shape(4);
2015 assert(aligned.index[3] == 0) by {
2017 assert(aligned == AbstractVaddr {
2018 index: self.align_down(4).index.insert(3, 0),
2019 ..self.align_down(4)
2020 });
2021 };
2022 assert(aligned.rec_compute_vaddr(4) == 0);
2023 assert(aligned.rec_compute_vaddr(3) == 0) by {
2024 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
2025 + aligned.rec_compute_vaddr(4)) as Vaddr);
2026 };
2027 assert(aligned.rec_compute_vaddr(2) == 0) by {
2028 assert(aligned.rec_compute_vaddr(2) == (aligned.index[2] * page_size(3)
2029 + aligned.rec_compute_vaddr(3)) as Vaddr);
2030 };
2031 assert(aligned.rec_compute_vaddr(1) == 0) by {
2032 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
2033 + aligned.rec_compute_vaddr(2)) as Vaddr);
2034 };
2035 } else {
2036 let level = NR_LEVELS - path.len();
2037 self.to_path_inv(level);
2038 self.to_path_len(level);
2039 assert forall|i: int| 0 <= i < path.len() implies #[trigger] path[i] == self.to_path(
2040 level,
2041 )[i] by {
2042 self.to_path_index(level, i);
2043 };
2044 Self::rec_vaddr_eq_if_indices_eq(path, self.to_path(level), 0);
2045 self.to_path_vaddr(level);
2046 self.align_down_shape(level + 1);
2047 }
2048 }
2049
2050 pub proof fn to_path_index(self, level: int, i: int)
2053 requires
2054 self.inv(),
2055 0 <= level < NR_LEVELS,
2056 0 <= i < NR_LEVELS - level,
2057 ensures
2058 self.to_path(level)[i] == self.index[NR_LEVELS - 1 - i],
2059 {
2060 self.to_path_len(level);
2061 self.rec_to_path_index(NR_LEVELS - 1, level, i);
2062 }
2063
2064 proof fn rec_to_path_index(self, abstract_level: int, bottom_level: int, i: int)
2065 requires
2066 self.inv(),
2067 0 <= bottom_level <= abstract_level < NR_LEVELS,
2068 0 <= i < abstract_level - bottom_level + 1,
2069 ensures
2070 self.rec_to_path(abstract_level, bottom_level)[i] == self.index[abstract_level - i],
2071 decreases abstract_level - bottom_level,
2072 {
2073 assert(self.index.contains_key(abstract_level));
2074 if abstract_level == bottom_level {
2075 } else {
2076 let head = seq![self.index[abstract_level]];
2077 let tail = self.rec_to_path(abstract_level - 1, bottom_level);
2078 let full = head.add(tail);
2079 if i == 0 {
2080 } else {
2081 self.rec_to_path_index(abstract_level - 1, bottom_level, i - 1);
2082 assert(0 <= i - 1 < tail.len()) by {
2083 self.rec_to_path_len(abstract_level - 1, bottom_level);
2084 };
2085 }
2086 }
2087 }
2088
2089 pub proof fn to_path_vaddr_concrete(self, level: int)
2094 requires
2095 self.inv(),
2096 0 <= level < NR_LEVELS,
2097 ensures
2098 vaddr(self.to_path(level)) + self.leading_bits * 0x1_0000_0000_0000int
2099 == nat_align_down(
2100 self.to_vaddr() as nat,
2101 page_size((level + 1) as PagingLevel) as nat,
2102 ),
2103 {
2104 self.to_path_vaddr(level);
2105 let aligned = self.align_down(level + 1);
2106 self.align_down_shape(level + 1);
2107 aligned.to_vaddr_is_compute_vaddr();
2108 self.align_down_concrete(level + 1);
2109 aligned.reflect_prop(
2110 nat_align_down(
2111 self.to_vaddr() as nat,
2112 page_size((level + 1) as PagingLevel) as nat,
2113 ) as Vaddr,
2114 );
2115 self.align_down_leading_bits(level + 1);
2116 let nad = nat_align_down(
2122 self.to_vaddr() as nat,
2123 page_size((level + 1) as PagingLevel) as nat,
2124 );
2125 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
2128 vstd_extra::arithmetic::lemma_nat_align_down_sound(
2129 self.to_vaddr() as nat,
2130 page_size((level + 1) as PagingLevel) as nat,
2131 );
2132 assert(aligned.leading_bits == self.leading_bits);
2133 assert(vaddr(self.to_path(level)) == aligned.compute_vaddr());
2134 assert(aligned.to_vaddr() == aligned.compute_vaddr() + aligned.leading_bits
2135 * 0x1_0000_0000_0000int);
2136 assert(aligned.to_vaddr() == nad as Vaddr);
2137 assert(aligned.to_vaddr() == nad);
2138 }
2139
2140 pub proof fn vaddr_range_from_path(self, level: int)
2143 requires
2144 self.inv(),
2145 0 <= level < NR_LEVELS,
2146 ensures
2147 vaddr(self.to_path(level)) + self.leading_bits * 0x1_0000_0000_0000int
2148 <= self.to_vaddr(),
2149 self.to_vaddr() < vaddr(self.to_path(level)) + self.leading_bits * 0x1_0000_0000_0000int
2150 + page_size((level + 1) as PagingLevel),
2151 {
2152 self.to_path_vaddr_concrete(level);
2153 let size = page_size((level + 1) as PagingLevel);
2154 let cur = self.to_vaddr() as nat;
2155 let start = vaddr(self.to_path(level));
2156
2157 assert(page_size((level + 1) as PagingLevel) >= PAGE_SIZE) by {
2158 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
2159 };
2160 lemma_nat_align_down_sound(cur, size as nat);
2161 }
2162}
2163
2164}