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 vstd::arithmetic::power2::pow2;
16use vstd::prelude::*;
17use vstd_extra::arithmetic::*;
18use vstd_extra::ghost_tree::TreePath;
19use vstd_extra::ownership::*;
20
21use crate::mm::page_table::PageTableConfig;
22use crate::mm::page_table::{page_size, page_size_spec};
23use crate::mm::{PagingLevel, Vaddr};
24use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
25
26use align_ext::AlignExt;
27
28verus! {
29
30pub struct AbstractVaddr {
42 pub offset: int,
43 pub index: Map<int, int>,
44 pub leading_bits: int,
45}
46
47impl Inv for AbstractVaddr {
48 open spec fn inv(self) -> bool {
49 &&& 0 <= self.offset
50 < PAGE_SIZE
51 &&& self.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS)
53 &&& forall|i: int|
54 #![trigger self.index.contains_key(i)]
55 0 <= i < NR_LEVELS ==> {
56 &&& self.index.contains_key(i)
57 &&& 0 <= self.index[i] < NR_ENTRIES
58 }
59 &&& 0 <= self.leading_bits < 0x1_0000int
61 }
62}
63
64impl AbstractVaddr {
65 pub open spec fn from_vaddr(va: Vaddr) -> Self {
70 AbstractVaddr {
71 offset: (va % PAGE_SIZE) as int,
72 index: Map::new(
73 |i: int| 0 <= i < NR_LEVELS,
74 |i: int| ((va / pow2((12 + 9 * i) as nat) as usize) % NR_ENTRIES) as int,
75 ),
76 leading_bits: (va as int / 0x1_0000_0000_0000int),
77 }
78 }
79
80 pub proof fn from_vaddr_wf(va: Vaddr)
81 ensures
82 AbstractVaddr::from_vaddr(va).inv(),
83 {
84 let abs = AbstractVaddr::from_vaddr(va);
85 assert forall|i: int| #![trigger abs.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
86 &&& abs.index.contains_key(i)
87 &&& 0 <= abs.index[i]
88 &&& abs.index[i] < NR_ENTRIES
89 } by {};
90 let va_i = va as int;
91 assert(0 <= abs.leading_bits < 0x1_0000int) by (nonlinear_arith)
92 requires
93 abs.leading_bits == va_i / 0x1_0000_0000_0000int,
94 0 <= va_i < 0x1_0000_0000_0000_0000int,
95 ;
96 }
97
98 pub open spec fn to_vaddr(self) -> Vaddr {
101 (self.offset + self.to_vaddr_indices(0) + self.leading_bits
102 * 0x1_0000_0000_0000int) as Vaddr
103 }
104
105 pub open spec fn to_vaddr_indices(self, start: int) -> int
107 decreases NR_LEVELS - start,
108 when start <= NR_LEVELS
109 {
110 if start >= NR_LEVELS {
111 0
112 } else {
113 self.index[start] * pow2((12 + 9 * start) as nat) as int + self.to_vaddr_indices(
114 start + 1,
115 )
116 }
117 }
118
119 pub open spec fn reflect(self, va: Vaddr) -> bool {
121 self == Self::from_vaddr(va)
122 }
123
124 pub broadcast proof fn reflect_prop(self, va: Vaddr)
127 requires
128 self.inv(),
129 self.reflect(va),
130 ensures
131 #[trigger] self.to_vaddr() == va,
132 #[trigger] Self::from_vaddr(va) == self,
133 {
134 Self::from_vaddr_to_vaddr_roundtrip(va);
138 }
139
140 pub proof fn from_vaddr_to_vaddr_roundtrip(va: Vaddr)
146 ensures
147 Self::from_vaddr(va).to_vaddr() == va,
148 {
149 vstd::arithmetic::power2::lemma2_to64();
150 vstd::arithmetic::power2::lemma2_to64_rest();
151 let abs = Self::from_vaddr(va);
152 assert(abs.to_vaddr_indices(4) == 0);
153 assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) as int + abs.to_vaddr_indices(
154 4,
155 ));
156 assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) as int + abs.to_vaddr_indices(
157 3,
158 ));
159 assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) as int + abs.to_vaddr_indices(
160 2,
161 ));
162 assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) as int + abs.to_vaddr_indices(
163 1,
164 ));
165 assert(va == (va % 4096usize) + ((va / 4096usize) % 512usize) * 4096usize + ((va
166 / 0x20_0000usize) % 512usize) * 0x20_0000usize + ((va / 0x4000_0000usize) % 512usize)
167 * 0x4000_0000usize + ((va / 0x80_0000_0000usize) % 512usize) * 0x80_0000_0000usize + (va
168 / 0x1_0000_0000_0000usize) * 0x1_0000_0000_0000usize) by (bit_vector);
169 }
170
171 pub broadcast proof fn reflect_from_vaddr(va: Vaddr)
173 ensures
174 #[trigger] Self::from_vaddr(va).reflect(va),
175 #[trigger] Self::from_vaddr(va).inv(),
176 {
177 Self::from_vaddr_wf(va);
178 }
179
180 pub broadcast proof fn reflect_to_vaddr(self)
182 requires
183 self.inv(),
184 ensures
185 #[trigger] self.reflect(self.to_vaddr()),
186 {
187 Self::to_vaddr_from_vaddr_roundtrip(self);
188 }
189
190 pub proof fn to_vaddr_from_vaddr_roundtrip(abs: Self)
193 requires
194 abs.inv(),
195 ensures
196 Self::from_vaddr(abs.to_vaddr()) == abs,
197 {
198 vstd::arithmetic::power2::lemma2_to64();
199 vstd::arithmetic::power2::lemma2_to64_rest();
200 abs.to_vaddr_bounded();
201 assert(abs.to_vaddr_indices(4) == 0);
202 assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) as int + abs.to_vaddr_indices(
203 4,
204 ));
205 assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) as int + abs.to_vaddr_indices(
206 3,
207 ));
208 assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) as int + abs.to_vaddr_indices(
209 2,
210 ));
211 assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) as int + abs.to_vaddr_indices(
212 1,
213 ));
214
215 assert(abs.index.contains_key(0));
216 assert(abs.index.contains_key(1));
217 assert(abs.index.contains_key(2));
218 assert(abs.index.contains_key(3));
219 let i0 = abs.index[0] as usize;
220 let i1 = abs.index[1] as usize;
221 let i2 = abs.index[2] as usize;
222 let i3 = abs.index[3] as usize;
223 let o = abs.offset as usize;
224 let tb = abs.leading_bits as usize;
225 let va = abs.to_vaddr();
226 assert(i0 < 512usize);
227 assert(i1 < 512usize);
228 assert(i2 < 512usize);
229 assert(i3 < 512usize);
230 assert(va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
231 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize);
232
233 assert(va % 4096usize == o) by (bit_vector)
234 requires
235 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
236 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
237 o < 4096usize,
238 i0 < 512usize,
239 i1 < 512usize,
240 i2 < 512usize,
241 i3 < 512usize,
242 tb < 0x1_0000usize,
243 ;
244 assert((va / 4096usize) % 512usize == i0) by (bit_vector)
245 requires
246 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
247 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
248 o < 4096usize,
249 i0 < 512usize,
250 i1 < 512usize,
251 i2 < 512usize,
252 i3 < 512usize,
253 tb < 0x1_0000usize,
254 ;
255 assert((va / 0x20_0000usize) % 512usize == i1) by (bit_vector)
256 requires
257 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
258 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
259 o < 4096usize,
260 i0 < 512usize,
261 i1 < 512usize,
262 i2 < 512usize,
263 i3 < 512usize,
264 tb < 0x1_0000usize,
265 ;
266 assert((va / 0x4000_0000usize) % 512usize == i2) by (bit_vector)
267 requires
268 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
269 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
270 o < 4096usize,
271 i0 < 512usize,
272 i1 < 512usize,
273 i2 < 512usize,
274 i3 < 512usize,
275 tb < 0x1_0000usize,
276 ;
277 assert((va / 0x80_0000_0000usize) % 512usize == i3) by (bit_vector)
278 requires
279 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
280 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
281 o < 4096usize,
282 i0 < 512usize,
283 i1 < 512usize,
284 i2 < 512usize,
285 i3 < 512usize,
286 tb < 0x1_0000usize,
287 ;
288 assert(va / 0x1_0000_0000_0000usize == tb) by (bit_vector)
289 requires
290 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
291 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
292 o < 4096usize,
293 i0 < 512usize,
294 i1 < 512usize,
295 i2 < 512usize,
296 i3 < 512usize,
297 tb < 0x1_0000usize,
298 ;
299
300 let back = Self::from_vaddr(va);
301 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] back.index[i]
302 == abs.index[i] by {
303 if i == 0 {
304 } else if i == 1 {
305 } else if i == 2 {
306 } else if i == 3 {
307 }
308 }
309 assert(back.index =~= abs.index);
310 }
311
312 pub broadcast proof fn reflect_eq(self, other: Self, va: Vaddr)
314 requires
315 #[trigger] self.reflect(va),
316 #[trigger] other.reflect(va),
317 ensures
318 self == other,
319 {
320 }
321
322 pub open spec fn align_down(self, level: int) -> Self
323 decreases level,
324 when level >= 1
325 {
326 if level == 1 {
327 AbstractVaddr { offset: 0, ..self }
328 } else {
329 let tmp = self.align_down(level - 1);
330 AbstractVaddr { index: tmp.index.insert(level - 2, 0), ..tmp }
331 }
332 }
333
334 pub proof fn align_down_inv(self, level: int)
335 requires
336 1 <= level <= NR_LEVELS,
337 self.inv(),
338 ensures
339 self.align_down(level).inv(),
340 forall|i: int|
341 level <= i < NR_LEVELS ==> #[trigger] self.index[i - 1] == self.align_down(
342 level,
343 ).index[i - 1],
344 decreases level,
345 {
346 if level == 1 {
347 assert(self.align_down(1).index =~= self.index);
348 } else {
349 let tmp = self.align_down(level - 1);
350 self.align_down_inv(level - 1);
351 let new = self.align_down(level);
352 assert(new.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
353 assert forall|i: int| #![trigger new.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
354 &&& new.index.contains_key(i)
355 &&& 0 <= new.index[i]
356 &&& new.index[i] < NR_ENTRIES
357 } by {
358 if i != level - 2 {
359 assert(tmp.index.contains_key(i));
360 }
361 }
362 }
363 }
364
365 pub proof fn align_down_leading_bits(self, level: int)
366 requires
367 1 <= level <= NR_LEVELS,
368 ensures
369 self.align_down(level).leading_bits == self.leading_bits,
370 decreases level,
371 {
372 if level > 1 {
373 self.align_down_leading_bits(level - 1);
374 }
375 }
376
377 pub proof fn align_down_shape(self, level: int)
378 requires
379 1 <= level <= NR_LEVELS,
380 self.inv(),
381 ensures
382 self.align_down(level).inv(),
383 self.align_down(level).offset == 0,
384 forall|i: int| 0 <= i < level - 1 ==> #[trigger] self.align_down(level).index[i] == 0,
385 forall|i: int|
386 level - 1 <= i < NR_LEVELS ==> #[trigger] self.align_down(level).index[i]
387 == self.index[i],
388 decreases level,
389 {
390 if level == 1 {
391 assert(self.align_down(1).index =~= self.index);
392 } else {
393 let tmp = self.align_down(level - 1);
394 self.align_down_shape(level - 1);
395 let new = self.align_down(level);
396 assert(new.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
397 assert forall|i: int| #![trigger new.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
398 &&& new.index.contains_key(i)
399 &&& 0 <= new.index[i]
400 &&& new.index[i] < NR_ENTRIES
401 } by {
402 if i != level - 2 {
403 assert(tmp.index.contains_key(i));
404 }
405 }
406 }
407 }
408
409 pub proof fn to_vaddr_indices_drop_zero_range(self, from: int, to: int)
410 requires
411 self.inv(),
412 0 <= from <= to <= NR_LEVELS,
413 forall|i: int| from <= i < to ==> self.index[i] == 0,
414 ensures
415 self.to_vaddr_indices(from) == self.to_vaddr_indices(to),
416 decreases to - from,
417 {
418 if from < to {
419 self.to_vaddr_indices_drop_zero_range(from + 1, to);
420 }
421 }
422
423 pub proof fn to_vaddr_indices_eq_if_indices_eq(self, other: Self, start: int)
424 requires
425 self.inv(),
426 other.inv(),
427 0 <= start <= NR_LEVELS,
428 forall|i: int| start <= i < NR_LEVELS ==> self.index[i] == other.index[i],
429 ensures
430 self.to_vaddr_indices(start) == other.to_vaddr_indices(start),
431 decreases NR_LEVELS - start,
432 {
433 if start < NR_LEVELS {
434 self.to_vaddr_indices_eq_if_indices_eq(other, start + 1);
435 }
436 }
437
438 pub proof fn align_down_to_vaddr_eq_if_upper_indices_eq(self, other: Self, level: int)
443 requires
444 1 <= level <= NR_LEVELS,
445 self.inv(),
446 other.inv(),
447 forall|i: int| level - 1 <= i < NR_LEVELS ==> self.index[i] == other.index[i],
449 self.leading_bits == other.leading_bits,
451 ensures
452 self.align_down(level).to_vaddr() == other.align_down(level).to_vaddr(),
453 decreases level,
454 {
455 let lhs = self.align_down(level);
456 let rhs = other.align_down(level);
457
458 self.align_down_shape(level);
459 other.align_down_shape(level);
460 self.align_down_leading_bits(level);
461 other.align_down_leading_bits(level);
462
463 lhs.to_vaddr_indices_drop_zero_range(0, level - 1);
464 rhs.to_vaddr_indices_drop_zero_range(0, level - 1);
465 lhs.to_vaddr_indices_eq_if_indices_eq(rhs, level - 1);
466 assert(lhs.leading_bits == rhs.leading_bits);
467 }
468
469 #[verifier::rlimit(400)]
474 pub proof fn align_down_to_vaddr_nat_align_down(self, level: int)
475 requires
476 self.inv(),
477 1 <= level <= NR_LEVELS,
478 ensures
479 self.align_down(level).to_vaddr() as nat == nat_align_down(
480 self.to_vaddr() as nat,
481 page_size(level as PagingLevel) as nat,
482 ),
483 {
484 let aligned = self.align_down(level);
485 vstd::arithmetic::power2::lemma2_to64();
486 vstd::arithmetic::power2::lemma2_to64_rest();
487 lemma_page_size_spec_values();
488 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
489
490 self.align_down_shape(level);
491 self.align_down_leading_bits(level);
492 self.to_vaddr_bounded();
493 aligned.to_vaddr_bounded();
494
495 aligned.to_vaddr_indices_drop_zero_range(0, level - 1);
497 aligned.to_vaddr_indices_eq_if_indices_eq(self, level - 1);
498
499 let o = self.offset;
501 let lb = self.leading_bits;
502 assert(self.index.contains_key(0));
503 assert(self.index.contains_key(1));
504 assert(self.index.contains_key(2));
505 assert(self.index.contains_key(3));
506 let i0 = self.index[0];
507 let i1 = self.index[1];
508 let i2 = self.index[2];
509 let i3 = self.index[3];
510 assert(0 <= o < 4096);
511 assert(0 <= lb < 0x1_0000);
512 assert(0 <= i0 < 512);
513 assert(0 <= i1 < 512);
514 assert(0 <= i2 < 512);
515 assert(0 <= i3 < 512);
516 assert(self.to_vaddr_indices(4) == 0);
517 assert(self.to_vaddr_indices(3) == i3 * 0x80_0000_0000int);
518 assert(self.to_vaddr_indices(2) == i2 * 0x4000_0000int + i3 * 0x80_0000_0000int);
519 assert(self.to_vaddr_indices(1) == i1 * 0x20_0000int + i2 * 0x4000_0000int + i3
520 * 0x80_0000_0000int);
521 assert(self.to_vaddr_indices(0) == i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int
522 + i3 * 0x80_0000_0000int);
523
524 let va = self.to_vaddr() as int;
525 let av = aligned.to_vaddr() as int;
526 let ps = page_size(level as PagingLevel) as int;
527
528 assert(va == o + self.to_vaddr_indices(0) + lb * 0x1_0000_0000_0000int);
530 assert(av == 0 + self.to_vaddr_indices(level - 1) + lb * 0x1_0000_0000_0000int);
531
532 let diff = va - av;
534 if level == 1 {
535 assert(ps == 0x1000);
536 assert(diff == o);
537 assert(av % ps == 0) by (nonlinear_arith)
538 requires
539 av == i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int + i3
540 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
541 ps == 0x1000,
542 ;
543 assert(0 <= diff < ps);
544 } else if level == 2 {
545 assert(ps == 0x20_0000);
546 assert(diff == o + i0 * 0x1000int);
547 assert(0 <= diff < ps) by (nonlinear_arith)
548 requires
549 diff == o + i0 * 0x1000int,
550 0 <= o < 4096,
551 0 <= i0 < 512,
552 ps == 0x20_0000,
553 ;
554 assert(av % ps == 0) by (nonlinear_arith)
555 requires
556 av == i1 * 0x20_0000int + i2 * 0x4000_0000int + i3 * 0x80_0000_0000int + lb
557 * 0x1_0000_0000_0000int,
558 ps == 0x20_0000,
559 ;
560 } else if level == 3 {
561 assert(ps == 0x4000_0000);
562 assert(diff == o + i0 * 0x1000int + i1 * 0x20_0000int);
563 assert(0 <= diff < ps) by (nonlinear_arith)
564 requires
565 diff == o + i0 * 0x1000int + i1 * 0x20_0000int,
566 0 <= o < 4096,
567 0 <= i0 < 512,
568 0 <= i1 < 512,
569 ps == 0x4000_0000,
570 ;
571 assert(av % ps == 0) by (nonlinear_arith)
572 requires
573 av == i2 * 0x4000_0000int + i3 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
574 ps == 0x4000_0000,
575 ;
576 } else {
577 assert(ps == 0x80_0000_0000);
578 assert(diff == o + i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int);
579 assert(0 <= diff < ps) by (nonlinear_arith)
580 requires
581 diff == o + i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int,
582 0 <= o < 4096,
583 0 <= i0 < 512,
584 0 <= i1 < 512,
585 0 <= i2 < 512,
586 ps == 0x80_0000_0000,
587 ;
588 assert(av % ps == 0) by (nonlinear_arith)
589 requires
590 av == i3 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
591 ps == 0x80_0000_0000,
592 ;
593 }
594
595 vstd_extra::arithmetic::lemma_nat_align_down_sound(va as nat, ps as nat);
597 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(va, ps);
598 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(av, ps);
599 let nad = nat_align_down(va as nat, ps as nat) as int;
603 assert(av as nat <= nad) by {
604 };
606 assert(nad <= va);
607 assert(nad - av < ps) by (nonlinear_arith)
608 requires
609 nad <= va,
610 va - av < ps,
611 av <= nad,
612 ;
613 vstd::arithmetic::div_mod::lemma_mod_sub_multiples_vanish(nad - av, ps);
616 assert((nad - av) % ps == (nad - av) % ps - ((av % ps) as int) + ((av % ps) as int));
617 }
618
619 pub proof fn align_down_concrete(self, level: int)
620 requires
621 self.inv(),
622 1 <= level <= NR_LEVELS,
623 ensures
624 self.align_down(level).reflect(
625 nat_align_down(
626 self.to_vaddr() as nat,
627 page_size(level as PagingLevel) as nat,
628 ) as Vaddr,
629 ),
630 {
631 let aligned = self.align_down(level);
632 self.align_down_shape(level);
633 self.align_down_to_vaddr_nat_align_down(level);
634 aligned.reflect_to_vaddr();
635 let nad = nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat);
638 self.to_vaddr_bounded();
639 assert(nad as Vaddr == aligned.to_vaddr());
640 }
641
642 pub proof fn same_node_indices_match(
648 va1: Vaddr,
649 va2: Vaddr,
650 node_start: Vaddr,
651 level: PagingLevel,
652 )
653 requires
654 1 <= level,
655 level < NR_LEVELS,
656 node_start <= va1,
657 va1 < node_start + page_size((level + 1) as PagingLevel),
658 node_start <= va2,
659 va2 < node_start + page_size((level + 1) as PagingLevel),
660 node_start as nat % page_size((level + 1) as PagingLevel) as nat == 0,
661 ensures
662 forall|i: int|
663 #![auto]
664 level as int <= i < NR_LEVELS ==> Self::from_vaddr(va1).index[i]
665 == Self::from_vaddr(va2).index[i],
666 {
667 vstd::arithmetic::power2::lemma2_to64();
668 vstd::arithmetic::power2::lemma2_to64_rest();
669 lemma_page_size_spec_values();
670 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
671
672 let ns = node_start;
673
674 if level == 1 {
679 assert((va1 / 0x20_0000usize) % 512 == (va2 / 0x20_0000usize) % 512) by (bit_vector)
680 requires
681 va1 >= ns,
682 va1 < ns + 0x20_0000usize,
683 va2 >= ns,
684 va2 < ns + 0x20_0000usize,
685 ns % 0x20_0000usize == 0usize,
686 ;
687 assert((va1 / 0x4000_0000usize) % 512 == (va2 / 0x4000_0000usize) % 512) by (bit_vector)
688 requires
689 va1 >= ns,
690 va1 < ns + 0x20_0000usize,
691 va2 >= ns,
692 va2 < ns + 0x20_0000usize,
693 ns % 0x20_0000usize == 0usize,
694 ;
695 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
696 by (bit_vector)
697 requires
698 va1 >= ns,
699 va1 < ns + 0x20_0000usize,
700 va2 >= ns,
701 va2 < ns + 0x20_0000usize,
702 ns % 0x20_0000usize == 0usize,
703 ;
704 } else if level == 2 {
705 assert((va1 / 0x4000_0000usize) % 512 == (va2 / 0x4000_0000usize) % 512) by (bit_vector)
706 requires
707 va1 >= ns,
708 va1 < ns + 0x4000_0000usize,
709 va2 >= ns,
710 va2 < ns + 0x4000_0000usize,
711 ns % 0x4000_0000usize == 0usize,
712 ;
713 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
714 by (bit_vector)
715 requires
716 va1 >= ns,
717 va1 < ns + 0x4000_0000usize,
718 va2 >= ns,
719 va2 < ns + 0x4000_0000usize,
720 ns % 0x4000_0000usize == 0usize,
721 ;
722 } else {
723 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
725 by (bit_vector)
726 requires
727 va1 >= ns,
728 va1 < ns + 0x80_0000_0000usize,
729 va2 >= ns,
730 va2 < ns + 0x80_0000_0000usize,
731 ns % 0x80_0000_0000usize == 0usize,
732 ;
733 }
734
735 assert forall|i: int| level as int <= i < NR_LEVELS implies Self::from_vaddr(va1).index[i]
738 == Self::from_vaddr(va2).index[i] by {
739 let abs1 = Self::from_vaddr(va1);
740 let abs2 = Self::from_vaddr(va2);
741 assert(abs1.index.contains_key(i));
742 assert(abs2.index.contains_key(i));
743 if i == 1 {
744 assert(pow2((12 + 9 * i) as nat) as usize == 0x20_0000);
745 } else if i == 2 {
746 assert(pow2((12 + 9 * i) as nat) as usize == 0x4000_0000);
747 } else {
748 assert(pow2((12 + 9 * i) as nat) as usize == 0x80_0000_0000);
749 }
750 }
751 }
752
753 pub open spec fn align_up(self, level: int) -> Self {
754 let lower_aligned = self.align_down(level);
755 lower_aligned.next_index(level)
756 }
757
758 pub proof fn align_up_concrete_sound(self, level: int)
762 requires
763 self.inv(),
764 1 <= level <= NR_LEVELS,
765 self.index[level - 1] + 1 < NR_ENTRIES,
766 ensures
767 self.align_up(level).reflect(
768 (nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
769 + page_size(level as PagingLevel) as nat) as Vaddr,
770 ),
771 {
772 let aligned = self.align_down(level);
773 self.align_down_shape(level);
774 self.align_down_to_vaddr_nat_align_down(level);
775 aligned.index_increment_adds_page_size(level);
776
777 let advanced = AbstractVaddr {
778 index: aligned.index.insert(level - 1, aligned.index[level - 1] + 1),
779 ..aligned
780 };
781 assert(aligned.next_index(level) == advanced);
782 assert(self.align_up(level) == advanced);
783
784 assert(advanced.inv()) by {
785 assert(advanced.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
786 assert forall|i: int|
787 #![trigger advanced.index.contains_key(i)]
788 0 <= i < NR_LEVELS implies {
789 &&& advanced.index.contains_key(i)
790 &&& 0 <= advanced.index[i]
791 &&& advanced.index[i] < NR_ENTRIES
792 } by {
793 assert(aligned.index.contains_key(i));
794 }
795 };
796 advanced.reflect_to_vaddr();
797 }
798
799 pub proof fn aligned_align_down_is_self(self, level: int)
805 requires
806 self.inv(),
807 1 <= level <= NR_LEVELS,
808 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat == 0,
809 ensures
810 self.align_down(level) == self,
811 {
812 let aligned = self.align_down(level);
813 let va = self.to_vaddr() as nat;
814 let ps = page_size(level as PagingLevel) as nat;
815
816 self.align_down_shape(level);
817 self.align_down_to_vaddr_nat_align_down(level);
818 lemma_page_size_ge_page_size(level as PagingLevel);
819 assert(ps > 0);
820 vstd_extra::arithmetic::lemma_nat_align_down_sound(va, ps);
821 self.to_vaddr_bounded();
822
823 assert(nat_align_down(va, ps) == va);
825 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self);
830 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(aligned);
831 }
834
835 pub proof fn aligned_align_up_advances(self, level: int)
843 requires
844 self.inv(),
845 1 <= level <= NR_LEVELS,
846 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat == 0,
847 self.to_vaddr() + page_size(level as PagingLevel) <= usize::MAX,
851 ensures
852 self.align_up(level).inv(),
853 self.align_up(level).to_vaddr() == self.to_vaddr() + page_size(level as PagingLevel),
854 decreases NR_LEVELS + 1 - level,
855 {
856 vstd::arithmetic::power2::lemma2_to64();
857 vstd::arithmetic::power2::lemma2_to64_rest();
858 lemma_page_size_spec_values();
859 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
860 lemma_page_size_ge_page_size(level as PagingLevel);
861
862 self.aligned_align_down_is_self(level);
863 if self.index[level - 1] + 1 < NR_ENTRIES {
866 self.index_increment_adds_page_size(level);
868 let advanced = AbstractVaddr {
871 index: self.index.insert(level - 1, self.index[level - 1] + 1),
872 ..self
873 };
874 assert(self.next_index(level) == advanced);
875 assert(self.align_up(level) == advanced);
876 assert(advanced.inv()) by {
877 assert(advanced.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
878 assert forall|i: int|
879 #![trigger advanced.index.contains_key(i)]
880 0 <= i < NR_LEVELS implies {
881 &&& advanced.index.contains_key(i)
882 &&& 0 <= advanced.index[i]
883 &&& advanced.index[i] < NR_ENTRIES
884 } by {
885 assert(self.index.contains_key(i));
886 }
887 };
888 } else {
889 assert(self.index.contains_key(level - 1));
891 assert(self.index[level - 1] < NR_ENTRIES); assert(self.index[level - 1] + 1 >= NR_ENTRIES); assert(self.index[level - 1] == NR_ENTRIES - 1);
894
895 if level < NR_LEVELS {
896 self.align_up_carry(level);
897 let prev_aligned = self.align_down((level + 1) as int);
900 self.align_down_shape(level + 1);
901 self.align_down_to_vaddr_nat_align_down(level + 1);
902 self.align_down_leading_bits(level + 1);
903 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
904 self.to_vaddr_bounded();
905 prev_aligned.to_vaddr_bounded();
906
907 let ps1 = page_size((level + 1) as PagingLevel) as nat;
909 assert(ps1 > 0);
910 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.to_vaddr() as nat, ps1);
911 assert(prev_aligned.to_vaddr() as nat % ps1 == 0);
912
913 let ps = page_size(level as PagingLevel) as int;
915 assert(ps1 as int == NR_ENTRIES * ps) by {
916 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
917 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
918 (level + 1) as PagingLevel);
919 };
920
921 assert forall|i: int| 0 <= i < level - 1 implies self.index[i] == 0 by {
925 assert(self.index.contains_key(i));
926 };
927 self.to_vaddr_indices_drop_zero_range(0, level - 1);
928 prev_aligned.to_vaddr_indices_drop_zero_range(0, level);
929 prev_aligned.to_vaddr_indices_eq_if_indices_eq(self, level);
930
931 assert(self.index.contains_key(level - 1));
932 if level == 1 {
933 assert(ps == 0x1000);
934 assert(pow2(12nat) as int == ps);
935 } else if level == 2 {
936 assert(ps == 0x20_0000);
937 assert(pow2(21nat) as int == ps);
938 } else if level == 3 {
939 assert(ps == 0x4000_0000);
940 assert(pow2(30nat) as int == ps);
941 }
942 assert(self.to_vaddr_indices(level - 1) == self.index[level - 1] * ps
943 + self.to_vaddr_indices(level));
944 assert(self.to_vaddr_indices(level - 1) == (NR_ENTRIES - 1) * ps
945 + self.to_vaddr_indices(level));
946
947 assert(prev_aligned.offset == 0);
949 assert(prev_aligned.leading_bits == self.leading_bits);
950 assert(self.offset == 0);
951
952 assert(prev_aligned.to_vaddr() as int + (NR_ENTRIES - 1) * ps
953 == self.to_vaddr() as int);
954
955 assert(prev_aligned.to_vaddr() as int + ps1 as int == self.to_vaddr() as int + ps)
957 by (nonlinear_arith)
958 requires
959 prev_aligned.to_vaddr() as int + (NR_ENTRIES - 1) * ps
960 == self.to_vaddr() as int,
961 ps1 as int == NR_ENTRIES * ps,
962 ;
963 assert(prev_aligned.to_vaddr() + page_size((level + 1) as PagingLevel)
964 <= usize::MAX);
965
966 prev_aligned.aligned_align_up_advances(level + 1);
967 prev_aligned.aligned_align_down_is_self(level + 1);
968
969 assert(self.align_up(level + 1) == prev_aligned.align_up(level + 1));
972
973 } else {
980 assert(level == NR_LEVELS);
983 self.align_down_shape(NR_LEVELS as int);
991 self.to_vaddr_bounded();
992 assert forall|i: int| 0 <= i < NR_LEVELS - 1 implies self.index[i] == 0 by {
993 assert(self.index.contains_key(i));
994 assert(self.align_down(NR_LEVELS as int).index[i] == 0);
995 };
996 self.to_vaddr_indices_drop_zero_range(0, NR_LEVELS - 1);
997 assert(self.index.contains_key(NR_LEVELS - 1));
998 let ps_top = page_size(NR_LEVELS as PagingLevel) as int;
999 assert(ps_top == 0x80_0000_0000);
1000 assert(self.to_vaddr_indices(NR_LEVELS as int) == 0);
1001 assert(self.to_vaddr_indices(NR_LEVELS - 1) == self.index[NR_LEVELS - 1] * ps_top);
1002 assert(self.to_vaddr_indices(0) == (NR_ENTRIES - 1) * ps_top);
1003 assert(self.offset == 0);
1004 assert(self.to_vaddr() as int == (NR_ENTRIES - 1) * ps_top + self.leading_bits
1005 * 0x1_0000_0000_0000int);
1006 assert(NR_ENTRIES * ps_top == 0x1_0000_0000_0000int) by (compute);
1007 assert(self.leading_bits + 1 < 0x1_0000) by (nonlinear_arith)
1009 requires
1010 self.to_vaddr() as int == (NR_ENTRIES - 1) * ps_top + self.leading_bits
1011 * 0x1_0000_0000_0000int,
1012 self.to_vaddr() + ps_top <= usize::MAX,
1013 ps_top == 0x80_0000_0000,
1014 NR_ENTRIES * ps_top == 0x1_0000_0000_0000int,
1015 0 <= self.leading_bits < 0x1_0000,
1016 usize::MAX == 0xffff_ffff_ffff_ffffusize,
1017 ;
1018
1019 let advanced_top = AbstractVaddr {
1025 index: self.index.insert(NR_LEVELS - 1, 0),
1026 leading_bits: self.leading_bits + 1,
1027 ..self
1028 };
1029 assert(self.next_index(NR_LEVELS as int) == advanced_top);
1030 assert(self.align_up(NR_LEVELS as int) == advanced_top);
1031
1032 assert(advanced_top.inv()) by {
1033 assert(advanced_top.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
1034 assert forall|i: int|
1035 #![trigger advanced_top.index.contains_key(i)]
1036 0 <= i < NR_LEVELS implies {
1037 &&& advanced_top.index.contains_key(i)
1038 &&& 0 <= advanced_top.index[i]
1039 &&& advanced_top.index[i] < NR_ENTRIES
1040 } by {
1041 assert(self.index.contains_key(i));
1042 }
1043 };
1044
1045 self.to_vaddr_bounded();
1055 advanced_top.to_vaddr_bounded();
1056 let ps = page_size(NR_LEVELS as PagingLevel) as int;
1057 assert(pow2((12 + 9 * NR_LEVELS) as nat) as int == 0x1_0000_0000_0000int)
1058 by (compute);
1059 assert(ps == 0x80_0000_0000);
1061
1062 self.align_down_shape(NR_LEVELS as int);
1065 assert forall|i: int| 0 <= i < NR_LEVELS - 1 implies self.index[i] == 0 by {
1066 assert(self.index.contains_key(i));
1067 assert(self.align_down(NR_LEVELS as int).index[i] == 0);
1068 };
1069 self.to_vaddr_indices_drop_zero_range(0, NR_LEVELS - 1);
1070 assert(self.index.contains_key(NR_LEVELS - 1));
1071 assert(self.to_vaddr_indices(NR_LEVELS - 1) == self.index[NR_LEVELS - 1] * ps
1072 + self.to_vaddr_indices(NR_LEVELS as int));
1073 assert(self.to_vaddr_indices(NR_LEVELS as int) == 0);
1074 assert(self.to_vaddr_indices(0) == (NR_ENTRIES - 1) * ps);
1075
1076 assert(advanced_top.offset == 0);
1078 assert forall|i: int| 0 <= i < NR_LEVELS implies advanced_top.index[i] == 0 by {
1079 assert(self.index.contains_key(i));
1080 };
1081 advanced_top.to_vaddr_indices_drop_zero_range(0, NR_LEVELS as int);
1082 assert(advanced_top.to_vaddr_indices(0) == 0);
1083
1084 assert(advanced_top.leading_bits == self.leading_bits + 1);
1089 assert(advanced_top.to_vaddr() as int == (self.leading_bits + 1)
1090 * 0x1_0000_0000_0000int);
1091 assert(self.to_vaddr() as int == (NR_ENTRIES - 1) * ps + self.leading_bits
1092 * 0x1_0000_0000_0000int);
1093 assert(NR_ENTRIES * ps == 0x1_0000_0000_0000int) by (compute);
1094 assert(advanced_top.to_vaddr() as int == self.to_vaddr() as int + ps)
1095 by (nonlinear_arith)
1096 requires
1097 advanced_top.to_vaddr() as int == (self.leading_bits + 1)
1098 * 0x1_0000_0000_0000int,
1099 self.to_vaddr() as int == (NR_ENTRIES - 1) * ps + self.leading_bits
1100 * 0x1_0000_0000_0000int,
1101 NR_ENTRIES * ps == 0x1_0000_0000_0000int,
1102 ;
1103 }
1104 }
1105 }
1106
1107 pub proof fn align_up_advances_general(self, level: int)
1114 requires
1115 self.inv(),
1116 1 <= level <= NR_LEVELS,
1117 nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1121 + page_size(level as PagingLevel) as nat <= usize::MAX as nat,
1122 ensures
1123 self.align_up(level).inv(),
1124 self.align_up(level).to_vaddr() as nat == nat_align_down(
1125 self.to_vaddr() as nat,
1126 page_size(level as PagingLevel) as nat,
1127 ) + page_size(level as PagingLevel) as nat,
1128 {
1129 let aligned = self.align_down(level);
1130 let ps = page_size(level as PagingLevel) as nat;
1131
1132 self.align_down_shape(level);
1133 self.align_down_to_vaddr_nat_align_down(level);
1134 lemma_page_size_ge_page_size(level as PagingLevel);
1135 self.to_vaddr_bounded();
1136 aligned.to_vaddr_bounded();
1137 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.to_vaddr() as nat, ps);
1138
1139 assert(aligned.to_vaddr() as nat % ps == 0);
1142
1143 assert(aligned.to_vaddr() + page_size(level as PagingLevel) <= usize::MAX);
1145
1146 aligned.aligned_align_up_advances(level);
1148
1149 aligned.aligned_align_down_is_self(level);
1155 assert(self.align_up(level) == aligned.align_up(level));
1156 }
1157
1158 pub proof fn align_diff_sound(self, level: int)
1160 requires
1161 1 <= level <= NR_LEVELS,
1162 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat != 0,
1163 ensures
1164 nat_align_up(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1165 == nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1166 + page_size(level as PagingLevel),
1167 {
1168 }
1170
1171 pub proof fn align_up_carry(self, level: int)
1174 requires
1175 self.inv(),
1176 1 <= level,
1177 level < NR_LEVELS,
1178 self.index[level - 1] == NR_ENTRIES - 1,
1179 ensures
1180 self.align_up(level) == self.align_up(level + 1),
1181 decreases NR_LEVELS - level,
1182 {
1183 self.align_down_shape(level);
1184 self.align_down_shape(level + 1);
1185 assert(self.align_down(level).index.insert(level - 1, 0) =~= self.align_down(
1186 level + 1,
1187 ).index);
1188 }
1189
1190 pub open spec fn next_index(self, level: int) -> Self
1191 decreases NR_LEVELS - level,
1192 when 1 <= level <= NR_LEVELS
1193 {
1194 let index = self.index[level - 1];
1195 let next_index = index + 1;
1196 if next_index == NR_ENTRIES && level < NR_LEVELS {
1197 let next_va = Self { index: self.index.insert(level - 1, 0), ..self };
1198 next_va.next_index(level + 1)
1199 } else if next_index == NR_ENTRIES && level == NR_LEVELS {
1200 Self {
1202 index: self.index.insert(level - 1, 0),
1203 leading_bits: self.leading_bits + 1,
1204 ..self
1205 }
1206 } else {
1207 Self { index: self.index.insert(level - 1, next_index), ..self }
1208 }
1209 }
1210
1211 pub open spec fn wrapped(self, start_level: int, level: int) -> bool
1212 decreases NR_LEVELS - level,
1213 when 1 <= start_level <= level <= NR_LEVELS
1214 {
1215 &&& self.next_index(start_level).index[level - 1] == 0 ==> {
1216 &&& self.index[level - 1] + 1 == NR_ENTRIES
1217 &&& if level < NR_LEVELS {
1218 self.wrapped(start_level, level + 1)
1219 } else {
1220 true
1221 }
1222 }
1223 &&& self.next_index(start_level).index[level - 1] != 0 ==> self.index[level - 1] + 1
1224 < NR_ENTRIES
1225 }
1226
1227 pub proof fn use_wrapped(self, start_level: int, level: int)
1228 requires
1229 1 <= start_level <= level < NR_LEVELS,
1230 self.wrapped(start_level, level),
1231 self.next_index(start_level).index[level - 1] == 0,
1232 ensures
1233 self.index[level - 1] + 1 == NR_ENTRIES,
1234 {
1235 }
1236
1237 pub proof fn wrapped_unwrap(self, start_level: int, level: int)
1238 requires
1239 1 <= start_level <= level < NR_LEVELS,
1240 self.wrapped(start_level, level),
1241 self.next_index(start_level).index[level - 1] == 0,
1242 ensures
1243 self.wrapped(start_level, level + 1),
1244 {
1245 }
1246
1247 pub proof fn wrapped_after_carry_equiv(self, start_level: int, level: int)
1248 requires
1249 self.inv(),
1250 1 <= start_level < level <= NR_LEVELS,
1251 self.index[start_level - 1] + 1 == NR_ENTRIES,
1252 ensures
1253 ({
1254 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1255 self.wrapped(start_level, level) == next_va.wrapped(start_level + 1, level)
1256 }),
1257 decreases NR_LEVELS - level,
1258 {
1259 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1260 assert forall|i: int| start_level <= i < NR_LEVELS implies next_va.index[i]
1261 == self.index[i] by {};
1262 if level < NR_LEVELS {
1263 self.wrapped_after_carry_equiv(start_level, level + 1);
1264 }
1265 }
1266
1267 pub proof fn wrapped_index_nonzero(self, start_level: int, level: int)
1269 requires
1270 1 <= start_level <= level <= NR_LEVELS,
1271 self.wrapped(start_level, level),
1272 self.index[level - 1] + 1 < NR_ENTRIES,
1273 ensures
1274 self.next_index(start_level).index[level - 1] != 0,
1275 {
1276 if self.next_index(start_level).index[level - 1] == 0 {
1277 if level < NR_LEVELS {
1278 self.use_wrapped(start_level, level);
1279 }
1280 }
1281 }
1282
1283 pub proof fn wrapped_nonzero_at_level(
1285 abs_va_down: Self,
1286 abs_next_va: Self,
1287 start_level: int,
1288 level: int,
1289 owner_index_at_level: int,
1290 )
1291 requires
1292 1 <= start_level <= level <= NR_LEVELS,
1293 abs_va_down.wrapped(start_level, level),
1294 abs_va_down.next_index(start_level) == abs_next_va,
1295 abs_va_down.index[level - 1] == owner_index_at_level,
1296 owner_index_at_level == 0,
1297 ensures
1298 abs_next_va.index[level - 1] != 0,
1299 {
1300 abs_va_down.wrapped_index_nonzero(start_level, level);
1301 }
1302
1303 pub proof fn wrapped_nonzero_at_level_general(
1307 abs_va_down: Self,
1308 abs_next_va: Self,
1309 start_level: int,
1310 level: int,
1311 owner_index_at_level: int,
1312 )
1313 requires
1314 1 <= start_level <= level <= NR_LEVELS,
1315 abs_va_down.wrapped(start_level, level),
1316 abs_va_down.next_index(start_level) == abs_next_va,
1317 abs_va_down.index[level - 1] == owner_index_at_level,
1318 owner_index_at_level + 1 < NR_ENTRIES,
1319 ensures
1320 abs_next_va.index[level - 1] != 0,
1321 {
1322 abs_va_down.wrapped_index_nonzero(start_level, level);
1323 }
1324
1325 #[verifier::spinoff_prover]
1326 pub proof fn next_index_preserves_lower_indices(self, start_level: int, lower_level: int)
1327 requires
1328 self.inv(),
1329 1 <= lower_level < start_level <= NR_LEVELS,
1330 ensures
1331 self.next_index(start_level).index[lower_level - 1] == self.index[lower_level - 1],
1332 decreases NR_LEVELS - start_level,
1333 {
1334 let index = self.index[start_level - 1];
1335 let next_index = index + 1;
1336 if next_index == NR_ENTRIES && start_level < NR_LEVELS {
1337 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1338 assert(next_va.inv()) by {
1339 assert(next_va.index.dom() =~= Set::new(|i: int| 0 <= i < NR_LEVELS));
1340 assert forall|i: int|
1341 #![trigger next_va.index.contains_key(i)]
1342 0 <= i < NR_LEVELS implies {
1343 &&& next_va.index.contains_key(i)
1344 &&& 0 <= next_va.index[i]
1345 &&& next_va.index[i] < NR_ENTRIES
1346 } by {
1347 assert(self.index.contains_key(i));
1348 }
1349 };
1350 next_va.next_index_preserves_lower_indices(start_level + 1, lower_level);
1351 } else if next_index == NR_ENTRIES && start_level == NR_LEVELS {
1352 }
1353 }
1354
1355 pub proof fn next_index_wrap_condition(self, level: int)
1356 requires
1357 self.inv(),
1358 1 <= level <= NR_LEVELS,
1359 ensures
1360 self.wrapped(level, level),
1361 decreases NR_LEVELS - level,
1362 {
1363 let index = self.index[level - 1];
1364 let next_index = index + 1;
1365 if next_index == NR_ENTRIES {
1366 if level < NR_LEVELS {
1367 let next_va = Self { index: self.index.insert(level - 1, 0), ..self };
1368 next_va.next_index_wrap_condition(level + 1);
1369 self.wrapped_after_carry_equiv(level, level + 1);
1370 next_va.next_index_preserves_lower_indices(level + 1, level);
1371 }
1372 } else {
1373 assert(self.index.contains_key(level - 1));
1374 }
1375 }
1376
1377 pub open spec fn compute_vaddr(self) -> Vaddr {
1390 self.rec_compute_vaddr(0)
1391 }
1392
1393 pub open spec fn rec_compute_vaddr(self, i: int) -> Vaddr
1395 decreases NR_LEVELS - i,
1396 when 0 <= i <= NR_LEVELS
1397 {
1398 if i >= NR_LEVELS {
1399 self.offset as Vaddr
1400 } else {
1401 let shift = page_size((i + 1) as PagingLevel);
1402 (self.index[i] * shift + self.rec_compute_vaddr(i + 1)) as Vaddr
1403 }
1404 }
1405
1406 pub open spec fn to_path(self, level: int) -> TreePath<NR_ENTRIES>
1416 recommends
1417 0 <= level < NR_LEVELS,
1418 {
1419 TreePath(self.rec_to_path(NR_LEVELS - 1, level))
1420 }
1421
1422 pub open spec fn rec_to_path(self, abstract_level: int, bottom_level: int) -> Seq<usize>
1426 decreases abstract_level - bottom_level,
1427 when bottom_level <= abstract_level
1428 {
1429 if abstract_level < bottom_level {
1430 seq![]
1431 } else if abstract_level == bottom_level {
1432 seq![self.index[abstract_level] as usize]
1434 } else {
1435 seq![self.index[abstract_level] as usize].add(
1437 self.rec_to_path(abstract_level - 1, bottom_level),
1438 )
1439 }
1440 }
1441
1442 #[verifier::rlimit(400)]
1448 pub proof fn to_path_vaddr(self, level: int)
1449 requires
1450 self.inv(),
1451 0 <= level < NR_LEVELS,
1452 ensures
1453 vaddr(self.to_path(level)) == self.align_down(level + 1).compute_vaddr(),
1454 {
1455 self.to_path_inv(level);
1456 self.to_path_len(level);
1457 lemma_page_size_spec_level1();
1458 vstd::arithmetic::power2::lemma2_to64();
1459 vstd::arithmetic::power2::lemma2_to64_rest();
1460 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
1461 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1462 let path = self.to_path(level);
1463 if level == 3 {
1464 let aligned = self.align_down(4);
1465 self.align_down_shape(4);
1466 self.to_path_index(3, 0);
1467 path.index_satisfies_elem_inv(0);
1468 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize) by {
1469 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, path.index(0)) + rec_vaddr(
1470 path,
1471 1,
1472 )) as usize);
1473 };
1474 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1475 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1476 + aligned.rec_compute_vaddr(4)) as Vaddr);
1477 };
1478 assert(aligned.rec_compute_vaddr(1) == self.index[3] * 0x80_0000_0000usize) by {
1479 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1480 + aligned.rec_compute_vaddr(2)) as Vaddr);
1481 };
1482 assert(aligned.compute_vaddr() == aligned.compute_vaddr());
1483 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1484 + aligned.rec_compute_vaddr(1)) as Vaddr);
1485 assert(vaddr(path) == aligned.compute_vaddr());
1486 } else if level == 2 {
1487 let aligned = self.align_down(3);
1488 self.align_down_shape(3);
1489 self.to_path_index(2, 0);
1490 self.to_path_index(2, 1);
1491 path.index_satisfies_elem_inv(0);
1492 path.index_satisfies_elem_inv(1);
1493 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize + path.index(1)
1494 * 0x4000_0000usize) by {
1495 assert(vaddr(path) == rec_vaddr(path, 0));
1496 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path.index(1)) + rec_vaddr(
1497 path,
1498 2,
1499 )) as usize);
1500 };
1501 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1502 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1503 + aligned.rec_compute_vaddr(4)) as Vaddr);
1504 };
1505 assert(aligned.rec_compute_vaddr(1) == self.index[2] * 0x4000_0000usize + self.index[3]
1506 * 0x80_0000_0000usize) by {
1507 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1508 + aligned.rec_compute_vaddr(2)) as Vaddr);
1509 };
1510 assert(vaddr(path) == aligned.compute_vaddr());
1511 } else if level == 1 {
1512 let aligned = self.align_down(2);
1513 self.align_down_shape(2);
1514 self.to_path_index(1, 0);
1515 self.to_path_index(1, 1);
1516 self.to_path_index(1, 2);
1517 path.index_satisfies_elem_inv(0);
1518 path.index_satisfies_elem_inv(1);
1519 path.index_satisfies_elem_inv(2);
1520 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize + path.index(1)
1521 * 0x4000_0000usize + path.index(2) * 0x20_0000usize) by {
1522 assert(vaddr(path) == rec_vaddr(path, 0));
1523 assert(rec_vaddr(path, 3) == 0);
1524 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, path.index(2)) + rec_vaddr(
1525 path,
1526 3,
1527 )) as usize);
1528 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path.index(1)) + rec_vaddr(
1529 path,
1530 2,
1531 )) as usize);
1532 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, path.index(0)) + rec_vaddr(
1533 path,
1534 1,
1535 )) as usize);
1536 assert(vaddr_make::<NR_LEVELS>(0, path.index(0)) == 0x80_0000_0000usize
1537 * path.index(0)) by (compute);
1538 assert(vaddr_make::<NR_LEVELS>(1, path.index(1)) == 0x4000_0000usize * path.index(
1539 1,
1540 )) by (compute);
1541 assert(vaddr_make::<NR_LEVELS>(2, path.index(2)) == 0x20_0000usize * path.index(2))
1542 by (compute);
1543 };
1544 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1545 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1546 + aligned.rec_compute_vaddr(4)) as Vaddr);
1547 };
1548 assert(aligned.rec_compute_vaddr(1) == self.index[1] * 0x20_0000usize + self.index[2]
1549 * 0x4000_0000usize + self.index[3] * 0x80_0000_0000usize) by {
1550 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1551 + aligned.rec_compute_vaddr(2)) as Vaddr);
1552 };
1553 assert(aligned.compute_vaddr() == aligned.compute_vaddr());
1554 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1555 + aligned.rec_compute_vaddr(1)) as Vaddr);
1556 assert(vaddr(path) == aligned.compute_vaddr());
1557 } else {
1558 let aligned = self.align_down(1);
1559 self.align_down_shape(1);
1560 self.to_path_index(0, 0);
1561 self.to_path_index(0, 1);
1562 self.to_path_index(0, 2);
1563 self.to_path_index(0, 3);
1564 path.index_satisfies_elem_inv(0);
1565 path.index_satisfies_elem_inv(1);
1566 path.index_satisfies_elem_inv(2);
1567 path.index_satisfies_elem_inv(3);
1568 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize + path.index(1)
1569 * 0x4000_0000usize + path.index(2) * 0x20_0000usize + path.index(3) * 0x1000usize)
1570 by {
1571 assert(vaddr(path) == rec_vaddr(path, 0));
1572 assert(rec_vaddr(path, 4) == 0);
1573 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, path.index(2)) + rec_vaddr(
1574 path,
1575 3,
1576 )) as usize);
1577 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path.index(1)) + rec_vaddr(
1578 path,
1579 2,
1580 )) as usize);
1581 assert(vaddr_make::<NR_LEVELS>(0, path.index(0)) == 0x80_0000_0000usize
1582 * path.index(0)) by (compute);
1583 assert(vaddr_make::<NR_LEVELS>(1, path.index(1)) == 0x4000_0000usize * path.index(
1584 1,
1585 )) by (compute);
1586 assert(vaddr_make::<NR_LEVELS>(2, path.index(2)) == 0x20_0000usize * path.index(2))
1587 by (compute);
1588 assert(vaddr_make::<NR_LEVELS>(3, path.index(3)) == 0x1000usize * path.index(3))
1589 by (compute);
1590 };
1591 assert(aligned.rec_compute_vaddr(4) == 0);
1592 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1593 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1594 + aligned.rec_compute_vaddr(4)) as Vaddr);
1595 };
1596 assert(aligned.rec_compute_vaddr(2) == self.index[2] * 0x4000_0000usize + self.index[3]
1597 * 0x80_0000_0000usize) by {};
1598 assert(aligned.compute_vaddr() == self.index[0] * 0x1000usize + self.index[1]
1599 * 0x20_0000usize + self.index[2] * 0x4000_0000usize + self.index[3]
1600 * 0x80_0000_0000usize) by {
1601 assert(aligned.compute_vaddr() == aligned.compute_vaddr());
1602 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1603 + aligned.rec_compute_vaddr(1)) as Vaddr);
1604 };
1605 assert(vaddr(path) == aligned.compute_vaddr());
1606 }
1607 }
1608
1609 pub proof fn rec_compute_vaddr_is_to_vaddr_indices(self, start: int)
1613 requires
1614 self.inv(),
1615 0 <= start <= NR_LEVELS,
1616 ensures
1617 self.rec_compute_vaddr(start) as int == self.to_vaddr_indices(start) + self.offset,
1618 decreases NR_LEVELS - start,
1619 {
1620 vstd::arithmetic::power2::lemma2_to64();
1621 vstd::arithmetic::power2::lemma2_to64_rest();
1622 lemma_page_size_spec_values();
1623 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1624 self.to_vaddr_indices_gap_bound(start);
1625 if start < NR_LEVELS {
1626 self.rec_compute_vaddr_is_to_vaddr_indices(start + 1);
1627 self.to_vaddr_indices_gap_bound(start + 1);
1628 assert(self.index.contains_key(start));
1629 if start == 0 {
1633 assert(page_size_spec(1) == pow2(12nat) as usize);
1634 } else if start == 1 {
1635 assert(page_size_spec(2) == pow2(21nat) as usize);
1636 } else if start == 2 {
1637 assert(page_size_spec(3) == pow2(30nat) as usize);
1638 } else {
1639 assert(page_size_spec(4) == pow2(39nat) as usize);
1640 }
1641 }
1642 }
1643
1644 pub proof fn to_vaddr_is_compute_vaddr(self)
1651 requires
1652 self.inv(),
1653 ensures
1654 self.to_vaddr() as int == self.compute_vaddr() as int + self.leading_bits
1655 * 0x1_0000_0000_0000int,
1656 {
1657 self.to_vaddr_bounded();
1658 self.rec_compute_vaddr_is_to_vaddr_indices(0);
1659 }
1660
1661 pub proof fn to_vaddr_indices_gap_bound(self, start: int)
1662 requires
1663 self.inv(),
1664 0 <= start <= NR_LEVELS,
1665 ensures
1666 0 <= self.to_vaddr_indices(start),
1667 self.to_vaddr_indices(start) + pow2((12 + 9 * start) as nat) as int <= pow2(
1668 (12 + 9 * NR_LEVELS) as nat,
1669 ) as int,
1670 decreases NR_LEVELS - start,
1671 {
1672 vstd::arithmetic::power2::lemma2_to64();
1673 vstd::arithmetic::power2::lemma2_to64_rest();
1674 vstd::arithmetic::power2::lemma_pow2_pos((12 + 9 * start) as nat);
1675 if start == NR_LEVELS {
1676 } else {
1677 let shift = pow2((12 + 9 * start) as nat) as int;
1678 let next_shift = pow2((12 + 9 * (start + 1)) as nat) as int;
1679 let top = pow2((12 + 9 * NR_LEVELS) as nat) as int;
1680 self.to_vaddr_indices_gap_bound(start + 1);
1681 assert(self.index.contains_key(start));
1682 vstd::arithmetic::power2::lemma_pow2_adds((12 + 9 * start) as nat, 9nat);
1683 vstd::arithmetic::mul::lemma_mul_inequality(self.index[start] + 1, 0x200int, shift);
1684 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1685 shift,
1686 self.index[start],
1687 1,
1688 );
1689 }
1690 }
1691
1692 pub proof fn to_vaddr_bounded(self)
1693 requires
1694 self.inv(),
1695 ensures
1696 0 <= self.offset + self.to_vaddr_indices(0) < 0x1_0000_0000_0000int,
1697 self.to_vaddr() as int == self.offset + self.to_vaddr_indices(0) + self.leading_bits
1698 * 0x1_0000_0000_0000int,
1699 self.offset + self.to_vaddr_indices(0) + self.leading_bits * 0x1_0000_0000_0000int
1700 < 0x1_0000_0000_0000_0000int,
1701 {
1702 vstd::arithmetic::power2::lemma2_to64();
1703 vstd::arithmetic::power2::lemma2_to64_rest();
1704 self.to_vaddr_indices_gap_bound(0);
1705 assert(pow2((12 + 9 * NR_LEVELS) as nat) as int == 0x1_0000_0000_0000int) by (compute);
1706 assert(self.leading_bits * 0x1_0000_0000_0000int + 0x1_0000_0000_0000int <= 0x1_0000
1707 * 0x1_0000_0000_0000int) by (nonlinear_arith)
1708 requires
1709 0 <= self.leading_bits < 0x1_0000int,
1710 ;
1711 assert(0x1_0000 * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int) by (compute);
1712 }
1713
1714 #[verifier::spinoff_prover]
1715 pub proof fn index_increment_adds_page_size(self, level: int)
1716 requires
1717 self.inv(),
1718 1 <= level <= NR_LEVELS,
1719 self.index[level - 1] + 1 < NR_ENTRIES,
1720 ensures
1721 (Self {
1722 index: self.index.insert(level - 1, self.index[level - 1] + 1),
1723 ..self
1724 }).to_vaddr() == self.to_vaddr() + page_size(level as PagingLevel),
1725 {
1726 let new_va = Self {
1727 index: self.index.insert(level - 1, self.index[level - 1] + 1),
1728 ..self
1729 };
1730 assert forall|i: int| #![trigger new_va.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
1731 &&& new_va.index.contains_key(i)
1732 &&& 0 <= new_va.index[i]
1733 &&& new_va.index[i] < NR_ENTRIES
1734 } by {
1735 assert(self.index.contains_key(i));
1736 };
1737 assert(new_va.inv());
1738 self.to_vaddr_bounded();
1739 new_va.to_vaddr_bounded();
1740 assert(new_va.to_vaddr() as int - self.to_vaddr() as int == new_va.to_vaddr_indices(0)
1741 - self.to_vaddr_indices(0));
1742 vstd::arithmetic::power2::lemma2_to64();
1743 vstd::arithmetic::power2::lemma2_to64_rest();
1744 if level == 1 {
1745 lemma_page_size_spec_level1();
1746 assert forall|i: int| 1 <= i < NR_LEVELS implies new_va.index[i] == self.index[i] by {};
1747 new_va.to_vaddr_indices_eq_if_indices_eq(self, 1);
1748 assert((self.index[0] + 1) * 0x1000 == self.index[0] * 0x1000 + 0x1000)
1749 by (nonlinear_arith);
1750 } else if level == 2 {
1751 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1752 assert forall|i: int| 2 <= i < NR_LEVELS implies new_va.index[i] == self.index[i] by {};
1753 new_va.to_vaddr_indices_eq_if_indices_eq(self, 2);
1754 assert(self.to_vaddr_indices(0) == self.index[0] * pow2(12nat) as int
1755 + self.to_vaddr_indices(1));
1756 assert((self.index[1] + 1) * 0x20_0000 == self.index[1] * 0x20_0000 + 0x20_0000)
1757 by (nonlinear_arith);
1758 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x20_0000);
1759 } else if level == 3 {
1760 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1761 assert forall|i: int| 3 <= i < NR_LEVELS implies new_va.index[i] == self.index[i] by {};
1762 new_va.to_vaddr_indices_eq_if_indices_eq(self, 3);
1763 assert(self.index.contains_key(2));
1764 assert(new_va.index.contains_key(2));
1765 assert((12 + 9 * 2) as nat == 30nat) by (compute);
1766 assert((self.index[2] + 1) * 0x4000_0000 == self.index[2] * 0x4000_0000 + 0x4000_0000)
1767 by (nonlinear_arith);
1768 assert(new_va.to_vaddr_indices(2) == self.to_vaddr_indices(2) + 0x4000_0000);
1769 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x4000_0000);
1770 } else {
1771 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1772 assert forall|i: int| 4 <= i < NR_LEVELS implies new_va.index[i] == self.index[i] by {};
1773 new_va.to_vaddr_indices_eq_if_indices_eq(self, 4);
1774 assert(self.to_vaddr_indices(1) == self.index[1] * pow2(21nat) as int
1775 + self.to_vaddr_indices(2));
1776 assert(self.to_vaddr_indices(2) == self.index[2] * pow2(30nat) as int
1777 + self.to_vaddr_indices(3));
1778 assert((self.index[3] + 1) * 0x80_0000_0000 == self.index[3] * 0x80_0000_0000
1779 + 0x80_0000_0000) by (nonlinear_arith);
1780 assert(new_va.to_vaddr_indices(3) == self.to_vaddr_indices(3) + 0x80_0000_0000);
1781 assert(new_va.to_vaddr_indices(2) == self.to_vaddr_indices(2) + 0x80_0000_0000);
1782 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x80_0000_0000);
1783 }
1784 }
1785
1786 pub proof fn to_path_len(self, level: int)
1788 requires
1789 0 <= level < NR_LEVELS,
1790 ensures
1791 self.to_path(level).len() == NR_LEVELS - level,
1792 {
1793 self.rec_to_path_len(NR_LEVELS - 1, level);
1794 }
1795
1796 proof fn rec_to_path_len(self, abstract_level: int, bottom_level: int)
1797 requires
1798 bottom_level <= abstract_level,
1799 ensures
1800 self.rec_to_path(abstract_level, bottom_level).len() == abstract_level - bottom_level
1801 + 1,
1802 decreases abstract_level - bottom_level,
1803 {
1804 if abstract_level > bottom_level {
1809 self.rec_to_path_len(abstract_level - 1, bottom_level);
1810 }
1811 }
1814
1815 pub proof fn to_path_inv(self, level: int)
1817 requires
1818 self.inv(),
1819 0 <= level < NR_LEVELS,
1820 ensures
1821 self.to_path(level).inv(),
1822 {
1823 self.to_path_len(level);
1824 assert forall|i: int| 0 <= i < self.to_path(level).len() implies TreePath::<
1825 NR_ENTRIES,
1826 >::elem_inv(#[trigger] self.to_path(level).index(i)) by {
1827 let j = NR_LEVELS - 1 - i;
1828 self.to_path_index(level, i);
1829 assert(self.index.contains_key(j));
1830 };
1831 }
1832}
1833
1834impl AbstractVaddr {
1836 proof fn rec_vaddr_eq_if_indices_eq(
1837 path1: TreePath<NR_ENTRIES>,
1838 path2: TreePath<NR_ENTRIES>,
1839 idx: int,
1840 )
1841 requires
1842 path1.inv(),
1843 path2.inv(),
1844 path1.len() == path2.len(),
1845 0 <= idx <= path1.len(),
1846 forall|i: int| idx <= i < path1.len() ==> path1.index(i) == path2.index(i),
1847 ensures
1848 rec_vaddr(path1, idx) == rec_vaddr(path2, idx),
1849 decreases path1.len() - idx,
1850 {
1851 if idx < path1.len() {
1852 path1.index_satisfies_elem_inv(idx);
1853 path2.index_satisfies_elem_inv(idx);
1854 Self::rec_vaddr_eq_if_indices_eq(path1, path2, idx + 1);
1855 }
1856 }
1857
1858 pub proof fn path_matches_vaddr(self, path: TreePath<NR_ENTRIES>)
1861 requires
1862 self.inv(),
1863 path.inv(),
1864 path.len() <= NR_LEVELS,
1865 forall|i: int| 0 <= i < path.len() ==> path.index(i) == self.index[NR_LEVELS - 1 - i],
1866 ensures
1867 vaddr(path) == self.align_down((NR_LEVELS - path.len() + 1) as int).compute_vaddr()
1868 - self.align_down((NR_LEVELS - path.len() + 1) as int).offset,
1869 {
1870 if path.len() == 0 {
1871 let aligned = self.align_down(5);
1872 self.align_down_shape(4);
1873 assert(aligned.index[3] == 0) by {
1875 assert(aligned == AbstractVaddr {
1876 index: self.align_down(4).index.insert(3, 0),
1877 ..self.align_down(4)
1878 });
1879 };
1880 assert(aligned.rec_compute_vaddr(4) == 0);
1881 assert(aligned.rec_compute_vaddr(3) == 0) by {
1882 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1883 + aligned.rec_compute_vaddr(4)) as Vaddr);
1884 };
1885 assert(aligned.rec_compute_vaddr(2) == 0) by {
1886 assert(aligned.rec_compute_vaddr(2) == (aligned.index[2] * page_size(3)
1887 + aligned.rec_compute_vaddr(3)) as Vaddr);
1888 };
1889 assert(aligned.rec_compute_vaddr(1) == 0) by {
1890 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1891 + aligned.rec_compute_vaddr(2)) as Vaddr);
1892 };
1893 } else {
1894 let level = (NR_LEVELS - path.len()) as int;
1895 assert(0 <= level < NR_LEVELS);
1896 self.to_path_inv(level);
1897 self.to_path_len(level);
1898 assert forall|i: int| 0 <= i < path.len() implies #[trigger] path.index(i)
1899 == self.to_path(level).index(i) by {
1900 self.to_path_index(level, i);
1901 };
1902 Self::rec_vaddr_eq_if_indices_eq(path, self.to_path(level), 0);
1903 self.to_path_vaddr(level);
1904 self.align_down_shape(level + 1);
1905 }
1906 }
1907
1908 pub proof fn to_path_index(self, level: int, i: int)
1911 requires
1912 self.inv(),
1913 0 <= level < NR_LEVELS,
1914 0 <= i < NR_LEVELS - level,
1915 ensures
1916 self.to_path(level).index(i) == self.index[NR_LEVELS - 1 - i],
1917 {
1918 self.to_path_len(level);
1919 self.rec_to_path_index(NR_LEVELS - 1, level, i);
1920 }
1921
1922 proof fn rec_to_path_index(self, abstract_level: int, bottom_level: int, i: int)
1923 requires
1924 self.inv(),
1925 0 <= bottom_level <= abstract_level < NR_LEVELS,
1926 0 <= i < abstract_level - bottom_level + 1,
1927 ensures
1928 self.rec_to_path(abstract_level, bottom_level).index(i) == self.index[abstract_level
1929 - i],
1930 decreases abstract_level - bottom_level,
1931 {
1932 assert(self.index.contains_key(abstract_level));
1933 if abstract_level == bottom_level {
1934 } else {
1935 let head = seq![self.index[abstract_level] as usize];
1936 let tail = self.rec_to_path(abstract_level - 1, bottom_level);
1937 let full = head.add(tail);
1938 if i == 0 {
1939 } else {
1940 self.rec_to_path_index(abstract_level - 1, bottom_level, i - 1);
1941 assert(0 <= i - 1 < tail.len()) by {
1942 self.rec_to_path_len(abstract_level - 1, bottom_level);
1943 };
1944 }
1945 }
1946 }
1947
1948 pub proof fn to_path_vaddr_concrete(self, level: int)
1953 requires
1954 self.inv(),
1955 0 <= level < NR_LEVELS,
1956 ensures
1957 vaddr(self.to_path(level)) as int + self.leading_bits * 0x1_0000_0000_0000int
1958 == nat_align_down(
1959 self.to_vaddr() as nat,
1960 page_size((level + 1) as PagingLevel) as nat,
1961 ) as int,
1962 {
1963 self.to_path_vaddr(level);
1964 let aligned = self.align_down(level + 1);
1965 self.align_down_shape(level + 1);
1966 aligned.to_vaddr_is_compute_vaddr();
1967 self.align_down_concrete(level + 1);
1968 aligned.reflect_prop(
1969 nat_align_down(
1970 self.to_vaddr() as nat,
1971 page_size((level + 1) as PagingLevel) as nat,
1972 ) as Vaddr,
1973 );
1974 self.align_down_leading_bits(level + 1);
1975 let nad = nat_align_down(
1981 self.to_vaddr() as nat,
1982 page_size((level + 1) as PagingLevel) as nat,
1983 );
1984 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1987 vstd_extra::arithmetic::lemma_nat_align_down_sound(
1988 self.to_vaddr() as nat,
1989 page_size((level + 1) as PagingLevel) as nat,
1990 );
1991 assert(nad <= self.to_vaddr() as nat);
1992 assert(nad <= usize::MAX);
1993 assert(aligned.leading_bits == self.leading_bits);
1994 assert(vaddr(self.to_path(level)) as int == aligned.compute_vaddr() as int);
1995 assert(aligned.to_vaddr() as int == aligned.compute_vaddr() as int + aligned.leading_bits
1996 * 0x1_0000_0000_0000int);
1997 assert(aligned.to_vaddr() == nad as Vaddr);
1998 assert(aligned.to_vaddr() as int == nad as int);
2000 }
2001
2002 pub proof fn vaddr_range_from_path(self, level: int)
2005 requires
2006 self.inv(),
2007 0 <= level < NR_LEVELS,
2008 ensures
2009 vaddr(self.to_path(level)) as int + self.leading_bits * 0x1_0000_0000_0000int
2010 <= self.to_vaddr() as int,
2011 (self.to_vaddr() as int) < vaddr(self.to_path(level)) as int + self.leading_bits
2012 * 0x1_0000_0000_0000int + page_size((level + 1) as PagingLevel) as int,
2013 {
2014 self.to_path_vaddr_concrete(level);
2015 let size = page_size((level + 1) as PagingLevel);
2016 let cur = self.to_vaddr() as nat;
2017 let start = vaddr(self.to_path(level));
2018
2019 assert(page_size((level + 1) as PagingLevel) >= PAGE_SIZE) by {
2020 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
2021 };
2022 lemma_nat_align_down_sound(cur, size as nat);
2023 }
2024}
2025
2026}