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::{PagingLevel, Vaddr, page_size};
23use crate::specs::arch::*;
24
25use align_ext::AlignExt;
26
27verus! {
28
29pub struct AbstractVaddr {
41 pub offset: int,
42 pub index: Map<int, int>,
43 pub leading_bits: int,
44}
45
46impl Inv for AbstractVaddr {
47 open spec fn inv(self) -> bool {
48 &&& 0 <= self.offset
49 < PAGE_SIZE
50 &&& self.index.dom() =~= Set::<int>::range(0, NR_LEVELS as int)
52 &&& forall|i: int|
53 #![trigger self.index.contains_key(i)]
54 0 <= i < NR_LEVELS ==> {
55 &&& self.index.contains_key(i)
56 &&& 0 <= self.index[i] < NR_ENTRIES
57 }
58 &&& 0 <= self.leading_bits < 0x1_0000int
60 }
61}
62
63impl AbstractVaddr {
64 pub open spec fn from_vaddr(va: Vaddr) -> Self {
69 AbstractVaddr {
70 offset: (va % PAGE_SIZE) as int,
71 index: Map::new(
72 Set::<int>::range(0, NR_LEVELS as int),
73 |i: int| ((va / pow2((12 + 9 * i) as nat) as usize) % NR_ENTRIES) as int,
74 ),
75 leading_bits: (va as int / 0x1_0000_0000_0000int),
76 }
77 }
78
79 pub proof fn from_vaddr_wf(va: Vaddr)
80 ensures
81 AbstractVaddr::from_vaddr(va).inv(),
82 {
83 let abs = AbstractVaddr::from_vaddr(va);
84 assert forall|i: int| #![trigger abs.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
85 &&& abs.index.contains_key(i)
86 &&& 0 <= abs.index[i]
87 &&& abs.index[i] < NR_ENTRIES
88 } by {};
89 let va_i = va as int;
90 assert(0 <= abs.leading_bits < 0x1_0000int) by (nonlinear_arith)
91 requires
92 abs.leading_bits == va_i / 0x1_0000_0000_0000int,
93 0 <= va_i < 0x1_0000_0000_0000_0000int,
94 ;
95 }
96
97 pub open spec fn to_vaddr(self) -> Vaddr {
100 (self.offset + self.to_vaddr_indices(0) + self.leading_bits
101 * 0x1_0000_0000_0000int) as Vaddr
102 }
103
104 pub open spec fn to_vaddr_indices(self, start: int) -> int
106 decreases NR_LEVELS - start,
107 when start <= NR_LEVELS
108 {
109 if start >= NR_LEVELS {
110 0
111 } else {
112 self.index[start] * pow2((12 + 9 * start) as nat) + self.to_vaddr_indices(start + 1)
113 }
114 }
115
116 pub open spec fn reflect(self, va: Vaddr) -> bool {
118 self == Self::from_vaddr(va)
119 }
120
121 pub broadcast proof fn reflect_prop(self, va: Vaddr)
124 requires
125 self.inv(),
126 self.reflect(va),
127 ensures
128 #[trigger] self.to_vaddr() == va,
129 #[trigger] Self::from_vaddr(va) == self,
130 {
131 Self::from_vaddr_to_vaddr_roundtrip(va);
135 }
136
137 pub proof fn from_vaddr_to_vaddr_roundtrip(va: Vaddr)
143 ensures
144 Self::from_vaddr(va).to_vaddr() == va,
145 {
146 vstd::arithmetic::power2::lemma2_to64();
147 vstd::arithmetic::power2::lemma2_to64_rest();
148 let abs = Self::from_vaddr(va);
149 assert(abs.to_vaddr_indices(4) == 0);
150 assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) + abs.to_vaddr_indices(4));
151 assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) + abs.to_vaddr_indices(3));
152 assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) + abs.to_vaddr_indices(2));
153 assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) + abs.to_vaddr_indices(1));
154 assert(va == (va % 4096usize) + ((va / 4096usize) % 512usize) * 4096usize + ((va
155 / 0x20_0000usize) % 512usize) * 0x20_0000usize + ((va / 0x4000_0000usize) % 512usize)
156 * 0x4000_0000usize + ((va / 0x80_0000_0000usize) % 512usize) * 0x80_0000_0000usize + (va
157 / 0x1_0000_0000_0000usize) * 0x1_0000_0000_0000usize) by (bit_vector);
158 }
159
160 pub broadcast proof fn reflect_from_vaddr(va: Vaddr)
162 ensures
163 #[trigger] Self::from_vaddr(va).reflect(va),
164 #[trigger] Self::from_vaddr(va).inv(),
165 {
166 Self::from_vaddr_wf(va);
167 }
168
169 pub broadcast proof fn reflect_to_vaddr(self)
171 requires
172 self.inv(),
173 ensures
174 #[trigger] self.reflect(self.to_vaddr()),
175 {
176 Self::to_vaddr_from_vaddr_roundtrip(self);
177 }
178
179 pub proof fn to_vaddr_from_vaddr_roundtrip(abs: Self)
182 requires
183 abs.inv(),
184 ensures
185 Self::from_vaddr(abs.to_vaddr()) == abs,
186 {
187 vstd::arithmetic::power2::lemma2_to64();
188 vstd::arithmetic::power2::lemma2_to64_rest();
189 abs.to_vaddr_bounded();
190 assert(abs.to_vaddr_indices(4) == 0);
191 assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) + abs.to_vaddr_indices(4));
192 assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) + abs.to_vaddr_indices(3));
193 assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) + abs.to_vaddr_indices(2));
194 assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) + abs.to_vaddr_indices(1));
195
196 assert(abs.index.contains_key(0));
197 assert(abs.index.contains_key(1));
198 assert(abs.index.contains_key(2));
199 assert(abs.index.contains_key(3));
200 let i0 = abs.index[0] as usize;
201 let i1 = abs.index[1] as usize;
202 let i2 = abs.index[2] as usize;
203 let i3 = abs.index[3] as usize;
204 let o = abs.offset as usize;
205 let tb = abs.leading_bits as usize;
206 let va = abs.to_vaddr();
207 assert(va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
208 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize);
209
210 assert(va % 4096usize == o) by (bit_vector)
211 requires
212 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
213 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
214 o < 4096usize,
215 i0 < 512usize,
216 i1 < 512usize,
217 i2 < 512usize,
218 i3 < 512usize,
219 tb < 0x1_0000usize,
220 ;
221 assert((va / 4096usize) % 512usize == i0) by (bit_vector)
222 requires
223 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
224 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
225 o < 4096usize,
226 i0 < 512usize,
227 i1 < 512usize,
228 i2 < 512usize,
229 i3 < 512usize,
230 tb < 0x1_0000usize,
231 ;
232 assert((va / 0x20_0000usize) % 512usize == i1) by (bit_vector)
233 requires
234 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
235 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
236 o < 4096usize,
237 i0 < 512usize,
238 i1 < 512usize,
239 i2 < 512usize,
240 i3 < 512usize,
241 tb < 0x1_0000usize,
242 ;
243 assert((va / 0x4000_0000usize) % 512usize == i2) by (bit_vector)
244 requires
245 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
246 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
247 o < 4096usize,
248 i0 < 512usize,
249 i1 < 512usize,
250 i2 < 512usize,
251 i3 < 512usize,
252 tb < 0x1_0000usize,
253 ;
254 assert((va / 0x80_0000_0000usize) % 512usize == i3) by (bit_vector)
255 requires
256 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
257 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
258 o < 4096usize,
259 i0 < 512usize,
260 i1 < 512usize,
261 i2 < 512usize,
262 i3 < 512usize,
263 tb < 0x1_0000usize,
264 ;
265 assert(va / 0x1_0000_0000_0000usize == tb) by (bit_vector)
266 requires
267 va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
268 * 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
269 o < 4096usize,
270 i0 < 512usize,
271 i1 < 512usize,
272 i2 < 512usize,
273 i3 < 512usize,
274 tb < 0x1_0000usize,
275 ;
276
277 let back = Self::from_vaddr(va);
278 assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] back.index[i]
279 == abs.index[i] by {
280 if i == 0 {
281 } else if i == 1 {
282 } else if i == 2 {
283 } else if i == 3 {
284 }
285 }
286 assert(back.index == abs.index);
287 }
288
289 pub broadcast proof fn reflect_eq(self, other: Self, va: Vaddr)
291 requires
292 #[trigger] self.reflect(va),
293 #[trigger] other.reflect(va),
294 ensures
295 self == other,
296 {
297 }
298
299 pub open spec fn align_down(self, level: int) -> Self
300 decreases level,
301 when level >= 1
302 {
303 if level == 1 {
304 AbstractVaddr { offset: 0, ..self }
305 } else {
306 let tmp = self.align_down(level - 1);
307 AbstractVaddr { index: tmp.index.insert(level - 2, 0), ..tmp }
308 }
309 }
310
311 pub proof fn align_down_inv(self, level: int)
312 requires
313 1 <= level <= NR_LEVELS,
314 self.inv(),
315 ensures
316 self.align_down(level).inv(),
317 forall|i: int|
318 level <= i < NR_LEVELS ==> #[trigger] self.index[i - 1] == self.align_down(
319 level,
320 ).index[i - 1],
321 decreases level,
322 {
323 if level == 1 {
324 assert(self.align_down(1).index == self.index);
325 } else {
326 let tmp = self.align_down(level - 1);
327 self.align_down_inv(level - 1);
328 let new = self.align_down(level);
329 assert(new.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
330 assert forall|i: int| #![trigger new.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
331 &&& new.index.contains_key(i)
332 &&& 0 <= new.index[i]
333 &&& new.index[i] < NR_ENTRIES
334 } by {
335 if i != level - 2 {
336 assert(tmp.index.contains_key(i));
337 }
338 }
339 }
340 }
341
342 pub proof fn align_down_leading_bits(self, level: int)
343 requires
344 1 <= level <= NR_LEVELS,
345 ensures
346 self.align_down(level).leading_bits == self.leading_bits,
347 decreases level,
348 {
349 if level > 1 {
350 self.align_down_leading_bits(level - 1);
351 }
352 }
353
354 pub proof fn align_down_shape(self, level: int)
355 requires
356 1 <= level <= NR_LEVELS,
357 self.inv(),
358 ensures
359 self.align_down(level).inv(),
360 self.align_down(level).offset == 0,
361 forall|i: int| 0 <= i < level - 1 ==> #[trigger] self.align_down(level).index[i] == 0,
362 forall|i: int|
363 level - 1 <= i < NR_LEVELS ==> #[trigger] self.align_down(level).index[i]
364 == self.index[i],
365 decreases level,
366 {
367 if level == 1 {
368 assert(self.align_down(1).index == self.index);
369 } else {
370 let tmp = self.align_down(level - 1);
371 self.align_down_shape(level - 1);
372 let new = self.align_down(level);
373 assert(new.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
374 assert forall|i: int| #![trigger new.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
375 &&& new.index.contains_key(i)
376 &&& 0 <= new.index[i]
377 &&& new.index[i] < NR_ENTRIES
378 } by {
379 if i != level - 2 {
380 assert(tmp.index.contains_key(i));
381 }
382 }
383 }
384 }
385
386 pub proof fn to_vaddr_indices_drop_zero_range(self, from: int, to: int)
387 requires
388 self.inv(),
389 0 <= from <= to <= NR_LEVELS,
390 forall|i: int| from <= i < to ==> self.index[i] == 0,
391 ensures
392 self.to_vaddr_indices(from) == self.to_vaddr_indices(to),
393 decreases to - from,
394 {
395 if from < to {
396 self.to_vaddr_indices_drop_zero_range(from + 1, to);
397 }
398 }
399
400 pub proof fn to_vaddr_indices_eq_if_indices_eq(self, other: Self, start: int)
401 requires
402 self.inv(),
403 other.inv(),
404 0 <= start <= NR_LEVELS,
405 forall|i: int| start <= i < NR_LEVELS ==> self.index[i] == other.index[i],
406 ensures
407 self.to_vaddr_indices(start) == other.to_vaddr_indices(start),
408 decreases NR_LEVELS - start,
409 {
410 if start < NR_LEVELS {
411 self.to_vaddr_indices_eq_if_indices_eq(other, start + 1);
412 }
413 }
414
415 pub proof fn align_down_to_vaddr_eq_if_upper_indices_eq(self, other: Self, level: int)
420 requires
421 1 <= level <= NR_LEVELS,
422 self.inv(),
423 other.inv(),
424 forall|i: int| level - 1 <= i < NR_LEVELS ==> self.index[i] == other.index[i],
426 self.leading_bits == other.leading_bits,
428 ensures
429 self.align_down(level).to_vaddr() == other.align_down(level).to_vaddr(),
430 decreases level,
431 {
432 let lhs = self.align_down(level);
433 let rhs = other.align_down(level);
434
435 self.align_down_shape(level);
436 other.align_down_shape(level);
437 self.align_down_leading_bits(level);
438 other.align_down_leading_bits(level);
439
440 lhs.to_vaddr_indices_drop_zero_range(0, level - 1);
441 rhs.to_vaddr_indices_drop_zero_range(0, level - 1);
442 lhs.to_vaddr_indices_eq_if_indices_eq(rhs, level - 1);
443 assert(lhs.leading_bits == rhs.leading_bits);
444 }
445
446 proof fn align_down_to_vaddr_arith(self, level: int)
450 requires
451 self.inv(),
452 1 <= level <= NR_LEVELS,
453 ensures
454 self.align_down(level).to_vaddr() as int % page_size(level as PagingLevel) as int == 0,
455 0 <= self.to_vaddr() - self.align_down(level).to_vaddr(),
456 self.to_vaddr() - self.align_down(level).to_vaddr() < page_size(level as PagingLevel),
457 {
458 let aligned = self.align_down(level);
459 vstd::arithmetic::power2::lemma2_to64();
460 vstd::arithmetic::power2::lemma2_to64_rest();
461 lemma_page_size_spec_values();
462 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
463
464 self.align_down_shape(level);
465 self.align_down_leading_bits(level);
466 self.to_vaddr_bounded();
467 aligned.to_vaddr_bounded();
468
469 aligned.to_vaddr_indices_drop_zero_range(0, level - 1);
471 aligned.to_vaddr_indices_eq_if_indices_eq(self, level - 1);
472
473 let o = self.offset;
475 let lb = self.leading_bits;
476 assert(self.index.contains_key(0));
477 assert(self.index.contains_key(1));
478 assert(self.index.contains_key(2));
479 assert(self.index.contains_key(3));
480 let i0 = self.index[0];
481 let i1 = self.index[1];
482 let i2 = self.index[2];
483 let i3 = self.index[3];
484 assert(self.to_vaddr_indices(4) == 0);
485 assert(self.to_vaddr_indices(3) == i3 * 0x80_0000_0000int);
486 assert(self.to_vaddr_indices(2) == i2 * 0x4000_0000int + i3 * 0x80_0000_0000int);
487 assert(self.to_vaddr_indices(1) == i1 * 0x20_0000int + i2 * 0x4000_0000int + i3
488 * 0x80_0000_0000int);
489 assert(self.to_vaddr_indices(0) == i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int
490 + i3 * 0x80_0000_0000int);
491
492 let va = self.to_vaddr() as int;
493 let av = aligned.to_vaddr() as int;
494 let ps = page_size(level as PagingLevel) as int;
495
496 assert(va == o + self.to_vaddr_indices(0) + lb * 0x1_0000_0000_0000int);
498 assert(av == 0 + self.to_vaddr_indices(level - 1) + lb * 0x1_0000_0000_0000int);
499
500 let diff = va - av;
502 if level == 1 {
503 assert(ps == 0x1000);
504 assert(diff == o);
505 assert(av % ps == 0) by (nonlinear_arith)
506 requires
507 av == i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int + i3
508 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
509 ps == 0x1000,
510 ;
511 } else if level == 2 {
512 assert(ps == 0x20_0000);
513 assert(diff == o + i0 * 0x1000int);
514 assert(0 <= diff < ps) by (nonlinear_arith)
515 requires
516 diff == o + i0 * 0x1000int,
517 0 <= o < 4096,
518 0 <= i0 < 512,
519 ps == 0x20_0000,
520 ;
521 assert(av % ps == 0) by (nonlinear_arith)
522 requires
523 av == i1 * 0x20_0000int + i2 * 0x4000_0000int + i3 * 0x80_0000_0000int + lb
524 * 0x1_0000_0000_0000int,
525 ps == 0x20_0000,
526 ;
527 } else if level == 3 {
528 assert(ps == 0x4000_0000);
529 assert(diff == o + i0 * 0x1000int + i1 * 0x20_0000int);
530 assert(0 <= diff < ps) by (nonlinear_arith)
531 requires
532 diff == o + i0 * 0x1000int + i1 * 0x20_0000int,
533 0 <= o < 4096,
534 0 <= i0 < 512,
535 0 <= i1 < 512,
536 ps == 0x4000_0000,
537 ;
538 assert(av % ps == 0) by (nonlinear_arith)
539 requires
540 av == i2 * 0x4000_0000int + i3 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
541 ps == 0x4000_0000,
542 ;
543 } else {
544 assert(ps == 0x80_0000_0000);
545 assert(diff == o + i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int);
546 assert(0 <= diff < ps) by (nonlinear_arith)
547 requires
548 diff == o + i0 * 0x1000int + i1 * 0x20_0000int + i2 * 0x4000_0000int,
549 0 <= o < 4096,
550 0 <= i0 < 512,
551 0 <= i1 < 512,
552 0 <= i2 < 512,
553 ps == 0x80_0000_0000,
554 ;
555 assert(av % ps == 0) by (nonlinear_arith)
556 requires
557 av == i3 * 0x80_0000_0000int + lb * 0x1_0000_0000_0000int,
558 ps == 0x80_0000_0000,
559 ;
560 }
561 }
562
563 pub proof fn align_down_to_vaddr_nat_align_down(self, level: int)
567 requires
568 self.inv(),
569 1 <= level <= NR_LEVELS,
570 ensures
571 self.align_down(level).to_vaddr() as nat == nat_align_down(
572 self.to_vaddr() as nat,
573 page_size(level as PagingLevel) as nat,
574 ),
575 {
576 self.align_down_to_vaddr_arith(level);
577
578 let va = self.to_vaddr() as int;
579 let av = self.align_down(level).to_vaddr() as int;
580 let ps = page_size(level as PagingLevel) as int;
581
582 assert(av % ps == 0);
583 assert(va - av < ps);
584
585 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(av, ps);
589 assert(av == ps * (av / ps)) by {
590 assert(av % ps == 0);
591 };
592 assert(va == ps * (av / ps) + (va - av));
593 vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(av / ps, va - av, ps);
594 assert((ps * (av / ps) + (va - av)) % ps == (va - av) % ps);
595 assert(va % ps == (va - av) % ps);
596 vstd::arithmetic::div_mod::lemma_small_mod((va - av) as nat, ps as nat);
597 assert((va - av) % ps == va - av);
598 assert(va % ps == va - av);
599 }
600
601 pub proof fn align_down_concrete(self, level: int)
602 requires
603 self.inv(),
604 1 <= level <= NR_LEVELS,
605 ensures
606 self.align_down(level).reflect(
607 nat_align_down(
608 self.to_vaddr() as nat,
609 page_size(level as PagingLevel) as nat,
610 ) as Vaddr,
611 ),
612 {
613 let aligned = self.align_down(level);
614 self.align_down_shape(level);
615 self.align_down_to_vaddr_nat_align_down(level);
616 aligned.reflect_to_vaddr();
617 let nad = nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat);
620 self.to_vaddr_bounded();
621 assert(nad as Vaddr == aligned.to_vaddr());
622 }
623
624 pub proof fn same_node_indices_match(
630 va1: Vaddr,
631 va2: Vaddr,
632 node_start: Vaddr,
633 level: PagingLevel,
634 )
635 requires
636 1 <= level,
637 level < NR_LEVELS,
638 node_start <= va1,
639 va1 < node_start + page_size((level + 1) as PagingLevel),
640 node_start <= va2,
641 va2 < node_start + page_size((level + 1) as PagingLevel),
642 node_start as nat % page_size((level + 1) as PagingLevel) as nat == 0,
643 ensures
644 forall|i: int|
645 #![auto]
646 level <= i < NR_LEVELS ==> Self::from_vaddr(va1).index[i] == Self::from_vaddr(
647 va2,
648 ).index[i],
649 {
650 vstd::arithmetic::power2::lemma2_to64();
651 vstd::arithmetic::power2::lemma2_to64_rest();
652 lemma_page_size_spec_values();
653 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
654
655 let ns = node_start;
656
657 if level == 1 {
662 assert((va1 / 0x20_0000usize) % 512 == (va2 / 0x20_0000usize) % 512) by (bit_vector)
663 requires
664 va1 >= ns,
665 va1 < ns + 0x20_0000usize,
666 va2 >= ns,
667 va2 < ns + 0x20_0000usize,
668 ns % 0x20_0000usize == 0usize,
669 ;
670 assert((va1 / 0x4000_0000usize) % 512 == (va2 / 0x4000_0000usize) % 512) by (bit_vector)
671 requires
672 va1 >= ns,
673 va1 < ns + 0x20_0000usize,
674 va2 >= ns,
675 va2 < ns + 0x20_0000usize,
676 ns % 0x20_0000usize == 0usize,
677 ;
678 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
679 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 } else if level == 2 {
688 assert((va1 / 0x4000_0000usize) % 512 == (va2 / 0x4000_0000usize) % 512) by (bit_vector)
689 requires
690 va1 >= ns,
691 va1 < ns + 0x4000_0000usize,
692 va2 >= ns,
693 va2 < ns + 0x4000_0000usize,
694 ns % 0x4000_0000usize == 0usize,
695 ;
696 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
697 by (bit_vector)
698 requires
699 va1 >= ns,
700 va1 < ns + 0x4000_0000usize,
701 va2 >= ns,
702 va2 < ns + 0x4000_0000usize,
703 ns % 0x4000_0000usize == 0usize,
704 ;
705 } else {
706 assert((va1 / 0x80_0000_0000usize) % 512 == (va2 / 0x80_0000_0000usize) % 512)
708 by (bit_vector)
709 requires
710 va1 >= ns,
711 va1 < ns + 0x80_0000_0000usize,
712 va2 >= ns,
713 va2 < ns + 0x80_0000_0000usize,
714 ns % 0x80_0000_0000usize == 0usize,
715 ;
716 }
717
718 assert forall|i: int| level <= i < NR_LEVELS implies Self::from_vaddr(va1).index[i]
721 == Self::from_vaddr(va2).index[i] by {
722 let abs1 = Self::from_vaddr(va1);
723 let abs2 = Self::from_vaddr(va2);
724 assert(abs1.index.contains_key(i));
725 assert(abs2.index.contains_key(i));
726 if i == 1 {
727 assert(pow2((12 + 9 * i) as nat) as usize == 0x20_0000);
728 } else if i == 2 {
729 assert(pow2((12 + 9 * i) as nat) as usize == 0x4000_0000);
730 } else {
731 assert(pow2((12 + 9 * i) as nat) as usize == 0x80_0000_0000);
732 }
733 }
734 }
735
736 pub open spec fn align_up(self, level: int) -> Self {
737 let lower_aligned = self.align_down(level);
738 lower_aligned.next_index(level)
739 }
740
741 pub proof fn align_up_concrete_sound(self, level: int)
745 requires
746 self.inv(),
747 1 <= level <= NR_LEVELS,
748 self.index[level - 1] + 1 < NR_ENTRIES,
749 ensures
750 self.align_up(level).reflect(
751 (nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
752 + page_size(level as PagingLevel) as nat) as Vaddr,
753 ),
754 {
755 let aligned = self.align_down(level);
756 self.align_down_shape(level);
757 self.align_down_to_vaddr_nat_align_down(level);
758 aligned.index_increment_adds_page_size(level);
759
760 let advanced = AbstractVaddr {
761 index: aligned.index.insert(level - 1, aligned.index[level - 1] + 1),
762 ..aligned
763 };
764 assert(aligned.next_index(level) == advanced);
765 assert(self.align_up(level) == advanced);
766
767 assert(advanced.inv()) by {
768 assert(advanced.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
769 assert forall|i: int|
770 #![trigger advanced.index.contains_key(i)]
771 0 <= i < NR_LEVELS implies {
772 &&& advanced.index.contains_key(i)
773 &&& 0 <= advanced.index[i]
774 &&& advanced.index[i] < NR_ENTRIES
775 } by {
776 assert(aligned.index.contains_key(i));
777 }
778 };
779 advanced.reflect_to_vaddr();
780 }
781
782 pub proof fn aligned_align_down_is_self(self, level: int)
788 requires
789 self.inv(),
790 1 <= level <= NR_LEVELS,
791 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat == 0,
792 ensures
793 self.align_down(level) == self,
794 {
795 let aligned = self.align_down(level);
796 let va = self.to_vaddr() as nat;
797 let ps = page_size(level as PagingLevel) as nat;
798
799 self.align_down_shape(level);
800 self.align_down_to_vaddr_nat_align_down(level);
801 lemma_page_size_ge_page_size(level as PagingLevel);
802 vstd_extra::arithmetic::lemma_nat_align_down_sound(va, ps);
803 self.to_vaddr_bounded();
804
805 assert(nat_align_down(va, ps) == va);
807 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(self);
812 AbstractVaddr::to_vaddr_from_vaddr_roundtrip(aligned);
813 }
816
817 pub proof fn aligned_align_up_advances(self, level: int)
825 requires
826 self.inv(),
827 1 <= level <= NR_LEVELS,
828 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat == 0,
829 self.to_vaddr() + page_size(level as PagingLevel) <= usize::MAX,
833 ensures
834 self.align_up(level).inv(),
835 self.align_up(level).to_vaddr() == self.to_vaddr() + page_size(level as PagingLevel),
836 decreases NR_LEVELS + 1 - level,
837 {
838 vstd::arithmetic::power2::lemma2_to64();
839 vstd::arithmetic::power2::lemma2_to64_rest();
840 lemma_page_size_spec_values();
841 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
842 lemma_page_size_ge_page_size(level as PagingLevel);
843
844 self.aligned_align_down_is_self(level);
845 if self.index[level - 1] + 1 < NR_ENTRIES {
848 self.index_increment_adds_page_size(level);
850 let advanced = AbstractVaddr {
853 index: self.index.insert(level - 1, self.index[level - 1] + 1),
854 ..self
855 };
856 assert(self.next_index(level) == advanced);
857 assert(self.align_up(level) == advanced);
858 assert(advanced.inv()) by {
859 assert(advanced.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
860 assert forall|i: int|
861 #![trigger advanced.index.contains_key(i)]
862 0 <= i < NR_LEVELS implies {
863 &&& advanced.index.contains_key(i)
864 &&& 0 <= advanced.index[i]
865 &&& advanced.index[i] < NR_ENTRIES
866 } by {
867 assert(self.index.contains_key(i));
868 }
869 };
870 } else {
871 assert(self.index.contains_key(level - 1));
873 assert(self.index[level - 1] < NR_ENTRIES); assert(self.index[level - 1] + 1 >= NR_ENTRIES); assert(self.index[level - 1] == NR_ENTRIES - 1);
876
877 if level < NR_LEVELS {
878 self.align_up_carry(level);
879 let prev_aligned = self.align_down(level + 1);
882 self.align_down_shape(level + 1);
883 self.align_down_to_vaddr_nat_align_down(level + 1);
884 self.align_down_leading_bits(level + 1);
885 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
886 self.to_vaddr_bounded();
887 prev_aligned.to_vaddr_bounded();
888
889 let ps1 = page_size((level + 1) as PagingLevel) as nat;
891 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.to_vaddr() as nat, ps1);
892 assert(prev_aligned.to_vaddr() as nat % ps1 == 0);
893
894 let ps = page_size(level as PagingLevel) as int;
896 assert(ps1 == NR_ENTRIES * ps) by {
897 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
898 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
899 (level + 1) as PagingLevel);
900 };
901
902 assert forall|i: int| 0 <= i < level - 1 implies self.index[i] == 0 by {
906 assert(self.index.contains_key(i));
907 };
908 self.to_vaddr_indices_drop_zero_range(0, level - 1);
909 prev_aligned.to_vaddr_indices_drop_zero_range(0, level);
910 prev_aligned.to_vaddr_indices_eq_if_indices_eq(self, level);
911
912 assert(self.index.contains_key(level - 1));
913 if level == 1 {
914 assert(ps == 0x1000);
915 assert(pow2(12nat) == ps);
916 } else if level == 2 {
917 assert(ps == 0x20_0000);
918 assert(pow2(21nat) == ps);
919 } else if level == 3 {
920 assert(ps == 0x4000_0000);
921 assert(pow2(30nat) == ps);
922 }
923 assert(self.to_vaddr_indices(level - 1) == self.index[level - 1] * ps
924 + self.to_vaddr_indices(level));
925 assert(self.to_vaddr_indices(level - 1) == (NR_ENTRIES - 1) * ps
926 + self.to_vaddr_indices(level));
927
928 assert(prev_aligned.offset == 0);
930 assert(prev_aligned.leading_bits == self.leading_bits);
931 assert(self.offset == 0);
932
933 assert(prev_aligned.to_vaddr() + (NR_ENTRIES - 1) * ps == self.to_vaddr());
934
935 assert(prev_aligned.to_vaddr() + ps1 == self.to_vaddr() + ps) by (nonlinear_arith)
937 requires
938 prev_aligned.to_vaddr() + (NR_ENTRIES - 1) * ps == self.to_vaddr(),
939 ps1 == NR_ENTRIES * ps,
940 ;
941 assert(prev_aligned.to_vaddr() + page_size((level + 1) as PagingLevel)
942 <= usize::MAX);
943
944 prev_aligned.aligned_align_up_advances(level + 1);
945 prev_aligned.aligned_align_down_is_self(level + 1);
946
947 assert(self.align_up(level + 1) == prev_aligned.align_up(level + 1));
950
951 } else {
958 assert(level == NR_LEVELS);
961 self.align_down_shape(NR_LEVELS as int);
969 self.to_vaddr_bounded();
970 assert forall|i: int| 0 <= i < NR_LEVELS - 1 implies self.index[i] == 0 by {
971 assert(self.index.contains_key(i));
972 assert(self.align_down(NR_LEVELS as int).index[i] == 0);
973 };
974 self.to_vaddr_indices_drop_zero_range(0, NR_LEVELS - 1);
975 assert(self.index.contains_key(NR_LEVELS - 1));
976 let ps_top = page_size(NR_LEVELS as PagingLevel) as int;
977 assert(ps_top == 0x80_0000_0000);
978 assert(self.to_vaddr_indices(NR_LEVELS as int) == 0);
979 assert(self.to_vaddr_indices(NR_LEVELS - 1) == self.index[NR_LEVELS - 1] * ps_top);
980 assert(self.to_vaddr_indices(0) == (NR_ENTRIES - 1) * ps_top);
981 assert(self.offset == 0);
982 assert(self.to_vaddr() == (NR_ENTRIES - 1) * ps_top + self.leading_bits
983 * 0x1_0000_0000_0000int);
984 assert(NR_ENTRIES * ps_top == 0x1_0000_0000_0000int) by (compute);
985 assert(self.leading_bits + 1 < 0x1_0000) by (nonlinear_arith)
987 requires
988 self.to_vaddr() == (NR_ENTRIES - 1) * ps_top + self.leading_bits
989 * 0x1_0000_0000_0000int,
990 self.to_vaddr() + ps_top <= usize::MAX,
991 ps_top == 0x80_0000_0000,
992 NR_ENTRIES * ps_top == 0x1_0000_0000_0000int,
993 0 <= self.leading_bits < 0x1_0000,
994 usize::MAX == 0xffff_ffff_ffff_ffffusize,
995 ;
996
997 let advanced_top = AbstractVaddr {
1003 index: self.index.insert(NR_LEVELS - 1, 0),
1004 leading_bits: self.leading_bits + 1,
1005 ..self
1006 };
1007 assert(self.next_index(NR_LEVELS as int) == advanced_top);
1008 assert(self.align_up(NR_LEVELS as int) == advanced_top);
1009
1010 assert(advanced_top.inv()) by {
1011 assert(advanced_top.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
1012 assert forall|i: int|
1013 #![trigger advanced_top.index.contains_key(i)]
1014 0 <= i < NR_LEVELS implies {
1015 &&& advanced_top.index.contains_key(i)
1016 &&& 0 <= advanced_top.index[i]
1017 &&& advanced_top.index[i] < NR_ENTRIES
1018 } by {
1019 assert(self.index.contains_key(i));
1020 }
1021 };
1022
1023 self.to_vaddr_bounded();
1033 advanced_top.to_vaddr_bounded();
1034 let ps = page_size(NR_LEVELS as PagingLevel) as int;
1035 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
1036 assert(ps == 0x80_0000_0000);
1038
1039 self.align_down_shape(NR_LEVELS as int);
1042 assert forall|i: int| 0 <= i < NR_LEVELS - 1 implies self.index[i] == 0 by {
1043 assert(self.index.contains_key(i));
1044 assert(self.align_down(NR_LEVELS as int).index[i] == 0);
1045 };
1046 self.to_vaddr_indices_drop_zero_range(0, NR_LEVELS - 1);
1047 assert(self.index.contains_key(NR_LEVELS - 1));
1048 assert(self.to_vaddr_indices(NR_LEVELS - 1) == self.index[NR_LEVELS - 1] * ps
1049 + self.to_vaddr_indices(NR_LEVELS as int));
1050 assert(self.to_vaddr_indices(NR_LEVELS as int) == 0);
1051 assert(self.to_vaddr_indices(0) == (NR_ENTRIES - 1) * ps);
1052
1053 assert(advanced_top.offset == 0);
1055 assert forall|i: int| 0 <= i < NR_LEVELS implies advanced_top.index[i] == 0 by {
1056 assert(self.index.contains_key(i));
1057 };
1058 advanced_top.to_vaddr_indices_drop_zero_range(0, NR_LEVELS as int);
1059 assert(advanced_top.to_vaddr_indices(0) == 0);
1060
1061 assert(advanced_top.leading_bits == self.leading_bits + 1);
1066 assert(advanced_top.to_vaddr() == (self.leading_bits + 1) * 0x1_0000_0000_0000int);
1067 assert(self.to_vaddr() == (NR_ENTRIES - 1) * ps + self.leading_bits
1068 * 0x1_0000_0000_0000int);
1069 assert(NR_ENTRIES * ps == 0x1_0000_0000_0000int) by (compute);
1070 assert(advanced_top.to_vaddr() == self.to_vaddr() + ps) by (nonlinear_arith)
1071 requires
1072 advanced_top.to_vaddr() == (self.leading_bits + 1) * 0x1_0000_0000_0000int,
1073 self.to_vaddr() == (NR_ENTRIES - 1) * ps + self.leading_bits
1074 * 0x1_0000_0000_0000int,
1075 NR_ENTRIES * ps == 0x1_0000_0000_0000int,
1076 ;
1077 }
1078 }
1079 }
1080
1081 pub proof fn align_up_advances_general(self, level: int)
1088 requires
1089 self.inv(),
1090 1 <= level <= NR_LEVELS,
1091 nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1095 + page_size(level as PagingLevel) as nat <= usize::MAX as nat,
1096 ensures
1097 self.align_up(level).inv(),
1098 self.align_up(level).to_vaddr() as nat == nat_align_down(
1099 self.to_vaddr() as nat,
1100 page_size(level as PagingLevel) as nat,
1101 ) + page_size(level as PagingLevel) as nat,
1102 {
1103 let aligned = self.align_down(level);
1104 let ps = page_size(level as PagingLevel) as nat;
1105
1106 self.align_down_shape(level);
1107 self.align_down_to_vaddr_nat_align_down(level);
1108 lemma_page_size_ge_page_size(level as PagingLevel);
1109 self.to_vaddr_bounded();
1110 aligned.to_vaddr_bounded();
1111 vstd_extra::arithmetic::lemma_nat_align_down_sound(self.to_vaddr() as nat, ps);
1112
1113 assert(aligned.to_vaddr() as nat % ps == 0);
1116
1117 assert(aligned.to_vaddr() + page_size(level as PagingLevel) <= usize::MAX);
1119
1120 aligned.aligned_align_up_advances(level);
1122
1123 aligned.aligned_align_down_is_self(level);
1129 assert(self.align_up(level) == aligned.align_up(level));
1130 }
1131
1132 pub proof fn align_diff_sound(self, level: int)
1134 requires
1135 1 <= level <= NR_LEVELS,
1136 self.to_vaddr() as nat % page_size(level as PagingLevel) as nat != 0,
1137 ensures
1138 nat_align_up(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1139 == nat_align_down(self.to_vaddr() as nat, page_size(level as PagingLevel) as nat)
1140 + page_size(level as PagingLevel),
1141 {
1142 }
1144
1145 pub proof fn align_up_carry(self, level: int)
1148 requires
1149 self.inv(),
1150 1 <= level,
1151 level < NR_LEVELS,
1152 self.index[level - 1] == NR_ENTRIES - 1,
1153 ensures
1154 self.align_up(level) == self.align_up(level + 1),
1155 decreases NR_LEVELS - level,
1156 {
1157 self.align_down_shape(level);
1158 self.align_down_shape(level + 1);
1159 assert(self.align_down(level).index.insert(level - 1, 0) == self.align_down(
1160 level + 1,
1161 ).index);
1162 }
1163
1164 pub open spec fn next_index(self, level: int) -> Self
1165 decreases NR_LEVELS - level,
1166 when 1 <= level <= NR_LEVELS
1167 {
1168 let index = self.index[level - 1];
1169 let next_index = index + 1;
1170 if next_index == NR_ENTRIES && level < NR_LEVELS {
1171 let next_va = Self { index: self.index.insert(level - 1, 0), ..self };
1172 next_va.next_index(level + 1)
1173 } else if next_index == NR_ENTRIES && level == NR_LEVELS {
1174 Self {
1176 index: self.index.insert(level - 1, 0),
1177 leading_bits: self.leading_bits + 1,
1178 ..self
1179 }
1180 } else {
1181 Self { index: self.index.insert(level - 1, next_index), ..self }
1182 }
1183 }
1184
1185 pub open spec fn wrapped(self, start_level: int, level: int) -> bool
1186 decreases NR_LEVELS - level,
1187 when 1 <= start_level <= level <= NR_LEVELS
1188 {
1189 &&& self.next_index(start_level).index[level - 1] == 0 ==> {
1190 &&& self.index[level - 1] + 1 == NR_ENTRIES
1191 &&& if level < NR_LEVELS {
1192 self.wrapped(start_level, level + 1)
1193 } else {
1194 true
1195 }
1196 }
1197 &&& self.next_index(start_level).index[level - 1] != 0 ==> self.index[level - 1] + 1
1198 < NR_ENTRIES
1199 }
1200
1201 pub proof fn use_wrapped(self, start_level: int, level: int)
1202 requires
1203 1 <= start_level <= level < NR_LEVELS,
1204 self.wrapped(start_level, level),
1205 self.next_index(start_level).index[level - 1] == 0,
1206 ensures
1207 self.index[level - 1] + 1 == NR_ENTRIES,
1208 {
1209 }
1210
1211 pub proof fn wrapped_unwrap(self, start_level: int, level: int)
1212 requires
1213 1 <= start_level <= level < NR_LEVELS,
1214 self.wrapped(start_level, level),
1215 self.next_index(start_level).index[level - 1] == 0,
1216 ensures
1217 self.wrapped(start_level, level + 1),
1218 {
1219 }
1220
1221 pub proof fn wrapped_after_carry_equiv(self, start_level: int, level: int)
1222 requires
1223 self.inv(),
1224 1 <= start_level < level <= NR_LEVELS,
1225 self.index[start_level - 1] + 1 == NR_ENTRIES,
1226 ensures
1227 ({
1228 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1229 self.wrapped(start_level, level) == next_va.wrapped(start_level + 1, level)
1230 }),
1231 decreases NR_LEVELS - level,
1232 {
1233 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1234 if level < NR_LEVELS {
1235 self.wrapped_after_carry_equiv(start_level, level + 1);
1236 }
1237 }
1238
1239 pub proof fn wrapped_index_nonzero(self, start_level: int, level: int)
1241 requires
1242 1 <= start_level <= level <= NR_LEVELS,
1243 self.wrapped(start_level, level),
1244 self.index[level - 1] + 1 < NR_ENTRIES,
1245 ensures
1246 self.next_index(start_level).index[level - 1] != 0,
1247 {
1248 if self.next_index(start_level).index[level - 1] == 0 {
1249 if level < NR_LEVELS {
1250 self.use_wrapped(start_level, level);
1251 }
1252 }
1253 }
1254
1255 pub proof fn wrapped_nonzero_at_level(
1257 abs_va_down: Self,
1258 abs_next_va: Self,
1259 start_level: int,
1260 level: int,
1261 owner_index_at_level: int,
1262 )
1263 requires
1264 1 <= start_level <= level <= NR_LEVELS,
1265 abs_va_down.wrapped(start_level, level),
1266 abs_va_down.next_index(start_level) == abs_next_va,
1267 abs_va_down.index[level - 1] == owner_index_at_level,
1268 owner_index_at_level == 0,
1269 ensures
1270 abs_next_va.index[level - 1] != 0,
1271 {
1272 abs_va_down.wrapped_index_nonzero(start_level, level);
1273 }
1274
1275 pub proof fn wrapped_nonzero_at_level_general(
1279 abs_va_down: Self,
1280 abs_next_va: Self,
1281 start_level: int,
1282 level: int,
1283 owner_index_at_level: int,
1284 )
1285 requires
1286 1 <= start_level <= level <= NR_LEVELS,
1287 abs_va_down.wrapped(start_level, level),
1288 abs_va_down.next_index(start_level) == abs_next_va,
1289 abs_va_down.index[level - 1] == owner_index_at_level,
1290 owner_index_at_level + 1 < NR_ENTRIES,
1291 ensures
1292 abs_next_va.index[level - 1] != 0,
1293 {
1294 abs_va_down.wrapped_index_nonzero(start_level, level);
1295 }
1296
1297 #[verifier::spinoff_prover]
1298 pub proof fn next_index_preserves_lower_indices(self, start_level: int, lower_level: int)
1299 requires
1300 self.inv(),
1301 1 <= lower_level < start_level <= NR_LEVELS,
1302 ensures
1303 self.next_index(start_level).index[lower_level - 1] == self.index[lower_level - 1],
1304 decreases NR_LEVELS - start_level,
1305 {
1306 let index = self.index[start_level - 1];
1307 let next_index = index + 1;
1308 if next_index == NR_ENTRIES && start_level < NR_LEVELS {
1309 let next_va = Self { index: self.index.insert(start_level - 1, 0), ..self };
1310 assert(next_va.inv()) by {
1311 assert(next_va.index.dom() == Set::<int>::range(0, NR_LEVELS as int));
1312 assert forall|i: int|
1313 #![trigger next_va.index.contains_key(i)]
1314 0 <= i < NR_LEVELS implies {
1315 &&& next_va.index.contains_key(i)
1316 &&& 0 <= next_va.index[i]
1317 &&& next_va.index[i] < NR_ENTRIES
1318 } by {
1319 assert(self.index.contains_key(i));
1320 }
1321 };
1322 next_va.next_index_preserves_lower_indices(start_level + 1, lower_level);
1323 } else if next_index == NR_ENTRIES && start_level == NR_LEVELS {
1324 }
1325 }
1326
1327 pub proof fn next_index_wrap_condition(self, level: int)
1328 requires
1329 self.inv(),
1330 1 <= level <= NR_LEVELS,
1331 ensures
1332 self.wrapped(level, level),
1333 decreases NR_LEVELS - level,
1334 {
1335 let index = self.index[level - 1];
1336 let next_index = index + 1;
1337 if next_index == NR_ENTRIES {
1338 if level < NR_LEVELS {
1339 let next_va = Self { index: self.index.insert(level - 1, 0), ..self };
1340 next_va.next_index_wrap_condition(level + 1);
1341 self.wrapped_after_carry_equiv(level, level + 1);
1342 next_va.next_index_preserves_lower_indices(level + 1, level);
1343 }
1344 } else {
1345 assert(self.index.contains_key(level - 1));
1346 }
1347 }
1348
1349 pub open spec fn compute_vaddr(self) -> Vaddr {
1362 self.rec_compute_vaddr(0)
1363 }
1364
1365 pub open spec fn rec_compute_vaddr(self, i: int) -> Vaddr
1367 decreases NR_LEVELS - i,
1368 when 0 <= i <= NR_LEVELS
1369 {
1370 if i >= NR_LEVELS {
1371 self.offset as Vaddr
1372 } else {
1373 let shift = page_size((i + 1) as PagingLevel);
1374 (self.index[i] * shift + self.rec_compute_vaddr(i + 1)) as Vaddr
1375 }
1376 }
1377
1378 pub open spec fn to_path(self, level: int) -> TreePath<NR_ENTRIES>
1388 recommends
1389 0 <= level < NR_LEVELS,
1390 {
1391 TreePath(self.rec_to_path(NR_LEVELS - 1, level))
1392 }
1393
1394 pub open spec fn rec_to_path(self, abstract_level: int, bottom_level: int) -> Seq<usize>
1398 decreases abstract_level - bottom_level,
1399 when bottom_level <= abstract_level
1400 {
1401 if abstract_level < bottom_level {
1402 seq![]
1403 } else if abstract_level == bottom_level {
1404 seq![self.index[abstract_level] as usize]
1406 } else {
1407 seq![self.index[abstract_level] as usize].add(
1409 self.rec_to_path(abstract_level - 1, bottom_level),
1410 )
1411 }
1412 }
1413
1414 #[verifier::rlimit(400)]
1420 pub proof fn to_path_vaddr(self, level: int)
1421 requires
1422 self.inv(),
1423 0 <= level < NR_LEVELS,
1424 ensures
1425 vaddr(self.to_path(level)) == self.align_down(level + 1).compute_vaddr(),
1426 {
1427 self.to_path_inv(level);
1428 self.to_path_len(level);
1429 lemma_page_size_spec_level1();
1430 vstd::arithmetic::power2::lemma2_to64();
1431 vstd::arithmetic::power2::lemma2_to64_rest();
1432 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
1433 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1434 let path = self.to_path(level);
1435 if level == 3 {
1436 let aligned = self.align_down(4);
1437 self.align_down_shape(4);
1438 self.to_path_index(3, 0);
1439 path.index_satisfies_elem_inv(0);
1440 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize) by {
1441 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, path.index(0)) + rec_vaddr(
1442 path,
1443 1,
1444 )) as usize);
1445 };
1446 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1447 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1448 + aligned.rec_compute_vaddr(4)) as Vaddr);
1449 };
1450 assert(aligned.rec_compute_vaddr(2) == self.index[3] * 0x80_0000_0000usize) by {
1451 assert(aligned.rec_compute_vaddr(2) == (aligned.index[2] * page_size(3)
1452 + aligned.rec_compute_vaddr(3)) as Vaddr);
1453 };
1454 assert(aligned.rec_compute_vaddr(1) == self.index[3] * 0x80_0000_0000usize) by {
1455 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1456 + aligned.rec_compute_vaddr(2)) as Vaddr);
1457 };
1458 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1459 + aligned.rec_compute_vaddr(1)) as Vaddr);
1460 assert(vaddr(path) == aligned.compute_vaddr());
1461 } else if level == 2 {
1462 let aligned = self.align_down(3);
1463 self.align_down_shape(3);
1464 self.to_path_index(2, 0);
1465 self.to_path_index(2, 1);
1466 path.index_satisfies_elem_inv(0);
1467 path.index_satisfies_elem_inv(1);
1468 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize + path.index(1)
1469 * 0x4000_0000usize) by {
1470 assert(vaddr(path) == rec_vaddr(path, 0));
1471 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path.index(1)) + rec_vaddr(
1472 path,
1473 2,
1474 )) as usize);
1475 };
1476 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1477 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1478 + aligned.rec_compute_vaddr(4)) as Vaddr);
1479 };
1480 assert(aligned.rec_compute_vaddr(1) == self.index[2] * 0x4000_0000usize + self.index[3]
1481 * 0x80_0000_0000usize) by {
1482 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1483 + aligned.rec_compute_vaddr(2)) as Vaddr);
1484 };
1485 assert(vaddr(path) == aligned.compute_vaddr());
1486 } else if level == 1 {
1487 let aligned = self.align_down(2);
1488 self.align_down_shape(2);
1489 self.to_path_index(1, 0);
1490 self.to_path_index(1, 1);
1491 self.to_path_index(1, 2);
1492 path.index_satisfies_elem_inv(0);
1493 path.index_satisfies_elem_inv(1);
1494 path.index_satisfies_elem_inv(2);
1495 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize + path.index(1)
1496 * 0x4000_0000usize + path.index(2) * 0x20_0000usize) by {
1497 assert(vaddr(path) == rec_vaddr(path, 0));
1498 assert(rec_vaddr(path, 3) == 0);
1499 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, path.index(2)) + rec_vaddr(
1500 path,
1501 3,
1502 )) as usize);
1503 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path.index(1)) + rec_vaddr(
1504 path,
1505 2,
1506 )) as usize);
1507 assert(rec_vaddr(path, 0) == (vaddr_make::<NR_LEVELS>(0, path.index(0)) + rec_vaddr(
1508 path,
1509 1,
1510 )) as usize);
1511 assert(vaddr_make::<NR_LEVELS>(0, path.index(0)) == 0x80_0000_0000usize
1512 * path.index(0)) by (compute);
1513 assert(vaddr_make::<NR_LEVELS>(1, path.index(1)) == 0x4000_0000usize * path.index(
1514 1,
1515 )) by (compute);
1516 assert(vaddr_make::<NR_LEVELS>(2, path.index(2)) == 0x20_0000usize * path.index(2))
1517 by (compute);
1518 };
1519 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1520 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1521 + aligned.rec_compute_vaddr(4)) as Vaddr);
1522 };
1523 assert(aligned.rec_compute_vaddr(1) == self.index[1] * 0x20_0000usize + self.index[2]
1524 * 0x4000_0000usize + self.index[3] * 0x80_0000_0000usize) by {
1525 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1526 + aligned.rec_compute_vaddr(2)) as Vaddr);
1527 };
1528 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1529 + aligned.rec_compute_vaddr(1)) as Vaddr);
1530 assert(vaddr(path) == aligned.compute_vaddr());
1531 } else {
1532 let aligned = self.align_down(1);
1533 self.align_down_shape(1);
1534 self.to_path_index(0, 0);
1535 self.to_path_index(0, 1);
1536 self.to_path_index(0, 2);
1537 self.to_path_index(0, 3);
1538 path.index_satisfies_elem_inv(0);
1539 path.index_satisfies_elem_inv(1);
1540 path.index_satisfies_elem_inv(2);
1541 path.index_satisfies_elem_inv(3);
1542 assert(vaddr(path) == path.index(0) * 0x80_0000_0000usize + path.index(1)
1543 * 0x4000_0000usize + path.index(2) * 0x20_0000usize + path.index(3) * 0x1000usize)
1544 by {
1545 assert(vaddr(path) == rec_vaddr(path, 0));
1546 assert(rec_vaddr(path, 4) == 0);
1547 assert(rec_vaddr(path, 2) == (vaddr_make::<NR_LEVELS>(2, path.index(2)) + rec_vaddr(
1548 path,
1549 3,
1550 )) as usize);
1551 assert(rec_vaddr(path, 1) == (vaddr_make::<NR_LEVELS>(1, path.index(1)) + rec_vaddr(
1552 path,
1553 2,
1554 )) as usize);
1555 assert(vaddr_make::<NR_LEVELS>(0, path.index(0)) == 0x80_0000_0000usize
1556 * path.index(0)) by (compute);
1557 assert(vaddr_make::<NR_LEVELS>(1, path.index(1)) == 0x4000_0000usize * path.index(
1558 1,
1559 )) by (compute);
1560 assert(vaddr_make::<NR_LEVELS>(2, path.index(2)) == 0x20_0000usize * path.index(2))
1561 by {
1562 assert(vaddr_shift_bits::<NR_LEVELS>(2) == 21nat) by (compute);
1563 assert(pow2(21nat) == 0x20_0000) by (compute);
1564 }
1565 assert(vaddr_make::<NR_LEVELS>(3, path.index(3)) == 0x1000usize * path.index(3))
1566 by (compute);
1567 };
1568 assert(aligned.rec_compute_vaddr(4) == 0);
1569 assert(aligned.rec_compute_vaddr(3) == self.index[3] * 0x80_0000_0000usize) by {
1570 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1571 + aligned.rec_compute_vaddr(4)) as Vaddr);
1572 };
1573 assert(aligned.rec_compute_vaddr(2) == self.index[2] * 0x4000_0000usize + self.index[3]
1574 * 0x80_0000_0000usize);
1575 assert(aligned.compute_vaddr() == self.index[0] * 0x1000usize + self.index[1]
1576 * 0x20_0000usize + self.index[2] * 0x4000_0000usize + self.index[3]
1577 * 0x80_0000_0000usize) by {
1578 assert(aligned.compute_vaddr() == (aligned.index[0] * page_size(1)
1579 + aligned.rec_compute_vaddr(1)) as Vaddr);
1580 };
1581 assert(vaddr(path) == aligned.compute_vaddr());
1582 }
1583 }
1584
1585 pub proof fn rec_compute_vaddr_is_to_vaddr_indices(self, start: int)
1589 requires
1590 self.inv(),
1591 0 <= start <= NR_LEVELS,
1592 ensures
1593 self.rec_compute_vaddr(start) == self.to_vaddr_indices(start) + self.offset,
1594 decreases NR_LEVELS - start,
1595 {
1596 vstd::arithmetic::power2::lemma2_to64();
1597 vstd::arithmetic::power2::lemma2_to64_rest();
1598 lemma_page_size_spec_values();
1599 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1600 self.to_vaddr_indices_gap_bound(start);
1601 if start < NR_LEVELS {
1602 self.rec_compute_vaddr_is_to_vaddr_indices(start + 1);
1603 self.to_vaddr_indices_gap_bound(start + 1);
1604 assert(self.index.contains_key(start));
1605 if start == 0 {
1609 assert(page_size(1) == pow2(12nat) as usize);
1610 } else if start == 1 {
1611 assert(page_size(2) == pow2(21nat) as usize);
1612 } else if start == 2 {
1613 assert(page_size(3) == pow2(30nat) as usize);
1614 } else {
1615 assert(page_size(4) == pow2(39nat) as usize);
1616 }
1617 }
1618 }
1619
1620 pub proof fn to_vaddr_is_compute_vaddr(self)
1627 requires
1628 self.inv(),
1629 ensures
1630 self.to_vaddr() == self.compute_vaddr() + self.leading_bits * 0x1_0000_0000_0000int,
1631 {
1632 self.to_vaddr_bounded();
1633 self.rec_compute_vaddr_is_to_vaddr_indices(0);
1634 }
1635
1636 pub proof fn to_vaddr_indices_gap_bound(self, start: int)
1637 requires
1638 self.inv(),
1639 0 <= start <= NR_LEVELS,
1640 ensures
1641 0 <= self.to_vaddr_indices(start),
1642 self.to_vaddr_indices(start) + pow2((12 + 9 * start) as nat) <= pow2(
1643 (12 + 9 * NR_LEVELS) as nat,
1644 ),
1645 decreases NR_LEVELS - start,
1646 {
1647 vstd::arithmetic::power2::lemma2_to64();
1648 vstd::arithmetic::power2::lemma2_to64_rest();
1649 vstd::arithmetic::power2::lemma_pow2_pos((12 + 9 * start) as nat);
1650 if start == NR_LEVELS {
1651 } else {
1652 let shift = pow2((12 + 9 * start) as nat) as int;
1653 let next_shift = pow2((12 + 9 * (start + 1)) as nat) as int;
1654 let top = pow2((12 + 9 * NR_LEVELS) as nat) as int;
1655 self.to_vaddr_indices_gap_bound(start + 1);
1656 assert(self.index.contains_key(start));
1657 vstd::arithmetic::power2::lemma_pow2_adds((12 + 9 * start) as nat, 9nat);
1658 vstd::arithmetic::mul::lemma_mul_inequality(self.index[start] + 1, 0x200int, shift);
1659 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1660 shift,
1661 self.index[start],
1662 1,
1663 );
1664 }
1665 }
1666
1667 pub proof fn to_vaddr_bounded(self)
1668 requires
1669 self.inv(),
1670 ensures
1671 0 <= self.offset + self.to_vaddr_indices(0) < 0x1_0000_0000_0000int,
1672 self.to_vaddr() == self.offset + self.to_vaddr_indices(0) + self.leading_bits
1673 * 0x1_0000_0000_0000int,
1674 self.offset + self.to_vaddr_indices(0) + self.leading_bits * 0x1_0000_0000_0000int
1675 < 0x1_0000_0000_0000_0000int,
1676 {
1677 vstd::arithmetic::power2::lemma2_to64();
1678 vstd::arithmetic::power2::lemma2_to64_rest();
1679 self.to_vaddr_indices_gap_bound(0);
1680 assert(pow2((12 + 9 * NR_LEVELS) as nat) == 0x1_0000_0000_0000int) by (compute);
1681 assert(self.leading_bits * 0x1_0000_0000_0000int + 0x1_0000_0000_0000int <= 0x1_0000
1682 * 0x1_0000_0000_0000int) by (nonlinear_arith)
1683 requires
1684 0 <= self.leading_bits < 0x1_0000int,
1685 ;
1686 assert(0x1_0000 * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int) by (compute);
1687 }
1688
1689 #[verifier::spinoff_prover]
1690 pub proof fn index_increment_adds_page_size(self, level: int)
1691 requires
1692 self.inv(),
1693 1 <= level <= NR_LEVELS,
1694 self.index[level - 1] + 1 < NR_ENTRIES,
1695 ensures
1696 (Self {
1697 index: self.index.insert(level - 1, self.index[level - 1] + 1),
1698 ..self
1699 }).to_vaddr() == self.to_vaddr() + page_size(level as PagingLevel),
1700 {
1701 let new_va = Self {
1702 index: self.index.insert(level - 1, self.index[level - 1] + 1),
1703 ..self
1704 };
1705 assert forall|i: int| #![trigger new_va.index.contains_key(i)] 0 <= i < NR_LEVELS implies {
1706 &&& new_va.index.contains_key(i)
1707 &&& 0 <= new_va.index[i]
1708 &&& new_va.index[i] < NR_ENTRIES
1709 } by {
1710 assert(self.index.contains_key(i));
1711 };
1712 self.to_vaddr_bounded();
1713 new_va.to_vaddr_bounded();
1714 assert(new_va.to_vaddr() - self.to_vaddr() == new_va.to_vaddr_indices(0)
1715 - self.to_vaddr_indices(0));
1716 vstd::arithmetic::power2::lemma2_to64();
1717 vstd::arithmetic::power2::lemma2_to64_rest();
1718 if level == 1 {
1719 lemma_page_size_spec_level1();
1720 new_va.to_vaddr_indices_eq_if_indices_eq(self, 1);
1721 assert((self.index[0] + 1) * 0x1000 == self.index[0] * 0x1000 + 0x1000)
1722 by (nonlinear_arith);
1723 } else if level == 2 {
1724 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1725 new_va.to_vaddr_indices_eq_if_indices_eq(self, 2);
1726 assert(self.to_vaddr_indices(0) == self.index[0] * pow2(12nat) + self.to_vaddr_indices(
1727 1,
1728 ));
1729 assert((self.index[1] + 1) * 0x20_0000 == self.index[1] * 0x20_0000 + 0x20_0000)
1730 by (nonlinear_arith);
1731 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x20_0000);
1732 } else if level == 3 {
1733 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1734 new_va.to_vaddr_indices_eq_if_indices_eq(self, 3);
1735 assert(self.index.contains_key(2));
1736 assert(new_va.index.contains_key(2));
1737 assert((12 + 9 * 2) as nat == 30nat) by (compute);
1738 assert((self.index[2] + 1) * 0x4000_0000 == self.index[2] * 0x4000_0000 + 0x4000_0000)
1739 by (nonlinear_arith);
1740 assert(new_va.to_vaddr_indices(2) == self.to_vaddr_indices(2) + 0x4000_0000);
1741 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x4000_0000);
1742 } else {
1743 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
1744 new_va.to_vaddr_indices_eq_if_indices_eq(self, 4);
1745 assert(self.to_vaddr_indices(1) == self.index[1] * pow2(21nat) + self.to_vaddr_indices(
1746 2,
1747 ));
1748 assert(self.to_vaddr_indices(2) == self.index[2] * pow2(30nat) + self.to_vaddr_indices(
1749 3,
1750 ));
1751 assert((self.index[3] + 1) * 0x80_0000_0000 == self.index[3] * 0x80_0000_0000
1752 + 0x80_0000_0000) by (nonlinear_arith);
1753 assert(new_va.to_vaddr_indices(3) == self.to_vaddr_indices(3) + 0x80_0000_0000);
1754 assert(new_va.to_vaddr_indices(2) == self.to_vaddr_indices(2) + 0x80_0000_0000);
1755 assert(new_va.to_vaddr_indices(1) == self.to_vaddr_indices(1) + 0x80_0000_0000);
1756 }
1757 }
1758
1759 pub proof fn to_path_len(self, level: int)
1761 requires
1762 0 <= level < NR_LEVELS,
1763 ensures
1764 self.to_path(level).len() == NR_LEVELS - level,
1765 {
1766 self.rec_to_path_len(NR_LEVELS - 1, level);
1767 }
1768
1769 proof fn rec_to_path_len(self, abstract_level: int, bottom_level: int)
1770 requires
1771 bottom_level <= abstract_level,
1772 ensures
1773 self.rec_to_path(abstract_level, bottom_level).len() == abstract_level - bottom_level
1774 + 1,
1775 decreases abstract_level - bottom_level,
1776 {
1777 if abstract_level > bottom_level {
1782 self.rec_to_path_len(abstract_level - 1, bottom_level);
1783 }
1784 }
1787
1788 pub proof fn to_path_inv(self, level: int)
1790 requires
1791 self.inv(),
1792 0 <= level < NR_LEVELS,
1793 ensures
1794 self.to_path(level).inv(),
1795 {
1796 self.to_path_len(level);
1797 assert forall|i: int| 0 <= i < self.to_path(level).len() implies TreePath::<
1798 NR_ENTRIES,
1799 >::elem_inv(#[trigger] self.to_path(level).index(i)) by {
1800 let j = NR_LEVELS - 1 - i;
1801 self.to_path_index(level, i);
1802 assert(self.index.contains_key(j));
1803 };
1804 }
1805}
1806
1807impl AbstractVaddr {
1809 proof fn rec_vaddr_eq_if_indices_eq(
1810 path1: TreePath<NR_ENTRIES>,
1811 path2: TreePath<NR_ENTRIES>,
1812 idx: int,
1813 )
1814 requires
1815 path1.inv(),
1816 path2.inv(),
1817 path1.len() == path2.len(),
1818 0 <= idx <= path1.len(),
1819 forall|i: int| idx <= i < path1.len() ==> path1.index(i) == path2.index(i),
1820 ensures
1821 rec_vaddr(path1, idx) == rec_vaddr(path2, idx),
1822 decreases path1.len() - idx,
1823 {
1824 if idx < path1.len() {
1825 path1.index_satisfies_elem_inv(idx);
1826 path2.index_satisfies_elem_inv(idx);
1827 Self::rec_vaddr_eq_if_indices_eq(path1, path2, idx + 1);
1828 }
1829 }
1830
1831 pub proof fn path_matches_vaddr(self, path: TreePath<NR_ENTRIES>)
1834 requires
1835 self.inv(),
1836 path.inv(),
1837 path.len() <= NR_LEVELS,
1838 forall|i: int| 0 <= i < path.len() ==> path.index(i) == self.index[NR_LEVELS - 1 - i],
1839 ensures
1840 vaddr(path) == self.align_down(NR_LEVELS - path.len() + 1).compute_vaddr()
1841 - self.align_down(NR_LEVELS - path.len() + 1).offset,
1842 {
1843 if path.len() == 0 {
1844 let aligned = self.align_down(5);
1845 self.align_down_shape(4);
1846 assert(aligned.index[3] == 0) by {
1848 assert(aligned == AbstractVaddr {
1849 index: self.align_down(4).index.insert(3, 0),
1850 ..self.align_down(4)
1851 });
1852 };
1853 assert(aligned.rec_compute_vaddr(4) == 0);
1854 assert(aligned.rec_compute_vaddr(3) == 0) by {
1855 assert(aligned.rec_compute_vaddr(3) == (aligned.index[3] * page_size(4)
1856 + aligned.rec_compute_vaddr(4)) as Vaddr);
1857 };
1858 assert(aligned.rec_compute_vaddr(2) == 0) by {
1859 assert(aligned.rec_compute_vaddr(2) == (aligned.index[2] * page_size(3)
1860 + aligned.rec_compute_vaddr(3)) as Vaddr);
1861 };
1862 assert(aligned.rec_compute_vaddr(1) == 0) by {
1863 assert(aligned.rec_compute_vaddr(1) == (aligned.index[1] * page_size(2)
1864 + aligned.rec_compute_vaddr(2)) as Vaddr);
1865 };
1866 } else {
1867 let level = NR_LEVELS - path.len();
1868 self.to_path_inv(level);
1869 self.to_path_len(level);
1870 assert forall|i: int| 0 <= i < path.len() implies #[trigger] path.index(i)
1871 == self.to_path(level).index(i) by {
1872 self.to_path_index(level, i);
1873 };
1874 Self::rec_vaddr_eq_if_indices_eq(path, self.to_path(level), 0);
1875 self.to_path_vaddr(level);
1876 self.align_down_shape(level + 1);
1877 }
1878 }
1879
1880 pub proof fn to_path_index(self, level: int, i: int)
1883 requires
1884 self.inv(),
1885 0 <= level < NR_LEVELS,
1886 0 <= i < NR_LEVELS - level,
1887 ensures
1888 self.to_path(level).index(i) == self.index[NR_LEVELS - 1 - i],
1889 {
1890 self.to_path_len(level);
1891 self.rec_to_path_index(NR_LEVELS - 1, level, i);
1892 }
1893
1894 proof fn rec_to_path_index(self, abstract_level: int, bottom_level: int, i: int)
1895 requires
1896 self.inv(),
1897 0 <= bottom_level <= abstract_level < NR_LEVELS,
1898 0 <= i < abstract_level - bottom_level + 1,
1899 ensures
1900 self.rec_to_path(abstract_level, bottom_level).index(i) == self.index[abstract_level
1901 - i],
1902 decreases abstract_level - bottom_level,
1903 {
1904 assert(self.index.contains_key(abstract_level));
1905 if abstract_level == bottom_level {
1906 } else {
1907 let head = seq![self.index[abstract_level] as usize];
1908 let tail = self.rec_to_path(abstract_level - 1, bottom_level);
1909 let full = head.add(tail);
1910 if i == 0 {
1911 } else {
1912 self.rec_to_path_index(abstract_level - 1, bottom_level, i - 1);
1913 assert(0 <= i - 1 < tail.len()) by {
1914 self.rec_to_path_len(abstract_level - 1, bottom_level);
1915 };
1916 }
1917 }
1918 }
1919
1920 pub proof fn to_path_vaddr_concrete(self, level: int)
1925 requires
1926 self.inv(),
1927 0 <= level < NR_LEVELS,
1928 ensures
1929 vaddr(self.to_path(level)) + self.leading_bits * 0x1_0000_0000_0000int
1930 == nat_align_down(
1931 self.to_vaddr() as nat,
1932 page_size((level + 1) as PagingLevel) as nat,
1933 ),
1934 {
1935 self.to_path_vaddr(level);
1936 let aligned = self.align_down(level + 1);
1937 self.align_down_shape(level + 1);
1938 aligned.to_vaddr_is_compute_vaddr();
1939 self.align_down_concrete(level + 1);
1940 aligned.reflect_prop(
1941 nat_align_down(
1942 self.to_vaddr() as nat,
1943 page_size((level + 1) as PagingLevel) as nat,
1944 ) as Vaddr,
1945 );
1946 self.align_down_leading_bits(level + 1);
1947 let nad = nat_align_down(
1953 self.to_vaddr() as nat,
1954 page_size((level + 1) as PagingLevel) as nat,
1955 );
1956 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1959 vstd_extra::arithmetic::lemma_nat_align_down_sound(
1960 self.to_vaddr() as nat,
1961 page_size((level + 1) as PagingLevel) as nat,
1962 );
1963 assert(aligned.leading_bits == self.leading_bits);
1964 assert(vaddr(self.to_path(level)) == aligned.compute_vaddr());
1965 assert(aligned.to_vaddr() == aligned.compute_vaddr() + aligned.leading_bits
1966 * 0x1_0000_0000_0000int);
1967 assert(aligned.to_vaddr() == nad as Vaddr);
1968 assert(aligned.to_vaddr() == nad);
1969 }
1970
1971 pub proof fn vaddr_range_from_path(self, level: int)
1974 requires
1975 self.inv(),
1976 0 <= level < NR_LEVELS,
1977 ensures
1978 vaddr(self.to_path(level)) + self.leading_bits * 0x1_0000_0000_0000int
1979 <= self.to_vaddr(),
1980 self.to_vaddr() < vaddr(self.to_path(level)) + self.leading_bits * 0x1_0000_0000_0000int
1981 + page_size((level + 1) as PagingLevel),
1982 {
1983 self.to_path_vaddr_concrete(level);
1984 let size = page_size((level + 1) as PagingLevel);
1985 let cur = self.to_vaddr() as nat;
1986 let start = vaddr(self.to_path(level));
1987
1988 assert(page_size((level + 1) as PagingLevel) >= PAGE_SIZE) by {
1989 lemma_page_size_ge_page_size((level + 1) as PagingLevel);
1990 };
1991 lemma_nat_align_down_sound(cur, size as nat);
1992 }
1993}
1994
1995}