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
10use vstd::{
11 arithmetic::{
12 div_mod::{
13 lemma_div_denominator, lemma_fundamental_div_mod, lemma_fundamental_div_mod_converse,
14 },
15 mul::lemma_mul_inequality,
16 power2::{lemma_pow2_pos, pow2},
17 },
18 bits::{lemma_usize_low_bits_mask_is_mod, lemma_usize_shr_is_div},
19 prelude::*,
20 std_specs::range::RangeInclusiveView,
21};
22use vstd_extra::{
23 arithmetic::*, external::ilog2::lemma_usize_is_pow2_is_ilog2_pow2, ownership::*, prelude::*,
24};
25
26use crate::specs::arch::*;
27
28use crate::mm::{
29 PagingConsts, PagingConstsTrait, PagingLevel, Vaddr, kspace::KernelPtConfig,
30 nr_subpage_per_huge, page_size, page_table::PageTableConfig, vm_space::UserPtConfig,
31};
32use align_ext::AlignExt;
33use core::ops::Range;
34pub use cursor::*;
35pub use node::*;
36pub use owners::*;
37pub use view::*;
38
39verus! {
40
41#[verifier::inline]
42pub open spec fn nr_pte_index_bits_spec<C: PagingConstsTrait>() -> usize {
43 nr_subpage_per_huge::<C>().ilog2() as usize
44}
45
46#[verifier::inline]
47pub open spec fn pte_index_bit_offset_spec<C: PagingConstsTrait>(level: PagingLevel) -> usize {
48 (C::BASE_PAGE_SIZE().ilog2() + nr_pte_index_bits_spec::<C>() * (level - 1)) as usize
49}
50
51#[verifier::inline]
53pub open spec fn pte_index_spec<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel) -> usize {
54 (va >> pte_index_bit_offset_spec::<C>(level)) & ((nr_subpage_per_huge::<C>() - 1) as usize)
55}
56
57pub proof fn lemma_pte_index_spec_is_div_mod<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
59 requires
60 1 <= level <= C::NR_LEVELS(),
61 ensures
62 pte_index_spec::<C>(va, level) == (va / page_size::<C>(level)) % nr_subpage_per_huge::<C>(),
63{
64 C::lemma_paging_consts_properties();
65 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(level);
66 let bits = nr_pte_index_bits_spec::<C>();
67 lemma_mul_inequality(1, C::NR_LEVELS() as int, bits as int);
68 lemma_usize_is_pow2_is_ilog2_pow2(nr_subpage_per_huge::<C>());
69 lemma_usize_shr_is_div(va, pte_index_bit_offset_spec::<C>(level));
70 lemma_usize_low_bits_mask_is_mod(va >> pte_index_bit_offset_spec::<C>(level), bits as nat);
71}
72
73pub proof fn lemma_pte_index_bound<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
75 requires
76 1 <= level <= C::NR_LEVELS(),
77 ensures
78 pte_index_spec::<C>(va, level) < nr_subpage_per_huge::<C>(),
79{
80 lemma_pte_index_spec_is_div_mod::<C>(va, level);
81 C::lemma_paging_consts_properties();
82 vstd::arithmetic::div_mod::lemma_mod_bound(
83 va as int / page_size::<C>(level) as int,
84 nr_subpage_per_huge::<C>() as int,
85 );
86}
87
88pub proof fn lemma_lower_indices_aligned<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
90 requires
91 1 <= level <= C::NR_LEVELS() + 1,
92 va % C::BASE_PAGE_SIZE() == 0,
93 forall|i: int| 1 <= i < level ==> #[trigger] pte_index_spec::<C>(va, i as PagingLevel) == 0,
94 ensures
95 va % page_size::<C>(level) == 0,
96 decreases level,
97{
98 C::lemma_paging_consts_properties();
99 lemma_page_size_base::<C>();
100 if level > 1 {
101 let lower = (level - 1) as PagingLevel;
102 lemma_lower_indices_aligned::<C>(va, lower);
103 lemma_page_size_next::<C>(lower);
104 lemma_pte_index_spec_is_div_mod::<C>(va, lower);
105 assert(pte_index_spec::<C>(va, lower) == 0);
106 vstd::arithmetic::div_mod::lemma_mod_breakdown(
107 va as int,
108 page_size::<C>(lower) as int,
109 nr_subpage_per_huge::<C>() as int,
110 );
111 vstd::arithmetic::mul::lemma_mul_basics(page_size::<C>(lower) as int);
112 assert(va % page_size::<C>(level) == 0);
113 } else {
114 assert(page_size::<C>(level) == C::BASE_PAGE_SIZE());
115 }
116}
117
118pub proof fn lemma_aligned_indices_zero<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
120 requires
121 1 <= level <= C::NR_LEVELS() + 1,
122 va % page_size::<C>(level) == 0,
123 ensures
124 va % C::BASE_PAGE_SIZE() == 0,
125 forall|i: int| 1 <= i < level ==> #[trigger] pte_index_spec::<C>(va, i as PagingLevel) == 0,
126 decreases level,
127{
128 C::lemma_paging_consts_properties();
129 lemma_page_size_base::<C>();
130 if level > 1 {
131 let lower = (level - 1) as PagingLevel;
132 lemma_page_size_next::<C>(lower);
133 let size = page_size::<C>(lower) as int;
134 let fanout = nr_subpage_per_huge::<C>() as int;
135 vstd::arithmetic::div_mod::lemma_mod_mod(va as int, size, fanout);
136 lemma_pte_index_spec_is_div_mod::<C>(va, lower);
137 vstd::arithmetic::div_mod::lemma_mod_breakdown(va as int, size, fanout);
138 vstd::arithmetic::div_mod::lemma_mod_bound(va as int / size, fanout);
139 assert(pte_index_spec::<C>(va, lower) == 0) by (nonlinear_arith)
140 requires
141 size > 0,
142 0 <= va as int / size % fanout,
143 size * (va as int / size % fanout) == 0,
144 pte_index_spec::<C>(va, lower) == va as int / size % fanout,
145 ;
146 lemma_aligned_indices_zero::<C>(va, lower);
147 } else {
148 assert(page_size::<C>(level) == C::BASE_PAGE_SIZE());
149 }
150}
151
152pub proof fn lemma_aligned_vaddr_slack<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
154 requires
155 1 <= level <= C::NR_LEVELS() + 1,
156 va % page_size::<C>(level) == 0,
157 ensures
158 va + page_size::<C>(level) <= usize::MAX + 1,
159{
160 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(level);
161 let size = page_size::<C>(level);
162 vstd::bits::lemma_usize_low_bits_mask_is_mod(
163 usize::MAX,
164 pte_index_bit_offset_spec::<C>(level) as nat,
165 );
166 vstd::bits::lemma_low_bits_mask_values();
167 assert(usize::MAX & ((size - 1) as usize) == (size - 1) as usize) by (bit_vector);
168 assert(usize::MAX % size == size - 1);
169 lemma_fundamental_div_mod(va as int, size as int);
170 lemma_fundamental_div_mod(usize::MAX as int, size as int);
171 vstd::arithmetic::div_mod::lemma_div_is_ordered(va as int, usize::MAX as int, size as int);
172 vstd::arithmetic::mul::lemma_mul_inequality(
173 va as int / size as int,
174 usize::MAX as int / size as int,
175 size as int,
176 );
177 assert(va + size <= usize::MAX + 1) by (nonlinear_arith)
178 requires
179 va == (size as int) * (va as int / size as int),
180 usize::MAX == (size as int) * (usize::MAX as int / size as int) + size - 1,
181 0 < size,
182 va as int / size as int <= usize::MAX as int / size as int,
183 ;
184}
185
186pub proof fn lemma_next_slot_pte_index<C: PagingConstsTrait>(
188 va: Vaddr,
189 next: Vaddr,
190 level: PagingLevel,
191)
192 requires
193 1 <= level <= C::NR_LEVELS(),
194 va < next <= va + page_size::<C>(level),
195 next % page_size::<C>(level) == 0,
196 ensures
197 next == (nat_align_down(va as nat, page_size::<C>(level) as nat) + page_size::<C>(
198 level,
199 )) as Vaddr,
200 pte_index_spec::<C>(next, level) == 0 ==> {
201 &&& pte_index_spec::<C>(va, level) + 1 == nr_subpage_per_huge::<C>()
202 &&& next % page_size::<C>((level + 1) as PagingLevel) == 0
203 },
204 pte_index_spec::<C>(next, level) != 0 ==> pte_index_spec::<C>(va, level) + 1
205 < nr_subpage_per_huge::<C>(),
206{
207 C::lemma_paging_consts_properties();
208 lemma_pte_index_spec_is_div_mod::<C>(va, level);
209 lemma_pte_index_spec_is_div_mod::<C>(next, level);
210 lemma_page_size_next::<C>(level);
211 let size = page_size::<C>(level) as int;
212 let fanout = nr_subpage_per_huge::<C>() as int;
213 let quotient = next as int / size;
214 let diff = next - va;
215 lemma_fundamental_div_mod(next as int, size);
216 vstd::arithmetic::mul::lemma_mul_basics(size);
217 vstd::arithmetic::mul::lemma_mul_is_distributive_sub_other_way(size, quotient, 1);
218 lemma_fundamental_div_mod_converse(va as int, size, quotient - 1, size - diff);
219 vstd::arithmetic::div_mod::lemma_mod_bound(va as int / size, fanout);
220 vstd::arithmetic::div_mod::lemma_add_mod_noop_right(1, va as int / size, fanout);
221 let index = pte_index_spec::<C>(va, level) as int;
222 if index + 1 < fanout {
223 vstd::arithmetic::div_mod::lemma_small_mod((index + 1) as nat, fanout as nat);
224 } else {
225 vstd::arithmetic::div_mod::lemma_mod_self_0(fanout);
226 }
227 if pte_index_spec::<C>(next, level) == 0 {
228 vstd::arithmetic::div_mod::lemma_mod_breakdown(next as int, size, fanout);
229 vstd::arithmetic::mul::lemma_mul_basics(size);
230 }
231}
232
233pub open spec fn vaddr_replace_pte_index_spec<C: PagingConstsTrait>(
235 va: Vaddr,
236 level: PagingLevel,
237 index: int,
238) -> Vaddr {
239 (va as int + (index - pte_index_spec::<C>(va, level)) * page_size::<C>(level)) as Vaddr
240}
241
242#[verifier::inline]
245pub open spec fn page_table_vaddr_bits_spec<C: PagingConstsTrait>() -> usize {
246 pte_index_bit_offset_spec::<C>((C::NR_LEVELS() + 1) as PagingLevel)
247}
248
249#[verifier::inline]
251pub open spec fn vaddr_upper_bits_spec<C: PagingConstsTrait>(va: Vaddr) -> usize {
252 va >> page_table_vaddr_bits_spec::<C>()
253}
254
255#[verifier::inline]
258pub open spec fn vaddr_upper_part_spec<C: PagingConstsTrait>(va: Vaddr) -> int {
259 vaddr_upper_bits_spec::<C>(va) as int * pow2(page_table_vaddr_bits_spec::<C>() as nat) as int
260}
261
262#[verifier::inline]
263pub open spec fn top_level_index_width_spec<C: PageTableConfig>() -> usize {
264 (C::ADDRESS_WIDTH_spec() - pte_index_bit_offset_spec::<C>(C::NR_LEVELS())) as usize
265}
266
267#[verusfmt::skip]
274pub open spec fn vaddr_range_spec<C: PageTableConfig>() -> RangeInclusiveView<Vaddr> {
275 let off = pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat;
276 let lb = C::LEADING_BITS_spec() as int;
277 let base = lb * 0x1_0000_0000_0000int;
278 let start = (base + (C::TOP_LEVEL_INDEX_RANGE().start) * pow2(off)) as usize;
279 let end = (base + (C::TOP_LEVEL_INDEX_RANGE().end) * pow2(off) - 1) as usize;
280 RangeInclusiveView { start, end, exhausted: false }
281}
282
283pub open spec fn is_valid_range_spec<C: PageTableConfig>(r: Range<Vaddr>) -> bool {
284 let va_range = vaddr_range_spec::<C>();
285 (r.start == 0 && r.end == 0) || (va_range.start <= r.start && r.end - 1 <= va_range.end)
286}
287
288pub(crate) proof fn lemma_vaddr_range_spec_user()
291 ensures
292 vaddr_range_spec::<UserPtConfig>().start == 0,
293 vaddr_range_spec::<UserPtConfig>().end == 0x0000_7FFF_FFFF_FFFF,
294{
295 lemma_arch_specific_consts_properties::<PagingConsts>();
296}
297
298pub(crate) proof fn lemma_vaddr_range_spec_kernel()
301 ensures
302 vaddr_range_spec::<KernelPtConfig>().start == 0xFFFF_8000_0000_0000,
303 vaddr_range_spec::<KernelPtConfig>().end == 0xFFFF_FFFF_FFFF_FFFF,
304{
305 lemma_arch_specific_consts_properties::<PagingConsts>();
306}
307
308pub proof fn lemma_same_node_pte_indices_match<C: PagingConstsTrait>(
310 va1: Vaddr,
311 va2: Vaddr,
312 node_start: Vaddr,
313 level: PagingLevel,
314)
315 requires
316 level < C::NR_LEVELS(),
317 node_start <= va1,
318 va1 < node_start + page_size::<C>((level + 1) as PagingLevel),
319 node_start <= va2,
320 va2 < node_start + page_size::<C>((level + 1) as PagingLevel),
321 node_start as nat % page_size::<C>((level + 1) as PagingLevel) as nat == 0,
322 ensures
323 pte_index_spec::<C>(va1, (level + 1) as PagingLevel) == pte_index_spec::<C>(
324 va2,
325 (level + 1) as PagingLevel,
326 ),
327 forall|i: int|
328 level <= i < C::NR_LEVELS() ==> (#[trigger] pte_index_spec::<C>(
329 va1,
330 (i + 1) as PagingLevel,
331 )) == pte_index_spec::<C>(va2, (i + 1) as PagingLevel),
332{
333 C::lemma_paging_consts_properties();
334 let small_level = (level + 1) as PagingLevel;
335 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(small_level);
336 let small = page_size::<C>(small_level) as int;
337 let quotient = node_start as int / small;
338 lemma_fundamental_div_mod(node_start as int, small);
339 lemma_fundamental_div_mod_converse(va1 as int, small, quotient, va1 - node_start);
340 lemma_fundamental_div_mod_converse(va2 as int, small, quotient, va2 - node_start);
341 lemma_pte_index_spec_is_div_mod::<C>(va1, small_level);
342 lemma_pte_index_spec_is_div_mod::<C>(va2, small_level);
343
344 assert forall|i: int| level <= i < C::NR_LEVELS() implies (#[trigger] pte_index_spec::<C>(
345 va1,
346 (i + 1) as PagingLevel,
347 )) == pte_index_spec::<C>(va2, (i + 1) as PagingLevel) by {
348 let large_level = (i + 1) as PagingLevel;
349 lemma_page_size_ratio::<C>(small_level, large_level);
350 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(large_level);
351 let delta = (nr_pte_index_bits_spec::<C>() * (i - level)) as nat;
352 lemma_pow2_pos(delta);
353 let ratio = pow2(delta) as int;
354 lemma_div_denominator(va1 as int, small, ratio);
355 lemma_div_denominator(va2 as int, small, ratio);
356 lemma_pte_index_spec_is_div_mod::<C>(va1, large_level);
357 lemma_pte_index_spec_is_div_mod::<C>(va2, large_level);
358 };
359}
360
361pub proof fn lemma_same_node_vaddr_upper_bits_match<C: PagingConstsTrait>(
364 va1: Vaddr,
365 va2: Vaddr,
366 node_start: Vaddr,
367 level: PagingLevel,
368)
369 requires
370 level <= C::NR_LEVELS(),
371 node_start <= va1,
372 va1 - node_start < page_size::<C>((level + 1) as PagingLevel),
373 node_start <= va2,
374 va2 - node_start < page_size::<C>((level + 1) as PagingLevel),
375 node_start as nat % page_size::<C>((level + 1) as PagingLevel) as nat == 0,
376 ensures
377 vaddr_upper_bits_spec::<C>(va1) == vaddr_upper_bits_spec::<C>(va2),
378{
379 C::lemma_paging_consts_properties();
380 let small_level = (level + 1) as PagingLevel;
381 let body_level = (C::NR_LEVELS() + 1) as PagingLevel;
382 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(small_level);
383 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(body_level);
384 let small = page_size::<C>(small_level) as int;
385 let quotient = node_start as int / small;
386 lemma_fundamental_div_mod(node_start as int, small);
387 lemma_fundamental_div_mod_converse(va1 as int, small, quotient, va1 - node_start);
388 lemma_fundamental_div_mod_converse(va2 as int, small, quotient, va2 - node_start);
389 let delta = (nr_pte_index_bits_spec::<C>() * (C::NR_LEVELS() - level)) as nat;
390 lemma_page_size_ratio::<C>(small_level, body_level);
391 lemma_pow2_pos(delta);
392 let ratio = pow2(delta) as int;
393 lemma_div_denominator(va1 as int, small, ratio);
394 lemma_div_denominator(va2 as int, small, ratio);
395 lemma_usize_shr_is_div(va1, page_table_vaddr_bits_spec::<C>());
396 lemma_usize_shr_is_div(va2, page_table_vaddr_bits_spec::<C>());
397}
398
399pub proof fn lemma_vaddr_upper_part_is_align_down<C: PagingConstsTrait>(va: Vaddr)
401 ensures
402 vaddr_upper_part_spec::<C>(va) == nat_align_down(
403 va as nat,
404 page_size::<C>((C::NR_LEVELS() + 1) as PagingLevel) as nat,
405 ),
406{
407 C::lemma_paging_consts_properties();
408 let level = (C::NR_LEVELS() + 1) as PagingLevel;
409 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(level);
410 lemma_usize_shr_is_div(va, page_table_vaddr_bits_spec::<C>());
411 lemma_fundamental_div_mod(va as int, page_size::<C>(level) as int);
412 vstd::arithmetic::mul::lemma_mul_is_commutative(
413 page_size::<C>(level) as int,
414 vaddr_upper_bits_spec::<C>(va) as int,
415 );
416}
417
418pub proof fn lemma_align_down_indices<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
420 requires
421 1 <= level <= C::NR_LEVELS(),
422 ensures
423 ({
424 let aligned = nat_align_down(va as nat, page_size::<C>(level) as nat) as Vaddr;
425 &&& aligned % C::BASE_PAGE_SIZE() == 0
426 &&& vaddr_upper_bits_spec::<C>(aligned) == vaddr_upper_bits_spec::<C>(va)
427 &&& forall|i: int|
428 1 <= i <= C::NR_LEVELS() ==> #[trigger] pte_index_spec::<C>(
429 aligned,
430 i as PagingLevel,
431 ) == if i < level {
432 0
433 } else {
434 pte_index_spec::<C>(va, i as PagingLevel)
435 }
436 }),
437{
438 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(level);
439 let size = page_size::<C>(level) as nat;
440 lemma_nat_align_down_sound(va as nat, size);
441 let aligned = nat_align_down(va as nat, size) as Vaddr;
442 lemma_aligned_indices_zero::<C>(aligned, level);
443 lemma_same_node_pte_indices_match::<C>(va, aligned, aligned, (level - 1) as PagingLevel);
444 lemma_same_node_vaddr_upper_bits_match::<C>(va, aligned, aligned, (level - 1) as PagingLevel);
445 assert forall|i: int| 1 <= i <= C::NR_LEVELS() implies #[trigger] pte_index_spec::<C>(
446 aligned,
447 i as PagingLevel,
448 ) == if i < level {
449 0
450 } else {
451 pte_index_spec::<C>(va, i as PagingLevel)
452 } by {
453 if i >= level {
454 assert((level - 1) < i);
455 assert(pte_index_spec::<C>(va, ((i - 1) + 1) as PagingLevel) == pte_index_spec::<C>(
456 aligned,
457 ((i - 1) + 1) as PagingLevel,
458 ));
459 }
460 };
461}
462
463pub proof fn lemma_inc_slot_indices<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
465 requires
466 1 <= level <= C::NR_LEVELS(),
467 pte_index_spec::<C>(va, level) + 1 < nr_subpage_per_huge::<C>(),
468 ensures
469 va + page_size::<C>(level) <= usize::MAX,
470 ({
471 let next = (va + page_size::<C>(level)) as Vaddr;
472 &&& next % C::BASE_PAGE_SIZE() == va % C::BASE_PAGE_SIZE()
473 &&& vaddr_upper_bits_spec::<C>(next) == vaddr_upper_bits_spec::<C>(va)
474 &&& forall|i: int|
475 1 <= i <= C::NR_LEVELS() ==> #[trigger] pte_index_spec::<C>(next, i as PagingLevel)
476 == pte_index_spec::<C>(va, i as PagingLevel) + if i == level {
477 1int
478 } else {
479 0int
480 }
481 }),
482{
483 C::lemma_paging_consts_properties();
484 lemma_page_size_next::<C>(level);
485 lemma_pte_index_spec_is_div_mod::<C>(va, level);
486 let size = page_size::<C>(level) as int;
487 let parent_size = page_size::<C>((level + 1) as PagingLevel) as int;
488 let fanout = nr_subpage_per_huge::<C>() as int;
489 let index = pte_index_spec::<C>(va, level) as int;
490 lemma_nat_align_down_sound(va as nat, parent_size as nat);
491 let start = nat_align_down(va as nat, parent_size as nat) as Vaddr;
492 lemma_aligned_vaddr_slack::<C>(start, (level + 1) as PagingLevel);
493 vstd::arithmetic::div_mod::lemma_mod_breakdown(va as int, size, fanout);
494 vstd::arithmetic::div_mod::lemma_mod_bound(va as int, size);
495 assert(index == va as int / size % fanout);
496 assert(va as int % parent_size == size * index + va as int % size);
497 vstd::arithmetic::div_mod::lemma_mod_bound(va as int, parent_size);
498 vstd::arithmetic::div_mod::lemma_div_pos_is_pos(va as int, parent_size);
499 lemma_fundamental_div_mod(va as int, parent_size);
500 assert(va - start == va as int % parent_size);
501 assert(va - start + size < parent_size) by (nonlinear_arith)
502 requires
503 va - start == size * index + va as int % size,
504 0 <= va as int % size < size,
505 index + 1 < fanout,
506 parent_size == size * fanout,
507 ;
508 let next = (va + size) as Vaddr;
509 lemma_fundamental_div_mod(va as int, size);
510 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(size, va as int / size, 1);
511 lemma_fundamental_div_mod_converse(next as int, size, va as int / size + 1, va as int % size);
512 lemma_pte_index_spec_is_div_mod::<C>(next, level);
513 vstd::arithmetic::div_mod::lemma_add_mod_noop_right(1, va as int / size, fanout);
514 vstd::arithmetic::div_mod::lemma_small_mod((index + 1) as nat, fanout as nat);
515 assert(pte_index_spec::<C>(next, level) == index + 1);
516 if level < C::NR_LEVELS() {
517 lemma_same_node_pte_indices_match::<C>(va, next, start, level);
518 }
519 lemma_same_node_vaddr_upper_bits_match::<C>(va, next, start, level);
520 lemma_page_size_divides::<C>(1, level);
521 lemma_page_size_base::<C>();
522 vstd::arithmetic::div_mod::lemma_add_mod_noop(va as int, size, C::BASE_PAGE_SIZE() as int);
523 vstd::arithmetic::div_mod::lemma_mod_twice(va as int, C::BASE_PAGE_SIZE() as int);
524 assert(next % C::BASE_PAGE_SIZE() == va % C::BASE_PAGE_SIZE());
525 assert forall|i: int| 1 <= i < level implies #[trigger] pte_index_spec::<C>(
526 next,
527 i as PagingLevel,
528 ) == pte_index_spec::<C>(va, i as PagingLevel) by {
529 let lower = i as PagingLevel;
530 let parent = (i + 1) as PagingLevel;
531 lemma_page_size_divides::<C>(parent, level);
532 lemma_page_size_next::<C>(lower);
533 let small = page_size::<C>(lower) as int;
534 let block = page_size::<C>(parent) as int;
535 vstd::arithmetic::div_mod::lemma_add_mod_noop(va as int, size, block);
536 vstd::arithmetic::div_mod::lemma_mod_twice(va as int, block);
537 assert(next as int % block == va as int % block);
538 vstd::arithmetic::div_mod::lemma_mod_mod(va as int, small, fanout);
539 vstd::arithmetic::div_mod::lemma_mod_mod(next as int, small, fanout);
540 vstd::arithmetic::div_mod::lemma_mod_breakdown(va as int, small, fanout);
541 vstd::arithmetic::div_mod::lemma_mod_breakdown(next as int, small, fanout);
542 lemma_pte_index_spec_is_div_mod::<C>(va, lower);
543 lemma_pte_index_spec_is_div_mod::<C>(next, lower);
544 assert(next as int % small == va as int % small);
545 assert(small * pte_index_spec::<C>(next, lower) == small * pte_index_spec::<C>(va, lower));
546 assert(pte_index_spec::<C>(next, lower) == pte_index_spec::<C>(va, lower))
547 by (nonlinear_arith)
548 requires
549 small > 0,
550 small * pte_index_spec::<C>(next, lower) == small * pte_index_spec::<C>(va, lower),
551 ;
552 };
553 assert forall|i: int| 1 <= i <= C::NR_LEVELS() implies #[trigger] pte_index_spec::<C>(
554 next,
555 i as PagingLevel,
556 ) == pte_index_spec::<C>(va, i as PagingLevel) + if i == level {
557 1int
558 } else {
559 0int
560 } by {
561 if i > level {
562 assert(level < C::NR_LEVELS());
563 assert(pte_index_spec::<C>(va, ((i - 1) + 1) as PagingLevel) == pte_index_spec::<C>(
564 next,
565 ((i - 1) + 1) as PagingLevel,
566 ));
567 }
568 };
569}
570
571}