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