1use vstd::arithmetic::power2::*;
3use vstd::prelude::*;
4use vstd::simple_pptr;
5use vstd::std_specs::clone::*;
6use vstd_extra::assert;
7use vstd_extra::panic::may_panic;
8use vstd_extra::prelude::*;
9
10use crate::specs::arch::*;
11use crate::specs::mm::page_table::{cursor::*, *};
12use crate::specs::task::InAtomicMode;
13
14use crate::mm::frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED};
15use crate::mm::kspace::kvirt_area::disable_preempt;
16use crate::specs::mm::{
17 frame::{mapping::frame_to_index, meta_owners::MetaPerm, meta_region_owners::MetaRegionOwners},
18 page_table::{
19 is_valid_range_spec, nr_pte_index_bits_spec, pte_index_bit_offset_spec,
20 top_level_index_width_spec, vaddr_range_spec,
21 },
22};
23
24use core::{
25 fmt::Debug,
26 intrinsics::transmute_unchecked,
27 ops::{Range, RangeInclusive},
28 sync::atomic::{AtomicUsize, Ordering},
29};
30
31use super::{
32 Paddr, PagingConstsTrait, PagingLevel, PodOnce, Vaddr,
33 kspace::KernelPtConfig,
34 nr_subpage_per_huge,
35 page_prop::{CachePolicy, PageProperty},
36 page_size,
37 vm_space::UserPtConfig,
38};
39
40use crate::{
41 Pod,
43 arch::mm::{PageTableEntry, PagingConsts},
44};
45
46mod node;
47pub use node::*;
48mod cursor;
49
50pub(crate) use cursor::*;
51
52#[cfg(ktest)]
53mod test;
54
55verus! {
58
59#[derive(Clone, Copy, PartialEq, Eq, Debug)]
60pub enum PageTableError {
61 InvalidVaddrRange(Vaddr, Vaddr),
63 InvalidVaddr(Vaddr),
65 UnalignedVaddr,
67}
68
69pub trait RCClone: Sized {
70 spec fn clone_requires(self, perm: MetaRegionOwners) -> bool;
71
72 spec fn clone_ensures(
73 self,
74 old_perm: MetaRegionOwners,
75 new_perm: MetaRegionOwners,
76 res: Self,
77 ) -> bool;
78
79 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self)
80 requires
81 self.clone_requires(*old(perm)),
82 ensures
83 res == *self,
87 self.clone_ensures(*old(perm), *final(perm), res),
88 final(perm).inv(),
89 final(perm).slots == old(perm).slots,
90 final(perm).slot_owners.dom() == old(perm).slot_owners.dom(),
91 ;
92}
93
94pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
112 spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize>;
113
114 #[verifier::when_used_as_spec(TOP_LEVEL_INDEX_RANGE_spec)]
121 fn TOP_LEVEL_INDEX_RANGE() -> Range<usize>
122 returns
123 Self::TOP_LEVEL_INDEX_RANGE(),
124 ;
125
126 open spec fn LEADING_BITS_spec() -> usize {
145 0
146 }
147
148 open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
149 true
150 }
151
152 #[verifier::when_used_as_spec(TOP_LEVEL_CAN_UNMAP_spec)]
158 fn TOP_LEVEL_CAN_UNMAP() -> bool
159 returns
160 Self::TOP_LEVEL_CAN_UNMAP(),
161 ;
162
163 open spec fn LOCKED_END_BOUND_spec() -> int {
177 0x1_0000_0000_0000_0000int
178 }
179
180 type E: PageTableEntryTrait;
182
183 type C: PagingConstsTrait;
185
186 type Item: RCClone;
199
200 spec fn item_into_raw_spec(item: Self::Item) -> (Paddr, PagingLevel, PageProperty);
201
202 #[verifier::when_used_as_spec(item_into_raw_spec)]
208 fn item_into_raw(item: Self::Item) -> ((paddr, level, prop): (Paddr, PagingLevel, PageProperty))
209 requires
210 Self::item_well_formed(item),
211 ensures
212 1 <= level <= NR_LEVELS,
213 valid_frame_paddr(paddr),
214 paddr % page_size(level) == 0,
215 paddr + page_size(level) <= MAX_PADDR,
216 Self::raw_item_well_formed(paddr, level, prop),
217 Self::E::new_page_req(paddr, level, prop),
218 returns
219 Self::item_into_raw_spec(item),
220 ;
221
222 spec fn item_from_raw_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self::Item;
223
224 #[verifier::when_used_as_spec(item_from_raw_spec)]
249 unsafe fn item_from_raw(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res:
250 Self::Item)
251 requires
252 valid_frame_paddr(paddr),
253 Self::raw_item_well_formed(paddr, level, prop),
254 ensures
255 Self::item_well_formed(res),
256 returns
257 Self::item_from_raw_spec(paddr, level, prop),
258 ;
259
260 spec fn tracked(item: Self::Item) -> bool;
264
265 spec fn item_well_formed(item: Self::Item) -> bool;
269
270 spec fn raw_item_well_formed(pa: Paddr, level: PagingLevel, prop: PageProperty) -> bool;
273
274 proof fn lemma_raw_item_well_formed_preserved(
276 pa: Paddr,
277 level: PagingLevel,
278 old_prop: PageProperty,
279 new_prop: PageProperty,
280 )
281 requires
282 valid_frame_paddr(pa),
283 Self::raw_item_well_formed(pa, level, old_prop),
284 Self::tracked(Self::item_from_raw(pa, level, new_prop)) == Self::tracked(
285 Self::item_from_raw(pa, level, old_prop),
286 ),
287 ensures
288 Self::raw_item_well_formed(pa, level, new_prop),
289 ;
290
291 proof fn lemma_raw_item_well_formed_split(
293 pa: Paddr,
294 level: PagingLevel,
295 prop: PageProperty,
296 child_pa: Paddr,
297 child_idx: usize,
298 )
299 requires
300 valid_frame_paddr(pa),
301 Self::raw_item_well_formed(pa, level, prop),
302 Self::E::new_page_req(pa, level, prop),
303 level > 1,
304 child_idx < NR_ENTRIES,
305 child_pa == pa + child_idx * page_size((level - 1) as PagingLevel),
306 ensures
307 Self::raw_item_well_formed(child_pa, (level - 1) as PagingLevel, prop),
308 Self::E::new_page_req(child_pa, (level - 1) as PagingLevel, prop),
309 ;
310
311 proof fn lemma_item_from_raw_well_formed(pa: Paddr, level: PagingLevel, prop: PageProperty)
313 requires
314 valid_frame_paddr(pa),
315 Self::raw_item_well_formed(pa, level, prop),
316 ensures
317 Self::item_well_formed(Self::item_from_raw(pa, level, prop)),
318 ;
319
320 proof fn lemma_item_into_raw_roundtrip(pa: Paddr, level: PagingLevel, prop: PageProperty)
322 requires
323 valid_frame_paddr(pa),
324 Self::raw_item_well_formed(pa, level, prop),
325 ensures
326 Self::item_into_raw(Self::item_from_raw(pa, level, prop)) == (pa, level, prop),
327 ;
328
329 proof fn lemma_item_from_raw_roundtrip(
331 item: Self::Item,
332 pa: Paddr,
333 level: PagingLevel,
334 prop: PageProperty,
335 )
336 requires
337 valid_frame_paddr(pa),
338 Self::item_well_formed(item),
339 Self::item_into_raw(item) == (pa, level, prop),
340 ensures
341 Self::item_from_raw(pa, level, prop) == item,
342 ;
343
344 proof fn lemma_clone_ensures_concrete(
351 item: Self::Item,
352 pa: Paddr,
353 old_regions: MetaRegionOwners,
354 new_regions: MetaRegionOwners,
355 res: Self::Item,
356 )
357 requires
358 item.clone_ensures(old_regions, new_regions, res),
359 Self::item_into_raw_spec(item).0 == pa,
360 res == item,
361 new_regions.inv(),
362 new_regions.slots =~= old_regions.slots,
363 new_regions.slot_owners.dom() =~= old_regions.slot_owners.dom(),
364 ensures
365 forall|i: int|
368 i != frame_to_index(pa) ==> (#[trigger] new_regions.slot_owners[i]
369 == old_regions.slot_owners[i]),
370 Self::tracked(item) ==> {
372 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
373 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value() + 1
374 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.id()
375 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.id()
376 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.storage
377 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.storage
378 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.vtable_ptr
379 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.vtable_ptr
380 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.in_list
381 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.in_list
382 &&& new_regions.slot_owners[frame_to_index(pa)].paths_in_pt
383 == old_regions.slot_owners[frame_to_index(pa)].paths_in_pt
384 &&& new_regions.slot_owners[frame_to_index(pa)].slot_vaddr
385 == old_regions.slot_owners[frame_to_index(pa)].slot_vaddr
386 &&& new_regions.slot_owners[frame_to_index(pa)].usage
387 == old_regions.slot_owners[frame_to_index(pa)].usage
388 },
389 !Self::tracked(item) ==> new_regions.slot_owners[frame_to_index(pa)]
390 == old_regions.slot_owners[frame_to_index(pa)],
391 Self::tracked(item) ==> new_regions.frame_obligations
394 == old_regions.frame_obligations.insert(frame_to_index(pa)),
395 !Self::tracked(item) ==> new_regions.frame_obligations == old_regions.frame_obligations,
396 ;
397
398 proof fn lemma_clone_requires_concrete(
404 item: Self::Item,
405 pa: Paddr,
406 level: PagingLevel,
407 prop: PageProperty,
408 regions: MetaRegionOwners,
409 )
410 requires
411 regions.inv(),
412 Self::item_from_raw_spec(pa, level, prop) == item,
413 Self::raw_item_well_formed(pa, level, prop),
414 valid_frame_paddr(pa),
415 regions.slots.contains_key(frame_to_index(pa)),
416 regions.slot_owners.contains_key(frame_to_index(pa)),
417 Self::tracked(item) ==> regions.slot_owners[frame_to_index(
418 pa,
419 )].inner_perms.ref_count.value() > 0,
420 Self::tracked(item) ==> regions.slot_owners[frame_to_index(
422 pa,
423 )].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
424 Self::tracked(item) ==> (regions.slot_owners[frame_to_index(
426 pa,
427 )].inner_perms.ref_count.value() < REF_COUNT_MAX || may_panic()),
428 ensures
429 item.clone_requires(regions),
430 ;
431
432 proof fn lemma_page_table_config_constant_requirements()
439 ensures
440 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
441 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end,
442 Self::TOP_LEVEL_INDEX_RANGE().end <= pow2(
443 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
444 Self::C::NR_LEVELS(),
445 )) as nat,
446 ),
447 Self::TOP_LEVEL_INDEX_RANGE().end * pow2(
448 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
449 ) <= usize::MAX,
450 Self::LEADING_BITS_spec() != 0usize ==> (Self::C::VA_SIGN_EXT() && ((
451 Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
452 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
453 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1),
454 (Self::C::VA_SIGN_EXT() && (((Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
455 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
456 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1)) ==> {
457 &&& Self::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int
458 - pow2(Self::C::ADDRESS_WIDTH() as nat)
459 },
460 Self::LEADING_BITS_spec() < 0x1_0000_usize,
461 pow2(
463 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
464 Self::C::NR_LEVELS(),
465 )) as nat,
466 ) == NR_ENTRIES,
467 ;
468
469 proof fn lemma_page_table_config_constant_properties()
473 ensures
474 Self::TOP_LEVEL_INDEX_RANGE().end <= NR_ENTRIES,
477 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
480 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end,
481 Self::TOP_LEVEL_INDEX_RANGE().end <= pow2(
482 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
483 Self::C::NR_LEVELS(),
484 )) as nat,
485 ),
486 Self::TOP_LEVEL_INDEX_RANGE().end * pow2(
487 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
488 ) <= usize::MAX,
489 Self::LEADING_BITS_spec() != 0usize ==> (Self::C::VA_SIGN_EXT() && ((
490 Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
491 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
492 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1),
493 (Self::C::VA_SIGN_EXT() && (((Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
494 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
495 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1)) ==> {
496 &&& Self::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int
497 - pow2(Self::C::ADDRESS_WIDTH() as nat)
498 },
499 Self::LEADING_BITS_spec() < 0x1_0000_usize,
500 pow2(
502 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
503 Self::C::NR_LEVELS(),
504 )) as nat,
505 ) == NR_ENTRIES,
506 {
507 Self::C::lemma_paging_consts_properties();
508 Self::lemma_page_table_config_constant_requirements();
509 }
510}
511
512impl<C: PageTableConfig> PagingConstsTrait for C {
515 open spec fn BASE_PAGE_SIZE_spec() -> usize {
516 C::C::BASE_PAGE_SIZE_spec()
517 }
518
519 fn BASE_PAGE_SIZE() -> usize {
520 C::C::BASE_PAGE_SIZE()
521 }
522
523 open spec fn NR_LEVELS_spec() -> PagingLevel {
524 C::C::NR_LEVELS_spec()
525 }
526
527 fn NR_LEVELS() -> PagingLevel {
528 proof {
529 assert(Self::NR_LEVELS() == C::C::NR_LEVELS());
530 }
531 C::C::NR_LEVELS()
532 }
533
534 open spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel {
535 C::C::HIGHEST_TRANSLATION_LEVEL_spec()
536 }
537
538 fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel {
539 C::C::HIGHEST_TRANSLATION_LEVEL()
540 }
541
542 open spec fn PTE_SIZE_spec() -> usize {
543 C::C::PTE_SIZE_spec()
544 }
545
546 fn PTE_SIZE() -> usize {
547 C::C::PTE_SIZE()
548 }
549
550 open spec fn ADDRESS_WIDTH_spec() -> usize {
551 C::C::ADDRESS_WIDTH_spec()
552 }
553
554 fn ADDRESS_WIDTH() -> usize {
555 C::C::ADDRESS_WIDTH()
556 }
557
558 open spec fn VA_SIGN_EXT_spec() -> bool {
559 C::C::VA_SIGN_EXT_spec()
560 }
561
562 fn VA_SIGN_EXT() -> bool {
563 C::C::VA_SIGN_EXT()
564 }
565
566 proof fn lemma_paging_consts_requirements() {
567 C::C::lemma_paging_consts_requirements();
568 }
569}
570
571#[verifier::external_body]
596pub fn largest_pages<C: PageTableConfig>(
597 mut va: Vaddr,
598 mut pa: Paddr,
599 mut len: usize,
600) -> impl Iterator<Item = (Paddr, PagingLevel)> {
601 assert_eq!(va % C::BASE_PAGE_SIZE(), 0);
602 assert_eq!(pa % C::BASE_PAGE_SIZE(), 0);
603 assert_eq!(len % C::BASE_PAGE_SIZE(), 0);
604 assert!(is_valid_range::<C>(&(va..(va + len))));
605
606 core::iter::from_fn(
607 move ||
608 {
609 if len == 0 {
610 return None;
611 }
612 let mut level = C::HIGHEST_TRANSLATION_LEVEL();
613 while page_size(level) > len || va % page_size(level) != 0 || pa % page_size(level)
614 != 0 {
615 level -= 1;
616 }
617
618 let item_start = pa;
619 va += page_size(level);
620 pa += page_size(level);
621 len -= page_size(level);
622
623 Some((item_start, level))
624 },
625 )
626}
627
628fn top_level_index_width<C: PageTableConfig>() -> (ret: usize)
630 returns
631 top_level_index_width_spec::<C>(),
632{
633 proof {
634 C::lemma_paging_consts_properties();
635 C::lemma_page_table_config_constant_properties();
636 }
637
638 C::ADDRESS_WIDTH() - pte_index_bit_offset::<C>(C::NR_LEVELS())
639}
640
641fn pt_va_range_start<C: PageTableConfig>() -> (ret: Vaddr)
642 ensures
643 ret == C::TOP_LEVEL_INDEX_RANGE().start * pow2(
644 pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat,
645 ),
646{
647 proof {
648 C::lemma_paging_consts_properties();
649 let ghost idx_start = C::TOP_LEVEL_INDEX_RANGE().start;
650 let ghost offset = pte_index_bit_offset_spec::<C>(C::NR_LEVELS());
651 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_start_shift_facts::<C>(
652 idx_start,
653 offset,
654 );
655 vstd::bits::lemma_usize_shl_is_mul(idx_start, offset);
656 }
657
658 C::TOP_LEVEL_INDEX_RANGE().start << pte_index_bit_offset::<C>(C::NR_LEVELS())
659}
660
661fn pt_va_range_end<C: PageTableConfig>() -> (ret: Vaddr)
667 ensures
668 ret == (C::TOP_LEVEL_INDEX_RANGE().end * pow2(
669 pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat,
670 ) - 1) % 0x1_0000_0000_0000_0000int,
671{
672 let idx_end = C::TOP_LEVEL_INDEX_RANGE().end;
673 proof {
674 C::lemma_paging_consts_properties();
675 }
676 let offset = pte_index_bit_offset::<C>(C::NR_LEVELS());
677
678 proof {
679 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_end_shift_facts::<C>(
680 idx_end,
681 offset,
682 );
683 vstd::bits::lemma_usize_shl_is_mul(idx_end, offset);
684 }
685
686 let shifted = idx_end << offset;
687 let ret = shifted.wrapping_sub(1);
688
689 proof {
690 assert(shifted == idx_end * pow2(offset as nat));
691 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_end_wrapping_sub::<C>(
692 idx_end,
693 offset,
694 shifted,
695 ret,
696 );
697 }
698 ret
699}
700
701fn sign_bit_of_va<C: PageTableConfig>(va: Vaddr) -> (ret: bool)
702 ensures
703 ret == ((va as int / pow2((C::ADDRESS_WIDTH() - 1) as nat) as int) % 2 == 1),
704{
705 proof {
706 C::lemma_paging_consts_properties();
707 C::lemma_page_table_config_constant_properties();
708 vstd::bits::lemma_usize_shr_is_div(va, (C::ADDRESS_WIDTH() - 1) as usize);
709 vstd::bits::lemma_usize_low_bits_mask_is_mod(va >> (C::ADDRESS_WIDTH() - 1), 1);
710 vstd::bits::lemma_low_bits_mask_values();
711 vstd::arithmetic::power2::lemma2_to64();
712 }
713 (va >> (C::ADDRESS_WIDTH() - 1)) & 1 != 0
714}
715
716fn apply_sign_ext<C: PageTableConfig>(va: Vaddr) -> (ret: Vaddr)
723 requires
724 va < pow2(C::ADDRESS_WIDTH() as nat),
725 C::ADDRESS_WIDTH() < usize::BITS,
726 C::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int - pow2(
727 C::ADDRESS_WIDTH() as nat,
728 ),
729 ensures
730 ret == va + C::LEADING_BITS_spec() * 0x1_0000_0000_0000int,
731{
732 let address_width = C::ADDRESS_WIDTH();
733 let low_bit = 1usize << address_width;
734 proof {
735 vstd::layout::unsigned_int_max_values();
736 vstd::bits::lemma_usize_pow2_no_overflow(address_width as nat);
737 vstd::bits::lemma_usize_shl_is_mul(1usize, address_width);
738 }
739 let low_mask = low_bit - 1;
740 let sign_ext_mask = !0 ^ low_mask;
741 let ret = va | sign_ext_mask;
742 proof {
743 assert(!0usize == 0xffff_ffff_ffff_ffffusize) by (compute_only);
744 assert(sign_ext_mask == usize::MAX - low_mask) by (bit_vector)
745 requires
746 sign_ext_mask == (!0usize ^ low_mask),
747 !0usize == 0xffff_ffff_ffff_ffffusize,
748 usize::MAX == 0xffff_ffff_ffff_ffffusize,
749 ;
750 assert(pow2(64) == 0x1_0000_0000_0000_0000nat) by {
751 vstd::arithmetic::power2::lemma2_to64();
752 };
753 assert(sign_ext_mask == 0x1_0000_0000_0000_0000int - pow2(address_width as nat));
754 assert(sign_ext_mask == C::LEADING_BITS_spec() * 0x1_0000_0000_0000int);
755
756 assert((va & sign_ext_mask) == 0usize) by (bit_vector)
757 requires
758 address_width < usize::BITS,
759 low_bit == 1usize << address_width,
760 low_mask == low_bit - 1,
761 sign_ext_mask == !0usize ^ low_mask,
762 va < low_bit,
763 ;
764 assert(ret == va + sign_ext_mask) by (bit_vector)
765 requires
766 ret == va | sign_ext_mask,
767 (va & sign_ext_mask) == 0usize,
768 ;
769 }
770 ret
771}
772
773#[verusfmt::skip]
780fn vaddr_range<C: PageTableConfig>() -> (ret: RangeInclusive<Vaddr>)
781 returns
782 vaddr_range_spec::<C>(),
783{
784 let mut start = pt_va_range_start::<C>();
785 let mut end = pt_va_range_end::<C>();
786
787 proof {
788 C::lemma_paging_consts_properties();
789 C::lemma_page_table_config_constant_properties();
790 crate::specs::mm::page_table::vaddr_range_proofs::lemma_idx_times_pow2_bound::<C>(
791 start,
792 end,
793 );
794 }
795
796 if C::VA_SIGN_EXT() && sign_bit_of_va::<C>(pt_va_range_start::<C>()) {
797 start = apply_sign_ext::<C>(start);
798 end = apply_sign_ext::<C>(end);
799 }
800 start..=end
801}
802
803fn is_valid_range<C: PageTableConfig>(r: &Range<Vaddr>) -> bool
805 requires
806 r.end > 0,
807 returns
808 is_valid_range_spec::<C>(*r),
809{
810 let va_range = vaddr_range::<C>();
811 (r.start == 0 && r.end == 0) || (*va_range.start() <= r.start && r.end - 1 <= *va_range.end())
812}
813
814fn nr_pte_index_bits<C: PagingConstsTrait>() -> usize
817 returns
818 nr_pte_index_bits_spec::<C>(),
819{
820 proof {
821 C::lemma_paging_consts_properties();
822 }
823 nr_subpage_per_huge::<C>().ilog2() as usize
824}
825
826fn pte_index<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel) -> (res: usize)
828 requires
829 1 <= level <= NR_LEVELS,
830 ensures
831 res == AbstractVaddr::from_vaddr(va).index[level - 1],
832{
833 proof {
834 let offset = pte_index_bit_offset_spec::<C>(level);
835 C::lemma_paging_consts_properties();
836 lemma_arch_specific_consts_properties::<C>();
837 assert(0 <= offset < usize::BITS) by (nonlinear_arith)
838 requires
839 1 <= level <= 4,
840 offset == 12 + 9 * (level - 1),
841 ;
842 lemma2_to64();
843 lemma2_to64_rest();
844 vstd::bits::lemma_usize_shr_is_div(va, pte_index_bit_offset_spec::<C>(level));
845 vstd::bits::lemma_low_bits_mask_values();
846 vstd::bits::lemma_usize_low_bits_mask_is_mod(
847 va >> pte_index_bit_offset_spec::<C>(level),
848 9,
849 );
850 }
851 (va >> pte_index_bit_offset::<C>(level)) & (nr_subpage_per_huge::<C>() - 1)
852}
853
854fn pte_index_bit_offset<C: PagingConstsTrait>(level: PagingLevel) -> usize
860 requires
861 1 <= level <= NR_LEVELS,
862 returns
863 pte_index_bit_offset_spec::<C>(level),
864{
865 proof {
866 C::lemma_paging_consts_properties();
867 lemma_arch_specific_consts_properties::<C>();
868 assert(12 + 9 * (level - 1) <= 39) by (nonlinear_arith)
869 requires
870 1 <= level <= NR_LEVELS,
871 NR_LEVELS == 4,
872 ;
873 }
874 C::BASE_PAGE_SIZE().ilog2() as usize + nr_pte_index_bits::<C>() * (level as usize - 1)
875}
876
877pub struct PageTable<C: PageTableConfig> {
880 pub root: PageTableNode<C>,
881}
882
883impl PageTable<KernelPtConfig> {
895 #[verifier::external_body]
897 pub(crate) fn new_kernel_page_table() -> Self {
898 unimplemented!()}
914
915 pub open spec fn create_user_pt_panic_condition(root_owner: NodeOwner<KernelPtConfig>) -> bool {
919 exists|i: usize|
920 #![trigger root_owner.children_perm.value()[i as int]]
921 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
922 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
923 let pte = root_owner.children_perm.value()[i as int];
924 ||| !pte.is_present()
925 ||| pte.is_last(root_owner.level)
926 }
927 }
928
929 #[verus_spec(r =>
934 with Tracked(kernel_owner): Tracked<&PageTableOwner<KernelPtConfig>>,
935 Tracked(regions): Tracked<&mut MetaRegionOwners>,
936 Tracked(guards): Tracked<&mut Guards<'rcu>>,
937 requires
938 kernel_owner.inv(),
939 old(regions).inv(),
940 kernel_owner.0.value().is_node(),
941 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
942 self.root.ptr.addr() == kernel_owner.0.value().node().meta_vaddr(),
944 kernel_owner.0.value().metaregion_sound(*old(regions)),
946 kernel_owner.metaregion_sound(*old(regions)),
950 old(guards).unlocked(kernel_owner.0.value().node().meta_vaddr()),
952 ensures
953 final(regions).inv(),
954 )]
955 pub(in crate::mm) fn create_user_page_table<'rcu, G: InAtomicMode + 'static>(
956 &'static self,
957 ) -> PageTable<UserPtConfig> {
958 let preempt_guard: &'rcu G = disable_preempt::<G>();
959
960 proof_decl! {
961 let tracked mut new_pt_owner: Option<PageTableOwner<UserPtConfig>> = None;
962 }
963 let ghost regions_before_alloc = *regions;
964 let new_pt: PageTable<UserPtConfig> = (
965 #[verus_spec(with Tracked(&mut new_pt_owner), Tracked(regions), Tracked(guards))]
966 PageTable::empty_with_owner());
967 let new_root = new_pt.root;
968 let ghost new_idx_g: int = crate::specs::mm::frame::mapping::frame_to_index(
970 new_pt_owner@.unwrap().0.value().meta_slot_paddr().unwrap(),
971 );
972 let ghost new_pt_owner_snap = new_pt_owner@.unwrap();
973 proof {
974 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
975 kernel_owner.0.value().meta_slot_paddr().unwrap(),
976 );
977 let new_idx = new_idx_g;
978 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
979 KernelPtConfig,
980 >::lemma_active_entry_not_in_free_pool(
981 kernel_owner.0.value(),
982 regions_before_alloc,
983 new_idx,
984 );
985 assert(kern_idx != new_idx);
986 assert(regions.slot_owners[kern_idx] == regions_before_alloc.slot_owners[kern_idx]);
987 assert(kernel_owner.metaregion_sound(*regions));
988 assert(!regions.slots.contains_key(new_idx));
989 }
990
991 proof_decl! {
992 let tracked root_owner: &NodeOwner<KernelPtConfig>
993 = kernel_owner.0.tracked_borrow_value().tracked_borrow_node();
994 let tracked mut new_pt_owner_val: PageTableOwner<UserPtConfig>
995 = new_pt_owner.tracked_take();
996 let tracked mut new_node_owner: NodeOwner<UserPtConfig> = {
997 let tracked new_pt_value = new_pt_owner_val.0.tracked_borrow_mut_value();
998 new_pt_value.tracked_take_node()
999 };
1000 let tracked mut entry_owner: &EntryOwner<KernelPtConfig>;
1001 }
1002
1003 proof {
1006 assert(kernel_owner.0.value().is_node());
1007 assert(kernel_owner.0.value().metaregion_sound(*regions));
1008 }
1009 let ghost regions_before_self_borrow: MetaRegionOwners = *regions;
1010 let mut root_node = {
1011 #[verus_spec(with Tracked(regions))]
1012 let root_ref = self.root.borrow();
1013 #[verus_spec(with Tracked(root_owner), Tracked(guards))]
1014 root_ref.lock(preempt_guard)
1015 };
1016 let ghost regions_after_kroot_borrow: MetaRegionOwners = *regions;
1017 let mut new_node: PageTableGuard<'rcu, UserPtConfig> = {
1018 #[verus_spec(with Tracked(regions))]
1019 let new_ref = new_root.borrow();
1020 #[verus_spec(with Tracked(&new_node_owner), Tracked(guards))]
1021 new_ref.lock(preempt_guard)
1022 };
1023 proof {
1024 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
1025 kernel_owner.0.value().meta_slot_paddr().unwrap(),
1026 );
1027 assert(regions_before_self_borrow.slot_owners
1028 == regions_after_kroot_borrow.slot_owners);
1029 assert forall|k: int|
1030 regions_before_self_borrow.slots.contains_key(
1031 k,
1032 ) implies regions_before_self_borrow.slots[k]
1033 == #[trigger] regions_after_kroot_borrow.slots[k] by {
1034 if k == kern_idx {
1035 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1036 KernelPtConfig,
1037 >::lemma_active_entry_not_in_free_pool(
1038 kernel_owner.0.value(),
1039 regions_before_self_borrow,
1040 k,
1041 );
1042 }
1043 };
1044 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1045 regions_before_self_borrow,
1046 regions_after_kroot_borrow,
1047 );
1048
1049 let new_idx = new_idx_g;
1050 assert(regions_before_alloc.slots.contains_key(new_idx));
1051 assert(kern_idx != new_idx) by {
1052 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1053 KernelPtConfig,
1054 >::lemma_active_entry_not_in_free_pool(
1055 kernel_owner.0.value(),
1056 regions_before_alloc,
1057 new_idx,
1058 );
1059 };
1060
1061 assert(!regions_before_self_borrow.slots.contains_key(new_idx));
1062 assert(!regions_after_kroot_borrow.slots.contains_key(new_idx));
1063 assert forall|k: int|
1064 regions_after_kroot_borrow.slots.contains_key(
1065 k,
1066 ) implies regions_after_kroot_borrow.slots[k] == #[trigger] regions.slots[k] by {
1067 if k != new_idx {
1068 }
1070 };
1071 assert(kernel_owner.metaregion_sound(regions_before_alloc));
1072
1073 kernel_owner.0.lemma_subtree_satisfies_implies(
1074 kernel_owner.0.value().path,
1075 |
1076 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1077 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1078 |
1079 e.is_frame() && e.parent_level > 1 ==> {
1080 let pa = e.frame().mapped_pa;
1081 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1082 forall|j: usize|
1083 0 < j < nr_pages ==> {
1084 let sub_idx =
1085 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1086 (pa + j * PAGE_SIZE) as usize,
1087 );
1088 sub_idx != new_idx
1089 }
1090 },
1091 |
1092 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1093 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1094 |
1095 e.is_frame() && e.parent_level > 1 ==> {
1096 let pa = e.frame().mapped_pa;
1097 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1098 forall|j: usize|
1099 0 < j < nr_pages ==> {
1100 let sub_idx =
1101 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1102 (pa + j * PAGE_SIZE) as usize,
1103 );
1104 sub_idx != new_idx || (regions.slots.contains_key(sub_idx)
1105 && regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1106 != REF_COUNT_UNUSED
1107 && regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1108 > 0
1109 && regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1110 <= REF_COUNT_MAX)
1111 }
1112 },
1113 );
1114 kernel_owner.metaregion_sound_preserved_one_slot_changed(
1115 regions_after_kroot_borrow,
1116 *regions,
1117 new_idx,
1118 );
1119 }
1120 let mut i: usize = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start;
1121 while i < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end
1122 invariant
1123 kernel_owner.inv(),
1124 kernel_owner.0.value().is_node(),
1125 regions.inv(),
1126 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
1127 i <= KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end,
1128 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i,
1129 *root_owner == kernel_owner.0.value().node(),
1131 root_owner.relate_guard(root_node),
1132 kernel_owner.metaregion_sound(*regions),
1134 new_node_owner.inv(),
1136 new_node_owner.relate_guard(new_node),
1137 regions.slots.contains_key(new_node_owner.slot_index),
1138 decreases KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end - i,
1139 {
1140 proof {
1141 let kern_node = kernel_owner.0.value().node();
1142 assert forall|j: usize|
1143 #![trigger kern_node.children_perm.value()[j as int]]
1144 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1145 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end implies {
1146 let pte = kern_node.children_perm.value()[j as int];
1147 pte.is_present() && !pte.is_last(kern_node.level)
1148 } by {
1149 let pte = kern_node.children_perm.value()[j as int];
1150 if !pte.is_present() || pte.is_last(kern_node.level) {
1151 assert(Self::create_user_pt_panic_condition(kern_node));
1152 }
1153 }
1154
1155 kernel_owner.pt_inv_unroll(i as int);
1156 let tracked child_subtree: &OwnerSubtree<KernelPtConfig> =
1157 kernel_owner.0.tracked_borrow_child(i as int);
1158 entry_owner = child_subtree.tracked_borrow_value();
1159 let kern_node = kernel_owner.0.value().node();
1160 assert(entry_owner.match_pte(
1161 kern_node.children_perm.value()[i as int],
1162 entry_owner.parent_level,
1163 ));
1164 assert(entry_owner.parent_level == kern_node.level);
1165 assert(child_subtree.inv());
1166 assert(entry_owner.inv());
1167 assert(root_owner.relate_guard(root_node));
1168
1169 kernel_owner.0.lemma_subtree_satisfies_unroll_once(
1170 kernel_owner.0.value().path,
1171 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1172 i as int,
1173 );
1174 assert(child_subtree.subtree_satisfies(
1175 kernel_owner.0.value().path.push_tail(i as int),
1176 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1177 ));
1178 assert(entry_owner.metaregion_sound(*regions));
1179 }
1180
1181 #[verus_spec(with Tracked(root_owner), Tracked(entry_owner), Tracked(&*regions))]
1182 let root_entry = root_node.entry(i);
1183 let ghost pre_to_ref_regions: MetaRegionOwners = *regions;
1184 #[verus_spec(with Tracked(entry_owner), Tracked(root_owner), Tracked(regions))]
1185 let child = root_entry.to_ref();
1186
1187 proof {
1188 let kern_node = kernel_owner.0.value().node();
1189 let pte = kern_node.children_perm.value()[i as int];
1190
1191 assert(pte.is_present() && !pte.is_last(kern_node.level)) by {
1192 if !pte.is_present() || pte.is_last(kern_node.level) {
1193 assert(KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
1194 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end);
1195 assert(exists|j: usize|
1196 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1197 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
1198 let p = #[trigger] kern_node.children_perm.value()[j as int];
1199 ||| !p.is_present()
1200 ||| p.is_last(kern_node.level)
1201 });
1202 assert(Self::create_user_pt_panic_condition(kern_node));
1203 }
1204 }
1205 assert(entry_owner.is_node());
1208 assert(child is PageTable);
1212 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1216 pre_to_ref_regions,
1217 *regions,
1218 );
1219 }
1220 let pt = match child {
1221 ChildRef::PageTable(pt) => pt,
1222 _ => vstd::pervasive::unreached(),
1223 };
1224
1225 let ghost entry_node_slot_idx = entry_owner.tracked_borrow_node().slot_index;
1226 let tracked entry_node_slot_perm = regions.slots.tracked_borrow(entry_node_slot_idx);
1227 #[verus_spec(with Tracked(entry_node_slot_perm))]
1228 let pt_addr = pt.start_paddr();
1229 let pte = PageTableEntry::new_pt(pt_addr);
1230
1231 proof {
1232 assert(regions.slots.contains_key(new_node_owner.slot_index));
1233 }
1234 unsafe {
1235 #[verus_spec(with Tracked(&mut new_node_owner), Tracked(&*regions))]
1236 new_node.write_pte(i, pte)
1237 };
1238
1239 i = i + 1;
1240 }
1241
1242 PageTable::<UserPtConfig> { root: new_root }
1243 }}
1269
1270#[verus_verify]
1271impl<C: PageTableConfig> PageTable<C> {
1272 pub open spec fn relates_owner(
1274 &self,
1275 owner: PageTableOwner<C>,
1276 regions: MetaRegionOwners,
1277 ) -> bool {
1278 &&& owner.inv()
1279 &&& self.root.ptr.addr() == owner.0.value().node().meta_vaddr()
1280 &&& owner.metaregion_sound(regions)
1281 }
1282
1283 #[verifier::external_body]
1287 pub fn empty() -> Self {
1288 unimplemented!()
1289 }
1290
1291 #[verifier::external_body]
1293 #[verus_spec(r =>
1294 with Tracked(owner): Tracked<&mut Option<PageTableOwner<C>>>,
1295 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1296 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1297 requires
1298 old(regions).inv(),
1299 ensures
1300 final(owner)@ is Some,
1301 final(owner)@->0.inv(),
1302 (final(owner)@->0).0.value().is_node(),
1303 (final(owner)@->0).0.value().is_node(),
1304 r.root.ptr.addr() == (final(owner)@->0).0.value().node().meta_vaddr(),
1305 (final(owner)@->0).0.value().metaregion_sound(*final(regions)),
1306 final(regions).inv(),
1307 final(guards).unlocked((final(owner)@->0).0.value().node().meta_vaddr()),
1308 final(guards).guards == old(guards).guards,
1311 old(regions).slots.contains_key(
1313 crate::specs::mm::frame::mapping::frame_to_index(
1314 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1315 !final(regions).slots.contains_key(
1318 crate::specs::mm::frame::mapping::frame_to_index(
1319 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1320 forall |i: int| #![trigger final(regions).slot_owners[i]]
1322 i != crate::specs::mm::frame::mapping::frame_to_index(
1323 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1324 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
1325 forall |a: usize| old(guards).lock_held(a) ==> final(guards).lock_held(a),
1326 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1327 final(regions).slot_owners[idx].paths_in_pt
1328 == old(regions).slot_owners[idx].paths_in_pt,
1329 forall |kt: PageTableOwner<KernelPtConfig>|
1335 #![trigger kt.metaregion_sound(*final(regions))]
1336 kt.inv() && kt.metaregion_sound(*old(regions))
1337 ==> kt.metaregion_sound(*final(regions)),
1338 forall |kt: PageTableOwner<KernelPtConfig>|
1343 #![trigger kt.metaregion_sound(*old(regions))]
1344 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1345 kt.0.subtree_satisfies(
1346 kt.0.value().path,
1347 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1348 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1349 e.meta_slot_paddr() is Some
1350 ==> crate::specs::mm::frame::mapping::frame_to_index(
1351 e.meta_slot_paddr()->0) !=
1352 crate::specs::mm::frame::mapping::frame_to_index(
1353 (final(owner)@->0).0.value().meta_slot_paddr()->0),
1354 ),
1355 forall |kt: PageTableOwner<KernelPtConfig>|
1359 #![trigger kt.metaregion_sound(*old(regions))]
1360 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1361 kt.0.subtree_satisfies(
1362 kt.0.value().path,
1363 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1364 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1365 e.is_frame() && e.parent_level > 1 ==> {
1366 let pa = e.frame().mapped_pa;
1367 let nr_pages = page_size(
1368 e.parent_level) / PAGE_SIZE;
1369 forall |j: usize| 0 < j < nr_pages ==> {
1370 let sub_idx =
1371 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1372 (pa + j * PAGE_SIZE) as usize);
1373 sub_idx != crate::specs::mm::frame::mapping::frame_to_index(
1374 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1375 }
1376 },
1377 ),
1378 )]
1379 pub fn empty_with_owner<'rcu>() -> Self {
1380 unimplemented!()
1381 }
1382
1383 #[verifier::external_body]
1384 pub(in crate::mm) unsafe fn first_activate_unchecked(&self) {
1385 unimplemented!()
1386 }
1390
1391 pub uninterp spec fn root_paddr_spec(&self) -> Paddr;
1392
1393 #[verifier::external_body]
1399 #[verifier::when_used_as_spec(root_paddr_spec)]
1400 pub fn root_paddr(&self) -> (r: Paddr)
1401 returns
1402 self.root_paddr_spec(),
1403 {
1404 unimplemented!()
1405 }
1408
1409 #[cfg(ktest)]
1415 pub fn page_walk(&self, vaddr: Vaddr) -> Option<(Paddr, PageProperty)> {
1416 unsafe { page_walk::<C>(self.root_paddr(), vaddr) }
1418 }
1419
1420 #[verus_spec(r =>
1425 with Tracked(owner): Tracked<PageTableOwner<C>>,
1426 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1427 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1428 Tracked(guards): Tracked<&mut Guards<'rcu>>
1429 requires
1430 self.relates_owner(owner, *old(regions)),
1431 owner.0.value().node().relate_guard(root_guard),
1432 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1434 ensures
1435 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1436 &&& r is Ok
1437 &&& r.unwrap().0.0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1438 &&& r.unwrap().1.in_locked_range()
1439 &&& r.unwrap().0.0.level == r.unwrap().0.0.guard_level
1440 &&& r.unwrap().0.0.guard_level == NR_LEVELS as PagingLevel
1441 &&& r.unwrap().0.0.va < r.unwrap().0.0.barrier_va.end
1442 &&& r.unwrap().0.0.va == va.start
1443 &&& r.unwrap().0.0.barrier_va == *va
1444 },
1445 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1446 forall |item: C::Item| #![trigger CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions))]
1447 CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions)) ==>
1448 CursorMut::<'rcu, C, G>::item_not_mapped(item, *final(regions)),
1449 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1453 old(regions).slot_owners[idx].inner_perms.ref_count.value()
1454 != REF_COUNT_UNUSED
1455 ==> final(regions).slot_owners[idx].paths_in_pt
1456 == old(regions).slot_owners[idx].paths_in_pt,
1457 forall|idx: int| #![trigger final(regions).slot_owners[idx]]
1458 old(regions).slot_owners.contains_key(idx)
1459 && old(regions).slot_owners[idx].inner_perms.ref_count.value()
1460 != REF_COUNT_UNUSED
1461 ==> final(regions).slot_owners[idx].inner_perms.ref_count.value()
1462 == old(regions).slot_owners[idx].inner_perms.ref_count.value()
1463 && final(regions).slot_owners[idx].usage
1464 == old(regions).slot_owners[idx].usage,
1465 )]
1466 pub fn cursor_mut<'rcu, G: InAtomicMode>(
1467 &'rcu self,
1468 guard: &'rcu G,
1469 va: &Range<Vaddr>,
1470 ) -> Result<(CursorMut<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>), PageTableError> {
1471 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1472 CursorMut::new(self, guard, va)
1473 }
1474
1475 #[verus_spec(r =>
1481 with Tracked(owner): Tracked<PageTableOwner<C>>,
1482 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1483 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1484 Tracked(guards): Tracked<&mut Guards<'rcu>>
1485 requires
1486 self.relates_owner(owner, *old(regions)),
1487 owner.0.value().node().relate_guard(root_guard),
1488 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1490 ensures
1491 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1492 &&& r is Ok
1493 &&& r.unwrap().0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1494 &&& r.unwrap().1.in_locked_range()
1495 &&& r.unwrap().0.level == r.unwrap().0.guard_level
1496 &&& r.unwrap().0.va < r.unwrap().0.barrier_va.end
1497 &&& r.unwrap().0.va == va.start
1498 &&& r.unwrap().0.barrier_va == *va
1499 &&& r.unwrap().1@.as_page_table_owner() == owner
1500 &&& r.unwrap().1@.continuations[3].path() == owner.0.value().path
1501 },
1502 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1503 forall|idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1504 old(regions).slot_owners[idx].inner_perms.ref_count.value()
1505 != REF_COUNT_UNUSED
1506 ==> final(regions).slot_owners[idx].paths_in_pt
1507 == old(regions).slot_owners[idx].paths_in_pt,
1508 (forall |i: int| #![trigger old(regions).slot_owners[i]]
1510 old(regions).slot_owners.contains_key(i)
1511 && old(regions).slot_owners[i].inner_perms.ref_count.value()
1512 != REF_COUNT_UNUSED
1513 ==> old(regions).slot_owners[i].inner_perms.ref_count.value() + 1
1514 < REF_COUNT_MAX)
1515 ==>
1516 (forall |i: int| #![trigger final(regions).slot_owners[i]]
1517 final(regions).slot_owners.contains_key(i)
1518 && final(regions).slot_owners[i].inner_perms.ref_count.value()
1519 != REF_COUNT_UNUSED
1520 ==> final(regions).slot_owners[i].inner_perms.ref_count.value() + 1
1521 < REF_COUNT_MAX),
1522 forall|idx: int| #![trigger final(regions).slot_owners[idx].inner_perms.ref_count.value()]
1527 final(regions).slot_owners[idx].inner_perms.ref_count.value()
1528 >= REF_COUNT_MAX
1529 ==> old(regions).slot_owners[idx].inner_perms.ref_count.value()
1530 == final(regions).slot_owners[idx].inner_perms.ref_count.value(),
1531 forall|idx: int| #![trigger old(regions).slot_owners[idx].inner_perms.ref_count.value()]
1532 old(regions).slot_owners[idx].inner_perms.ref_count.value()
1533 >= REF_COUNT_MAX
1534 ==> final(regions).slot_owners[idx].inner_perms.ref_count.value()
1535 == old(regions).slot_owners[idx].inner_perms.ref_count.value(),
1536 )]
1537 pub fn cursor<'rcu, G: InAtomicMode>(&'rcu self, guard: &'rcu G, va: &Range<Vaddr>) -> Result<
1538 (Cursor<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>),
1539 PageTableError,
1540 > {
1541 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1542 Cursor::new(self, guard, va)
1543 }}
1555
1556#[cfg(ktest)]
1579pub(super) unsafe fn page_walk<C: PageTableConfig>(root_paddr: Paddr, vaddr: Vaddr) -> Option<
1580 (Paddr, PageProperty),
1581> {
1582 use super::paddr_to_vaddr;
1583
1584 let _rcu_guard = disable_preempt();
1585
1586 let mut pt_addr = paddr_to_vaddr(root_paddr);
1587 #[verusfmt::skip]
1588 for cur_level in (1..= C::NR_LEVELS()).rev() {
1589 let offset = pte_index::<C>(vaddr, cur_level);
1590 let cur_pte = unsafe { load_pte((pt_addr as *mut C::E).add(offset), Ordering::Acquire) };
1596
1597 if !cur_pte.is_present() {
1598 return None;
1599 }
1600 if cur_pte.is_last(cur_level) {
1601 debug_assert!(cur_level <= C::HIGHEST_TRANSLATION_LEVEL);
1602 return Some(
1603 (cur_pte.paddr() + (vaddr & (page_size::<C>(cur_level) - 1)), cur_pte.prop()),
1604 );
1605 }
1606 pt_addr = paddr_to_vaddr(cur_pte.paddr());
1607 }
1608
1609 unreachable!("All present PTEs at the level 1 must be last-level PTEs");
1610}
1611
1612pub trait PageTableEntryTrait:
1616 Clone + Copy + Debug + Default + Sized + Pod + PodOnce + Send + Sync + 'static {
1617 spec fn new_absent_spec() -> Self;
1618
1619 #[verifier(when_used_as_spec(new_absent_spec))]
1623 fn new_absent() -> (res: Self)
1624 ensures
1625 valid_frame_paddr(res.paddr()),
1626 !res.is_present(),
1627 returns
1628 Self::new_absent(),
1629 ;
1630
1631 spec fn is_present_spec(&self) -> bool;
1632
1633 #[verifier::when_used_as_spec(is_present_spec)]
1639 fn is_present(&self) -> bool
1640 returns
1641 self.is_present_spec(),
1642 ;
1643
1644 spec fn new_page_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self;
1645
1646 spec fn new_page_req(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> bool;
1648
1649 #[verifier::when_used_as_spec(new_page_spec)]
1651 fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res: Self)
1652 requires
1653 paddr < MAX_PADDR,
1654 Self::new_page_req(paddr, level, prop),
1655 ensures
1656 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1657 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1658 valid_frame_paddr(res.paddr()),
1659 res.is_present(),
1660 res.is_last(level),
1661 res.prop() == prop,
1662 returns
1663 Self::new_page(paddr, level, prop),
1664 ;
1665
1666 spec fn new_pt_spec(paddr: Paddr) -> Self;
1667
1668 #[verifier::when_used_as_spec(new_pt_spec)]
1670 fn new_pt(paddr: Paddr) -> (res: Self)
1671 requires
1672 paddr < MAX_PADDR,
1673 ensures
1674 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1675 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1676 valid_frame_paddr(res.paddr()),
1677 res.is_present(),
1678 forall|level: PagingLevel| !res.is_last(level),
1679 returns
1680 Self::new_pt(paddr),
1681 ;
1682
1683 spec fn paddr_spec(&self) -> Paddr;
1689
1690 #[verifier::when_used_as_spec(paddr_spec)]
1691 fn paddr(&self) -> (res: Paddr)
1692 ensures
1693 valid_frame_paddr(res),
1694 returns
1695 self.paddr(),
1696 ;
1697
1698 spec fn prop_spec(&self) -> PageProperty;
1699
1700 #[verifier::when_used_as_spec(prop_spec)]
1701 fn prop(&self) -> PageProperty
1702 returns
1703 self.prop(),
1704 ;
1705
1706 spec fn set_prop_req(self, prop: PageProperty) -> bool;
1708
1709 fn set_prop(&mut self, prop: PageProperty)
1710 requires
1711 old(self).set_prop_req(prop),
1712 ensures
1713 !old(self).is_present() ==> *old(self) == *final(self),
1714 old(self).is_present() ==> {
1715 &&& final(self).prop() == prop
1716 &&& final(self).paddr() == old(self).paddr()
1717 &&& final(self).is_present()
1718 &&& forall|level: PagingLevel|
1719 #![trigger old(self).is_last(level)]
1720 old(self).is_last(level) ==> final(self).is_last(level)
1721 },
1722 ;
1723
1724 spec fn is_last_spec(&self, level: PagingLevel) -> bool;
1725
1726 #[verifier::when_used_as_spec(is_last_spec)]
1731 fn is_last(&self, level: PagingLevel) -> bool
1732 returns
1733 self.is_last_spec(level),
1734 ;
1735
1736 spec fn as_usize_spec(self) -> usize;
1737
1738 #[verifier::external_body]
1740 #[verifier::when_used_as_spec(as_usize_spec)]
1741 fn as_usize(self) -> usize
1742 returns
1743 self.as_usize(),
1744 {
1745 unimplemented!()
1746 }
1751
1752 #[verifier::external_body]
1754 fn from_usize(pte_raw: usize) -> Self {
1755 unimplemented!()
1756 }
1761
1762 proof fn lemma_page_table_entry_properties()
1764 ensures
1765 core::mem::size_of::<Self>() == core::mem::size_of::<usize>(),
1766 core::mem::size_of::<Self>() % core::mem::align_of::<Self>() == 0,
1767 core::mem::align_of::<Self>() > 0,
1768 valid_frame_paddr(Self::new_absent().paddr()),
1769 !Self::new_absent().is_present(),
1770 forall|level: PagingLevel|
1771 #![trigger Self::new_absent().is_last(level)]
1772 1 < level ==> !Self::new_absent().is_last(level),
1773 forall|paddr: Paddr, level: PagingLevel, prop: PageProperty|
1774 #![trigger Self::new_page(paddr, level, prop)]
1775 Self::new_page_req(paddr, level, prop) && (prop.cache is Writeback
1776 || prop.cache is Writethrough || prop.cache is Uncacheable) ==> {
1777 &&& Self::new_page(paddr, level, prop).is_present()
1778 &&& (paddr < MAX_PADDR ==> Self::new_page(paddr, level, prop).paddr() == paddr
1779 & !((PAGE_SIZE - 1) as usize))
1780 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_page(
1781 paddr,
1782 level,
1783 prop,
1784 ).paddr() == paddr)
1785 &&& Self::new_page(paddr, level, prop).prop() == prop
1786 &&& Self::new_page(paddr, level, prop).is_last(level)
1787 },
1788 forall|paddr: Paddr|
1789 #![trigger Self::new_pt(paddr)]
1790 {
1791 &&& Self::new_pt(paddr).is_present()
1792 &&& (paddr < MAX_PADDR ==> Self::new_pt(paddr).paddr() == paddr & !((PAGE_SIZE
1793 - 1) as usize))
1794 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_pt(paddr).paddr()
1795 == paddr)
1796 &&& forall|level: PagingLevel| !Self::new_pt(paddr).is_last(level)
1797 },
1798 ;
1799
1800 proof fn lemma_paddr_is_page_aligned(self)
1801 ensures
1802 self.paddr() % PAGE_SIZE == 0,
1803 ;
1804}
1805
1806#[verifier::external_body]
1821#[verus_spec(
1822 with Tracked(perm): Tracked<&vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1823 requires
1824 perm.is_init(ptr.index as int),
1825 perm.addr() == ptr.addr(),
1826 0 <= ptr.index < NR_ENTRIES,
1827 returns
1828 perm.value()[ptr.index as int],
1829)]
1830pub unsafe fn load_pte<E: PageTableEntryTrait>(
1831 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1832 ordering: Ordering,
1833) -> (pte: E) {
1834 unimplemented!()
1835}
1836
1837#[verifier::external_body]
1850#[verus_spec(
1851 with Tracked(perm): Tracked<&mut vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1852 requires
1853 old(perm).addr() == ptr.addr(),
1854 0 <= ptr.index < NR_ENTRIES,
1855 old(perm).is_init_all(),
1856 ensures
1857 final(perm).value()[ptr.index as int] == new_val,
1858 final(perm).value() == old(perm).value().update(ptr.index as int, new_val),
1859 final(perm).addr() == old(perm).addr(),
1860 final(perm).is_init_all(),
1861)]
1862pub unsafe fn store_pte<E: PageTableEntryTrait>(
1863 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1864 new_val: E,
1865 ordering: Ordering,
1866);
1867
1868}