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_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::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_owner(pa).ref_count() == old_regions.slot_owner(pa).ref_count()
373 + 1
374 &&& new_regions.slot_owner(pa).ref_count_perm.id() == old_regions.slot_owner(
375 pa,
376 ).ref_count_perm.id()
377 &&& new_regions.slot_owner(pa).storage_perm() == old_regions.slot_owner(
378 pa,
379 ).storage_perm()
380 &&& new_regions.slot_owner(pa).vtable_ptr_perm() == old_regions.slot_owner(
381 pa,
382 ).vtable_ptr_perm()
383 &&& new_regions.slot_owner(pa).in_list_perm == old_regions.slot_owner(
384 pa,
385 ).in_list_perm
386 &&& new_regions.slot_owner(pa).paths_in_pt == old_regions.slot_owner(pa).paths_in_pt
387 &&& new_regions.slot_owner(pa).slot_vaddr == old_regions.slot_owner(pa).slot_vaddr
388 &&& new_regions.slot_owner(pa).usage == old_regions.slot_owner(pa).usage
389 },
390 !Self::tracked(item) ==> new_regions.slot_owner(pa) == old_regions.slot_owner(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.contains(frame_to_index(pa)),
416 Self::tracked(item) ==> regions.slot_owner(pa).ref_count() > 0,
417 Self::tracked(item) ==> regions.slot_owner(pa).ref_count() != REF_COUNT_UNUSED,
419 Self::tracked(item) ==> (regions.slot_owner(pa).ref_count() < REF_COUNT_MAX
421 || may_panic()),
422 ensures
423 item.clone_requires(regions),
424 ;
425
426 proof fn lemma_page_table_config_constant_requirements()
433 ensures
434 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
435 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end,
436 Self::TOP_LEVEL_INDEX_RANGE().end <= pow2(
437 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
438 Self::C::NR_LEVELS(),
439 )) as nat,
440 ),
441 Self::TOP_LEVEL_INDEX_RANGE().end * pow2(
442 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
443 ) <= usize::MAX,
444 Self::LEADING_BITS_spec() != 0usize ==> (Self::C::VA_SIGN_EXT() && ((
445 Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
446 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
447 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1),
448 (Self::C::VA_SIGN_EXT() && (((Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
449 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
450 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1)) ==> {
451 &&& Self::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int
452 - pow2(Self::C::ADDRESS_WIDTH() as nat)
453 },
454 Self::LEADING_BITS_spec() < 0x1_0000_usize,
455 pow2(
457 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
458 Self::C::NR_LEVELS(),
459 )) as nat,
460 ) == NR_ENTRIES,
461 ;
462
463 proof fn lemma_page_table_config_constant_properties()
467 ensures
468 Self::TOP_LEVEL_INDEX_RANGE().end <= NR_ENTRIES,
471 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
474 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end,
475 Self::TOP_LEVEL_INDEX_RANGE().end <= pow2(
476 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
477 Self::C::NR_LEVELS(),
478 )) as nat,
479 ),
480 Self::TOP_LEVEL_INDEX_RANGE().end * pow2(
481 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
482 ) <= usize::MAX,
483 Self::LEADING_BITS_spec() != 0usize ==> (Self::C::VA_SIGN_EXT() && ((
484 Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
485 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
486 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1),
487 (Self::C::VA_SIGN_EXT() && (((Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
488 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
489 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1)) ==> {
490 &&& Self::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int
491 - pow2(Self::C::ADDRESS_WIDTH() as nat)
492 },
493 Self::LEADING_BITS_spec() < 0x1_0000_usize,
494 pow2(
496 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
497 Self::C::NR_LEVELS(),
498 )) as nat,
499 ) == NR_ENTRIES,
500 {
501 Self::C::lemma_paging_consts_properties();
502 Self::lemma_page_table_config_constant_requirements();
503 }
504}
505
506impl<C: PageTableConfig> PagingConstsTrait for C {
509 open spec fn BASE_PAGE_SIZE_spec() -> usize {
510 C::C::BASE_PAGE_SIZE_spec()
511 }
512
513 fn BASE_PAGE_SIZE() -> usize {
514 C::C::BASE_PAGE_SIZE()
515 }
516
517 open spec fn NR_LEVELS_spec() -> PagingLevel {
518 C::C::NR_LEVELS_spec()
519 }
520
521 fn NR_LEVELS() -> PagingLevel {
522 proof {
523 assert(Self::NR_LEVELS() == C::C::NR_LEVELS());
524 }
525 C::C::NR_LEVELS()
526 }
527
528 open spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel {
529 C::C::HIGHEST_TRANSLATION_LEVEL_spec()
530 }
531
532 fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel {
533 C::C::HIGHEST_TRANSLATION_LEVEL()
534 }
535
536 open spec fn PTE_SIZE_spec() -> usize {
537 C::C::PTE_SIZE_spec()
538 }
539
540 fn PTE_SIZE() -> usize {
541 C::C::PTE_SIZE()
542 }
543
544 open spec fn ADDRESS_WIDTH_spec() -> usize {
545 C::C::ADDRESS_WIDTH_spec()
546 }
547
548 fn ADDRESS_WIDTH() -> usize {
549 C::C::ADDRESS_WIDTH()
550 }
551
552 open spec fn VA_SIGN_EXT_spec() -> bool {
553 C::C::VA_SIGN_EXT_spec()
554 }
555
556 fn VA_SIGN_EXT() -> bool {
557 C::C::VA_SIGN_EXT()
558 }
559
560 proof fn lemma_paging_consts_requirements() {
561 C::C::lemma_paging_consts_requirements();
562 }
563}
564
565#[verifier::external_body]
590pub fn largest_pages<C: PageTableConfig>(
591 mut va: Vaddr,
592 mut pa: Paddr,
593 mut len: usize,
594) -> impl Iterator<Item = (Paddr, PagingLevel)> {
595 assert_eq!(va % C::BASE_PAGE_SIZE(), 0);
596 assert_eq!(pa % C::BASE_PAGE_SIZE(), 0);
597 assert_eq!(len % C::BASE_PAGE_SIZE(), 0);
598 assert!(is_valid_range::<C>(&(va..(va + len))));
599
600 core::iter::from_fn(
601 move ||
602 {
603 if len == 0 {
604 return None;
605 }
606 let mut level = C::HIGHEST_TRANSLATION_LEVEL();
607 while page_size(level) > len || va % page_size(level) != 0 || pa % page_size(level)
608 != 0 {
609 level -= 1;
610 }
611
612 let item_start = pa;
613 va += page_size(level);
614 pa += page_size(level);
615 len -= page_size(level);
616
617 Some((item_start, level))
618 },
619 )
620}
621
622fn top_level_index_width<C: PageTableConfig>() -> (ret: usize)
624 returns
625 top_level_index_width_spec::<C>(),
626{
627 proof {
628 C::lemma_paging_consts_properties();
629 C::lemma_page_table_config_constant_properties();
630 }
631
632 C::ADDRESS_WIDTH() - pte_index_bit_offset::<C>(C::NR_LEVELS())
633}
634
635fn pt_va_range_start<C: PageTableConfig>() -> (ret: Vaddr)
636 ensures
637 ret == C::TOP_LEVEL_INDEX_RANGE().start * pow2(
638 pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat,
639 ),
640{
641 proof {
642 C::lemma_paging_consts_properties();
643 let ghost idx_start = C::TOP_LEVEL_INDEX_RANGE().start;
644 let ghost offset = pte_index_bit_offset_spec::<C>(C::NR_LEVELS());
645 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_start_shift_facts::<C>(
646 idx_start,
647 offset,
648 );
649 vstd::bits::lemma_usize_shl_is_mul(idx_start, offset);
650 }
651
652 C::TOP_LEVEL_INDEX_RANGE().start << pte_index_bit_offset::<C>(C::NR_LEVELS())
653}
654
655fn pt_va_range_end<C: PageTableConfig>() -> (ret: Vaddr)
661 ensures
662 ret == (C::TOP_LEVEL_INDEX_RANGE().end * pow2(
663 pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat,
664 ) - 1) % 0x1_0000_0000_0000_0000int,
665{
666 let idx_end = C::TOP_LEVEL_INDEX_RANGE().end;
667 proof {
668 C::lemma_paging_consts_properties();
669 }
670 let offset = pte_index_bit_offset::<C>(C::NR_LEVELS());
671
672 proof {
673 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_end_shift_facts::<C>(
674 idx_end,
675 offset,
676 );
677 vstd::bits::lemma_usize_shl_is_mul(idx_end, offset);
678 }
679
680 let shifted = idx_end << offset;
681 let ret = shifted.wrapping_sub(1);
682
683 proof {
684 assert(shifted == idx_end * pow2(offset as nat));
685 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_end_wrapping_sub::<C>(
686 idx_end,
687 offset,
688 shifted,
689 ret,
690 );
691 }
692 ret
693}
694
695fn sign_bit_of_va<C: PageTableConfig>(va: Vaddr) -> (ret: bool)
696 ensures
697 ret == ((va as int / pow2((C::ADDRESS_WIDTH() - 1) as nat) as int) % 2 == 1),
698{
699 proof {
700 C::lemma_paging_consts_properties();
701 C::lemma_page_table_config_constant_properties();
702 vstd::bits::lemma_usize_shr_is_div(va, (C::ADDRESS_WIDTH() - 1) as usize);
703 vstd::bits::lemma_usize_low_bits_mask_is_mod(va >> (C::ADDRESS_WIDTH() - 1), 1);
704 vstd::bits::lemma_low_bits_mask_values();
705 vstd::arithmetic::power2::lemma2_to64();
706 }
707 (va >> (C::ADDRESS_WIDTH() - 1)) & 1 != 0
708}
709
710fn apply_sign_ext<C: PageTableConfig>(va: Vaddr) -> (ret: Vaddr)
717 requires
718 va < pow2(C::ADDRESS_WIDTH() as nat),
719 C::ADDRESS_WIDTH() < usize::BITS,
720 C::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int - pow2(
721 C::ADDRESS_WIDTH() as nat,
722 ),
723 ensures
724 ret == va + C::LEADING_BITS_spec() * 0x1_0000_0000_0000int,
725{
726 let address_width = C::ADDRESS_WIDTH();
727 let low_bit = 1usize << address_width;
728 proof {
729 vstd::layout::unsigned_int_max_values();
730 vstd::bits::lemma_usize_pow2_no_overflow(address_width as nat);
731 vstd::bits::lemma_usize_shl_is_mul(1usize, address_width);
732 }
733 let low_mask = low_bit - 1;
734 let sign_ext_mask = !0 ^ low_mask;
735 let ret = va | sign_ext_mask;
736 proof {
737 assert(!0usize == 0xffff_ffff_ffff_ffffusize) by (compute_only);
738 assert(sign_ext_mask == usize::MAX - low_mask) by (bit_vector)
739 requires
740 sign_ext_mask == (!0usize ^ low_mask),
741 !0usize == 0xffff_ffff_ffff_ffffusize,
742 usize::MAX == 0xffff_ffff_ffff_ffffusize,
743 ;
744 assert(pow2(64) == 0x1_0000_0000_0000_0000nat) by {
745 vstd::arithmetic::power2::lemma2_to64();
746 };
747 assert(sign_ext_mask == 0x1_0000_0000_0000_0000int - pow2(address_width as nat));
748 assert(sign_ext_mask == C::LEADING_BITS_spec() * 0x1_0000_0000_0000int);
749
750 assert((va & sign_ext_mask) == 0usize) by (bit_vector)
751 requires
752 address_width < usize::BITS,
753 low_bit == 1usize << address_width,
754 low_mask == low_bit - 1,
755 sign_ext_mask == !0usize ^ low_mask,
756 va < low_bit,
757 ;
758 assert(ret == va + sign_ext_mask) by (bit_vector)
759 requires
760 ret == va | sign_ext_mask,
761 (va & sign_ext_mask) == 0usize,
762 ;
763 }
764 ret
765}
766
767#[verusfmt::skip]
774fn vaddr_range<C: PageTableConfig>() -> (ret: RangeInclusive<Vaddr>)
775 ensures
776 ret@ == vaddr_range_spec::<C>(),
777{
778 let mut start = pt_va_range_start::<C>();
779 let mut end = pt_va_range_end::<C>();
780
781 proof {
782 C::lemma_paging_consts_properties();
783 C::lemma_page_table_config_constant_properties();
784 crate::specs::mm::page_table::vaddr_range_proofs::lemma_idx_times_pow2_bound::<C>(
785 start,
786 end,
787 );
788 }
789
790 if C::VA_SIGN_EXT() && sign_bit_of_va::<C>(pt_va_range_start::<C>()) {
791 start = apply_sign_ext::<C>(start);
792 end = apply_sign_ext::<C>(end);
793 }
794 start..=end
795}
796
797fn is_valid_range<C: PageTableConfig>(r: &Range<Vaddr>) -> bool
799 requires
800 r.end > 0,
801 returns
802 is_valid_range_spec::<C>(*r),
803{
804 let va_range = vaddr_range::<C>();
805 (r.start == 0 && r.end == 0) || (*va_range.start() <= r.start && r.end - 1 <= *va_range.end())
806}
807
808fn nr_pte_index_bits<C: PagingConstsTrait>() -> usize
811 returns
812 nr_pte_index_bits_spec::<C>(),
813{
814 proof {
815 C::lemma_paging_consts_properties();
816 }
817 nr_subpage_per_huge::<C>().ilog2() as usize
818}
819
820fn pte_index<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel) -> (res: usize)
822 requires
823 1 <= level <= NR_LEVELS,
824 ensures
825 res == AbstractVaddr::from_vaddr(va).index[level - 1],
826{
827 proof {
828 let offset = pte_index_bit_offset_spec::<C>(level);
829 C::lemma_paging_consts_properties();
830 lemma_arch_specific_consts_properties::<C>();
831 assert(0 <= offset < usize::BITS) by (nonlinear_arith)
832 requires
833 1 <= level <= 4,
834 offset == 12 + 9 * (level - 1),
835 ;
836 lemma2_to64();
837 lemma2_to64_rest();
838 vstd::bits::lemma_usize_shr_is_div(va, pte_index_bit_offset_spec::<C>(level));
839 vstd::bits::lemma_low_bits_mask_values();
840 vstd::bits::lemma_usize_low_bits_mask_is_mod(
841 va >> pte_index_bit_offset_spec::<C>(level),
842 9,
843 );
844 }
845 (va >> pte_index_bit_offset::<C>(level)) & (nr_subpage_per_huge::<C>() - 1)
846}
847
848fn pte_index_bit_offset<C: PagingConstsTrait>(level: PagingLevel) -> usize
854 requires
855 1 <= level <= NR_LEVELS,
856 returns
857 pte_index_bit_offset_spec::<C>(level),
858{
859 proof {
860 C::lemma_paging_consts_properties();
861 lemma_arch_specific_consts_properties::<C>();
862 assert(12 + 9 * (level - 1) <= 39) by (nonlinear_arith)
863 requires
864 1 <= level <= NR_LEVELS,
865 NR_LEVELS == 4,
866 ;
867 }
868 C::BASE_PAGE_SIZE().ilog2() as usize + nr_pte_index_bits::<C>() * (level as usize - 1)
869}
870
871pub struct PageTable<C: PageTableConfig> {
874 pub root: PageTableNode<C>,
875}
876
877impl PageTable<KernelPtConfig> {
889 #[verifier::external_body]
891 pub(crate) fn new_kernel_page_table() -> Self {
892 unimplemented!()}
908
909 pub open spec fn create_user_pt_panic_condition(root_owner: NodeOwner<KernelPtConfig>) -> bool {
913 exists|i: usize|
914 #![trigger root_owner.children_perm.value()[i as int]]
915 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
916 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
917 let pte = root_owner.children_perm.value()[i as int];
918 ||| !pte.is_present()
919 ||| pte.is_last(root_owner.level)
920 }
921 }
922
923 #[verus_spec(r =>
928 with Tracked(kernel_owner): Tracked<&PageTableOwner<KernelPtConfig>>,
929 Tracked(regions): Tracked<&mut MetaRegionOwners>,
930 Tracked(guards): Tracked<&mut Guards<'rcu>>,
931 requires
932 kernel_owner.inv(),
933 old(regions).inv(),
934 kernel_owner.0.value().is_node(),
935 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
936 self.root.ptr.addr() == kernel_owner.0.value().node().meta_vaddr(),
938 kernel_owner.0.value().metaregion_sound(*old(regions)),
940 kernel_owner.metaregion_sound(*old(regions)),
944 old(guards).unlocked(kernel_owner.0.value().node().meta_vaddr()),
946 ensures
947 final(regions).inv(),
948 )]
949 pub(in crate::mm) fn create_user_page_table<'rcu, G: InAtomicMode + 'static>(
950 &'static self,
951 ) -> PageTable<UserPtConfig> {
952 let preempt_guard: &'rcu G = disable_preempt::<G>();
953
954 proof_decl! {
955 let tracked mut new_pt_owner: Option<PageTableOwner<UserPtConfig>> = None;
956 }
957 let ghost regions_before_alloc = *regions;
958 let new_pt: PageTable<UserPtConfig> = (
959 #[verus_spec(with Tracked(&mut new_pt_owner), Tracked(regions), Tracked(guards))]
960 PageTable::empty_with_owner());
961 let new_root = new_pt.root;
962 let ghost new_idx_g: int = crate::specs::mm::frame::mapping::frame_to_index(
964 new_pt_owner@.unwrap().0.value().meta_slot_paddr().unwrap(),
965 );
966 let ghost new_pt_owner_snap = new_pt_owner@.unwrap();
967 proof {
968 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
969 kernel_owner.0.value().meta_slot_paddr().unwrap(),
970 );
971 let new_idx = new_idx_g;
972 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
973 KernelPtConfig,
974 >::lemma_active_entry_not_in_free_pool(
975 kernel_owner.0.value(),
976 regions_before_alloc,
977 new_idx,
978 );
979 assert(kern_idx != new_idx);
980 assert(regions.slot_owners[kern_idx] == regions_before_alloc.slot_owners[kern_idx]);
981 assert(kernel_owner.metaregion_sound(*regions));
982 assert(!regions.contains(new_idx));
983 }
984
985 proof_decl! {
986 let tracked root_owner: &NodeOwner<KernelPtConfig>
987 = kernel_owner.0.tracked_borrow_value().tracked_borrow_node();
988 let tracked mut new_pt_owner_val: PageTableOwner<UserPtConfig>
989 = new_pt_owner.tracked_take();
990 let tracked mut new_node_owner: NodeOwner<UserPtConfig> = {
991 let tracked new_pt_value = new_pt_owner_val.0.tracked_borrow_mut_value();
992 new_pt_value.tracked_take_node()
993 };
994 let tracked mut entry_owner: &EntryOwner<KernelPtConfig>;
995 }
996
997 proof {
1000 assert(kernel_owner.0.value().is_node());
1001 assert(kernel_owner.0.value().metaregion_sound(*regions));
1002 }
1003 let ghost regions_before_self_borrow: MetaRegionOwners = *regions;
1004 let mut root_node = {
1005 #[verus_spec(with Tracked(regions))]
1006 let root_ref = self.root.borrow();
1007 #[verus_spec(with Tracked(root_owner), Tracked(guards))]
1008 root_ref.lock(preempt_guard)
1009 };
1010 let ghost regions_after_kroot_borrow: MetaRegionOwners = *regions;
1011 let mut new_node: PageTableGuard<'rcu, UserPtConfig> = {
1012 #[verus_spec(with Tracked(regions))]
1013 let new_ref = new_root.borrow();
1014 #[verus_spec(with Tracked(&new_node_owner), Tracked(guards))]
1015 new_ref.lock(preempt_guard)
1016 };
1017 proof {
1018 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
1019 kernel_owner.0.value().meta_slot_paddr().unwrap(),
1020 );
1021 assert(regions_before_self_borrow.slot_owners
1022 == regions_after_kroot_borrow.slot_owners);
1023 assert forall|k: int|
1024 regions_before_self_borrow.contains(k) implies regions_before_self_borrow.slots[k]
1025 == #[trigger] regions_after_kroot_borrow.slots[k] by {
1026 if k == kern_idx {
1027 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1028 KernelPtConfig,
1029 >::lemma_active_entry_not_in_free_pool(
1030 kernel_owner.0.value(),
1031 regions_before_self_borrow,
1032 k,
1033 );
1034 }
1035 };
1036 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1037 regions_before_self_borrow,
1038 regions_after_kroot_borrow,
1039 );
1040
1041 let new_idx = new_idx_g;
1042 assert(regions_before_alloc.contains(new_idx));
1043 assert(kern_idx != new_idx) by {
1044 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1045 KernelPtConfig,
1046 >::lemma_active_entry_not_in_free_pool(
1047 kernel_owner.0.value(),
1048 regions_before_alloc,
1049 new_idx,
1050 );
1051 };
1052
1053 assert(!regions_before_self_borrow.contains(new_idx));
1054 assert(!regions_after_kroot_borrow.contains(new_idx));
1055 assert forall|k: int|
1056 regions_after_kroot_borrow.contains(k) implies regions_after_kroot_borrow.slots[k]
1057 == #[trigger] regions.slots[k] by {};
1058 assert(kernel_owner.metaregion_sound(regions_before_alloc));
1059
1060 kernel_owner.0.lemma_subtree_satisfies_implies(
1061 kernel_owner.0.value().path,
1062 |
1063 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1064 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1065 |
1066 e.is_frame() && e.parent_level > 1 ==> {
1067 let pa = e.frame().mapped_pa;
1068 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1069 forall|j: usize|
1070 0 < j < nr_pages ==> {
1071 let sub_idx =
1072 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1073 (pa + j * PAGE_SIZE) as usize,
1074 );
1075 sub_idx != new_idx
1076 }
1077 },
1078 |
1079 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1080 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1081 |
1082 e.is_frame() && e.parent_level > 1 ==> {
1083 let pa = e.frame().mapped_pa;
1084 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1085 forall|j: usize|
1086 0 < j < nr_pages ==> {
1087 let sub_idx =
1088 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1089 (pa + j * PAGE_SIZE) as usize,
1090 );
1091 sub_idx != new_idx || (regions.contains(sub_idx)
1092 && regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1093 && regions.slot_owners[sub_idx].ref_count() > 0
1094 && regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX)
1095 }
1096 },
1097 );
1098 kernel_owner.metaregion_sound_preserved_one_slot_changed(
1099 regions_after_kroot_borrow,
1100 *regions,
1101 new_idx,
1102 );
1103 }
1104 let mut i: usize = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start;
1105 while i < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end
1106 invariant
1107 kernel_owner.inv(),
1108 kernel_owner.0.value().is_node(),
1109 regions.inv(),
1110 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
1111 i <= KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end,
1112 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i,
1113 *root_owner == kernel_owner.0.value().node(),
1115 root_owner.relate_guard(root_node),
1116 kernel_owner.metaregion_sound(*regions),
1118 new_node_owner.inv(),
1120 new_node_owner.relate_guard(new_node),
1121 regions.contains(new_node_owner.slot_index),
1122 decreases KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end - i,
1123 {
1124 proof {
1125 let kern_node = kernel_owner.0.value().node();
1126 assert forall|j: usize|
1127 #![trigger kern_node.children_perm.value()[j as int]]
1128 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1129 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end implies {
1130 let pte = kern_node.children_perm.value()[j as int];
1131 pte.is_present() && !pte.is_last(kern_node.level)
1132 } by {
1133 let pte = kern_node.children_perm.value()[j as int];
1134 if !pte.is_present() || pte.is_last(kern_node.level) {
1135 assert(Self::create_user_pt_panic_condition(kern_node));
1136 }
1137 }
1138
1139 kernel_owner.pt_inv_unroll(i as int);
1140 let tracked child_subtree: &OwnerSubtree<KernelPtConfig> =
1141 kernel_owner.0.tracked_borrow_child(i as int);
1142 entry_owner = child_subtree.tracked_borrow_value();
1143 let kern_node = kernel_owner.0.value().node();
1144 assert(entry_owner.match_pte(
1145 kern_node.children_perm.value()[i as int],
1146 entry_owner.parent_level,
1147 ));
1148 assert(entry_owner.parent_level == kern_node.level);
1149 assert(child_subtree.inv());
1150 assert(entry_owner.inv());
1151 assert(root_owner.relate_guard(root_node));
1152
1153 kernel_owner.0.lemma_subtree_satisfies_unroll_once(
1154 kernel_owner.0.value().path,
1155 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1156 i as int,
1157 );
1158 assert(child_subtree.subtree_satisfies(
1159 kernel_owner.0.value().path.push_tail(i as int),
1160 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1161 ));
1162 assert(entry_owner.metaregion_sound(*regions));
1163 }
1164
1165 #[verus_spec(with Tracked(root_owner), Tracked(entry_owner), Tracked(&*regions))]
1166 let root_entry = root_node.entry(i);
1167 let ghost pre_to_ref_regions: MetaRegionOwners = *regions;
1168 #[verus_spec(with Tracked(entry_owner), Tracked(root_owner), Tracked(regions))]
1169 let child = root_entry.to_ref();
1170
1171 proof {
1172 let kern_node = kernel_owner.0.value().node();
1173 let pte = kern_node.children_perm.value()[i as int];
1174
1175 assert(pte.is_present() && !pte.is_last(kern_node.level)) by {
1176 if !pte.is_present() || pte.is_last(kern_node.level) {
1177 assert(KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
1178 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end);
1179 assert(exists|j: usize|
1180 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1181 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
1182 let p = #[trigger] kern_node.children_perm.value()[j as int];
1183 ||| !p.is_present()
1184 ||| p.is_last(kern_node.level)
1185 });
1186 assert(Self::create_user_pt_panic_condition(kern_node));
1187 }
1188 }
1189 assert(entry_owner.is_node());
1192 assert(child is PageTable);
1196 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1200 pre_to_ref_regions,
1201 *regions,
1202 );
1203 }
1204 let pt = match child {
1205 ChildRef::PageTable(pt) => pt,
1206 _ => vstd::pervasive::unreached(),
1207 };
1208
1209 let ghost entry_node_slot_idx = entry_owner.tracked_borrow_node().slot_index;
1210 let tracked entry_node_slot_perm = regions.slots.tracked_borrow(entry_node_slot_idx);
1211 #[verus_spec(with Tracked(entry_node_slot_perm))]
1212 let pt_addr = pt.start_paddr();
1213 let pte = PageTableEntry::new_pt(pt_addr);
1214
1215 proof {
1216 assert(regions.contains(new_node_owner.slot_index));
1217 }
1218 unsafe {
1219 #[verus_spec(with Tracked(&mut new_node_owner), Tracked(&*regions))]
1220 new_node.write_pte(i, pte)
1221 };
1222
1223 i = i + 1;
1224 }
1225
1226 PageTable::<UserPtConfig> { root: new_root }
1227 }}
1253
1254#[verus_verify]
1255impl<C: PageTableConfig> PageTable<C> {
1256 pub open spec fn relates_owner(
1258 &self,
1259 owner: PageTableOwner<C>,
1260 regions: MetaRegionOwners,
1261 ) -> bool {
1262 &&& owner.inv()
1263 &&& self.root.ptr.addr() == owner.0.value().node().meta_vaddr()
1264 &&& owner.metaregion_sound(regions)
1265 }
1266
1267 #[verifier::external_body]
1271 pub fn empty() -> Self {
1272 unimplemented!()
1273 }
1274
1275 #[verifier::external_body]
1277 #[verus_spec(r =>
1278 with Tracked(owner): Tracked<&mut Option<PageTableOwner<C>>>,
1279 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1280 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1281 requires
1282 old(regions).inv(),
1283 ensures
1284 final(owner)@ is Some,
1285 final(owner)@->0.inv(),
1286 (final(owner)@->0).0.value().is_node(),
1287 (final(owner)@->0).0.value().is_node(),
1288 r.root.ptr.addr() == (final(owner)@->0).0.value().node().meta_vaddr(),
1289 (final(owner)@->0).0.value().metaregion_sound(*final(regions)),
1290 final(regions).inv(),
1291 final(guards).unlocked((final(owner)@->0).0.value().node().meta_vaddr()),
1292 final(guards).guards == old(guards).guards,
1295 old(regions).contains(
1297 crate::specs::mm::frame::mapping::frame_to_index(
1298 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1299 !final(regions).contains(
1302 crate::specs::mm::frame::mapping::frame_to_index(
1303 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1304 forall |i: int| #![trigger final(regions).slot_owners[i]]
1306 i != crate::specs::mm::frame::mapping::frame_to_index(
1307 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1308 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
1309 forall |a: usize| old(guards).lock_held(a) ==> final(guards).lock_held(a),
1310 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1311 final(regions).slot_owners[idx].paths_in_pt
1312 == old(regions).slot_owners[idx].paths_in_pt,
1313 forall |kt: PageTableOwner<KernelPtConfig>|
1319 #![trigger kt.metaregion_sound(*final(regions))]
1320 kt.inv() && kt.metaregion_sound(*old(regions))
1321 ==> kt.metaregion_sound(*final(regions)),
1322 forall |kt: PageTableOwner<KernelPtConfig>|
1327 #![trigger kt.metaregion_sound(*old(regions))]
1328 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1329 kt.0.subtree_satisfies(
1330 kt.0.value().path,
1331 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1332 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1333 e.meta_slot_paddr() is Some
1334 ==> crate::specs::mm::frame::mapping::frame_to_index(
1335 e.meta_slot_paddr()->0) !=
1336 crate::specs::mm::frame::mapping::frame_to_index(
1337 (final(owner)@->0).0.value().meta_slot_paddr()->0),
1338 ),
1339 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.is_frame() && e.parent_level > 1 ==> {
1350 let pa = e.frame().mapped_pa;
1351 let nr_pages = page_size(
1352 e.parent_level) / PAGE_SIZE;
1353 forall |j: usize| 0 < j < nr_pages ==> {
1354 let sub_idx =
1355 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1356 (pa + j * PAGE_SIZE) as usize);
1357 sub_idx != crate::specs::mm::frame::mapping::frame_to_index(
1358 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1359 }
1360 },
1361 ),
1362 )]
1363 pub fn empty_with_owner<'rcu>() -> Self {
1364 unimplemented!()
1365 }
1366
1367 #[verifier::external_body]
1368 pub(in crate::mm) unsafe fn first_activate_unchecked(&self) {
1369 unimplemented!()
1370 }
1374
1375 pub uninterp spec fn root_paddr_spec(&self) -> Paddr;
1376
1377 #[verifier::external_body]
1383 #[verifier::when_used_as_spec(root_paddr_spec)]
1384 pub fn root_paddr(&self) -> (r: Paddr)
1385 returns
1386 self.root_paddr_spec(),
1387 {
1388 unimplemented!()
1389 }
1392
1393 #[cfg(ktest)]
1399 pub fn page_walk(&self, vaddr: Vaddr) -> Option<(Paddr, PageProperty)> {
1400 unsafe { page_walk::<C>(self.root_paddr(), vaddr) }
1402 }
1403
1404 #[verus_spec(r =>
1409 with Tracked(owner): Tracked<PageTableOwner<C>>,
1410 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1411 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1412 Tracked(guards): Tracked<&mut Guards<'rcu>>
1413 requires
1414 self.relates_owner(owner, *old(regions)),
1415 owner.0.value().node().relate_guard(root_guard),
1416 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1418 ensures
1419 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1420 &&& r is Ok
1421 &&& r.unwrap().0.0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1422 &&& r.unwrap().1.in_locked_range()
1423 &&& r.unwrap().0.0.level == r.unwrap().0.0.guard_level
1424 &&& r.unwrap().0.0.guard_level == NR_LEVELS as PagingLevel
1425 &&& r.unwrap().0.0.va < r.unwrap().0.0.barrier_va.end
1426 &&& r.unwrap().0.0.va == va.start
1427 &&& r.unwrap().0.0.barrier_va == *va
1428 },
1429 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1430 forall |item: C::Item| #![trigger CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions))]
1431 CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions)) ==>
1432 CursorMut::<'rcu, C, G>::item_not_mapped(item, *final(regions)),
1433 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1437 old(regions).slot_owners[idx].ref_count()
1438 != REF_COUNT_UNUSED
1439 ==> final(regions).slot_owners[idx].paths_in_pt
1440 == old(regions).slot_owners[idx].paths_in_pt,
1441 forall|idx: int| #![trigger final(regions).slot_owners[idx]]
1442 old(regions).contains(idx)
1443 && old(regions).slot_owners[idx].ref_count()
1444 != REF_COUNT_UNUSED
1445 ==> final(regions).slot_owners[idx].ref_count()
1446 == old(regions).slot_owners[idx].ref_count()
1447 && final(regions).slot_owners[idx].usage
1448 == old(regions).slot_owners[idx].usage,
1449 )]
1450 pub fn cursor_mut<'rcu, G: InAtomicMode>(
1451 &'rcu self,
1452 guard: &'rcu G,
1453 va: &Range<Vaddr>,
1454 ) -> Result<(CursorMut<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>), PageTableError> {
1455 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1456 CursorMut::new(self, guard, va)
1457 }
1458
1459 #[verus_spec(r =>
1465 with Tracked(owner): Tracked<PageTableOwner<C>>,
1466 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1467 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1468 Tracked(guards): Tracked<&mut Guards<'rcu>>
1469 requires
1470 self.relates_owner(owner, *old(regions)),
1471 owner.0.value().node().relate_guard(root_guard),
1472 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1474 ensures
1475 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1476 &&& r is Ok
1477 &&& r.unwrap().0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1478 &&& r.unwrap().1.in_locked_range()
1479 &&& r.unwrap().0.level == r.unwrap().0.guard_level
1480 &&& r.unwrap().0.va < r.unwrap().0.barrier_va.end
1481 &&& r.unwrap().0.va == va.start
1482 &&& r.unwrap().0.barrier_va == *va
1483 &&& r.unwrap().1@.as_page_table_owner() == owner
1484 &&& r.unwrap().1@.continuations[3].path() == owner.0.value().path
1485 },
1486 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1487 forall|idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1488 old(regions).slot_owners[idx].ref_count()
1489 != REF_COUNT_UNUSED
1490 ==> final(regions).slot_owners[idx].paths_in_pt
1491 == old(regions).slot_owners[idx].paths_in_pt,
1492 (forall |i: int| #![trigger old(regions).slot_owners[i]]
1494 old(regions).contains(i)
1495 && old(regions).slot_owners[i].ref_count()
1496 != REF_COUNT_UNUSED
1497 ==> old(regions).slot_owners[i].ref_count() + 1
1498 < REF_COUNT_MAX)
1499 ==>
1500 (forall |i: int| #![trigger final(regions).slot_owners[i]]
1501 final(regions).contains(i)
1502 && final(regions).slot_owners[i].ref_count()
1503 != REF_COUNT_UNUSED
1504 ==> final(regions).slot_owners[i].ref_count() + 1
1505 < REF_COUNT_MAX),
1506 forall|idx: int| #![trigger final(regions).slot_owners[idx].ref_count()]
1511 final(regions).slot_owners[idx].ref_count()
1512 >= REF_COUNT_MAX
1513 ==> old(regions).slot_owners[idx].ref_count()
1514 == final(regions).slot_owners[idx].ref_count(),
1515 forall|idx: int| #![trigger old(regions).slot_owners[idx].ref_count()]
1516 old(regions).slot_owners[idx].ref_count()
1517 >= REF_COUNT_MAX
1518 ==> final(regions).slot_owners[idx].ref_count()
1519 == old(regions).slot_owners[idx].ref_count(),
1520 )]
1521 pub fn cursor<'rcu, G: InAtomicMode>(&'rcu self, guard: &'rcu G, va: &Range<Vaddr>) -> Result<
1522 (Cursor<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>),
1523 PageTableError,
1524 > {
1525 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1526 Cursor::new(self, guard, va)
1527 }}
1539
1540#[cfg(ktest)]
1563pub(super) unsafe fn page_walk<C: PageTableConfig>(root_paddr: Paddr, vaddr: Vaddr) -> Option<
1564 (Paddr, PageProperty),
1565> {
1566 use super::paddr_to_vaddr;
1567
1568 let _rcu_guard = disable_preempt();
1569
1570 let mut pt_addr = paddr_to_vaddr(root_paddr);
1571 #[verusfmt::skip]
1572 for cur_level in (1..= C::NR_LEVELS()).rev() {
1573 let offset = pte_index::<C>(vaddr, cur_level);
1574 let cur_pte = unsafe { load_pte((pt_addr as *mut C::E).add(offset), Ordering::Acquire) };
1580
1581 if !cur_pte.is_present() {
1582 return None;
1583 }
1584 if cur_pte.is_last(cur_level) {
1585 debug_assert!(cur_level <= C::HIGHEST_TRANSLATION_LEVEL);
1586 return Some(
1587 (cur_pte.paddr() + (vaddr & (page_size::<C>(cur_level) - 1)), cur_pte.prop()),
1588 );
1589 }
1590 pt_addr = paddr_to_vaddr(cur_pte.paddr());
1591 }
1592
1593 unreachable!("All present PTEs at the level 1 must be last-level PTEs");
1594}
1595
1596pub trait PageTableEntryTrait:
1600 Clone + Copy + Debug + Default + Sized + Pod + PodOnce + Send + Sync + 'static {
1601 spec fn new_absent_spec() -> Self;
1602
1603 #[verifier(when_used_as_spec(new_absent_spec))]
1607 fn new_absent() -> (res: Self)
1608 ensures
1609 valid_frame_paddr(res.paddr()),
1610 !res.is_present(),
1611 returns
1612 Self::new_absent(),
1613 ;
1614
1615 spec fn is_present_spec(&self) -> bool;
1616
1617 #[verifier::when_used_as_spec(is_present_spec)]
1623 fn is_present(&self) -> bool
1624 returns
1625 self.is_present_spec(),
1626 ;
1627
1628 spec fn new_page_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self;
1629
1630 spec fn new_page_req(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> bool;
1632
1633 #[verifier::when_used_as_spec(new_page_spec)]
1635 fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res: Self)
1636 requires
1637 paddr < MAX_PADDR,
1638 Self::new_page_req(paddr, level, prop),
1639 ensures
1640 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1641 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1642 valid_frame_paddr(res.paddr()),
1643 res.is_present(),
1644 res.is_last(level),
1645 res.prop() == prop,
1646 returns
1647 Self::new_page(paddr, level, prop),
1648 ;
1649
1650 spec fn new_pt_spec(paddr: Paddr) -> Self;
1651
1652 #[verifier::when_used_as_spec(new_pt_spec)]
1654 fn new_pt(paddr: Paddr) -> (res: Self)
1655 requires
1656 paddr < MAX_PADDR,
1657 ensures
1658 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1659 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1660 valid_frame_paddr(res.paddr()),
1661 res.is_present(),
1662 forall|level: PagingLevel| !res.is_last(level),
1663 returns
1664 Self::new_pt(paddr),
1665 ;
1666
1667 spec fn paddr_spec(&self) -> Paddr;
1673
1674 #[verifier::when_used_as_spec(paddr_spec)]
1675 fn paddr(&self) -> (res: Paddr)
1676 ensures
1677 valid_frame_paddr(res),
1678 returns
1679 self.paddr(),
1680 ;
1681
1682 spec fn prop_spec(&self) -> PageProperty;
1683
1684 #[verifier::when_used_as_spec(prop_spec)]
1685 fn prop(&self) -> PageProperty
1686 returns
1687 self.prop(),
1688 ;
1689
1690 spec fn set_prop_req(self, prop: PageProperty) -> bool;
1692
1693 fn set_prop(&mut self, prop: PageProperty)
1694 requires
1695 old(self).set_prop_req(prop),
1696 ensures
1697 !old(self).is_present() ==> *old(self) == *final(self),
1698 old(self).is_present() ==> {
1699 &&& final(self).prop() == prop
1700 &&& final(self).paddr() == old(self).paddr()
1701 &&& final(self).is_present()
1702 &&& forall|level: PagingLevel|
1703 #![trigger old(self).is_last(level)]
1704 old(self).is_last(level) ==> final(self).is_last(level)
1705 },
1706 ;
1707
1708 spec fn is_last_spec(&self, level: PagingLevel) -> bool;
1709
1710 #[verifier::when_used_as_spec(is_last_spec)]
1715 fn is_last(&self, level: PagingLevel) -> bool
1716 returns
1717 self.is_last_spec(level),
1718 ;
1719
1720 spec fn as_usize_spec(self) -> usize;
1721
1722 #[verifier::external_body]
1724 #[verifier::when_used_as_spec(as_usize_spec)]
1725 fn as_usize(self) -> usize
1726 returns
1727 self.as_usize(),
1728 {
1729 unimplemented!()
1730 }
1735
1736 #[verifier::external_body]
1738 fn from_usize(pte_raw: usize) -> Self {
1739 unimplemented!()
1740 }
1745
1746 proof fn lemma_page_table_entry_properties()
1748 ensures
1749 core::mem::size_of::<Self>() == core::mem::size_of::<usize>(),
1750 core::mem::size_of::<Self>() % core::mem::align_of::<Self>() == 0,
1751 core::mem::align_of::<Self>() > 0,
1752 valid_frame_paddr(Self::new_absent().paddr()),
1753 !Self::new_absent().is_present(),
1754 forall|level: PagingLevel|
1755 #![trigger Self::new_absent().is_last(level)]
1756 1 < level ==> !Self::new_absent().is_last(level),
1757 forall|paddr: Paddr, level: PagingLevel, prop: PageProperty|
1758 #![trigger Self::new_page(paddr, level, prop)]
1759 Self::new_page_req(paddr, level, prop) && (prop.cache is Writeback
1760 || prop.cache is Writethrough || prop.cache is Uncacheable) ==> {
1761 &&& Self::new_page(paddr, level, prop).is_present()
1762 &&& (paddr < MAX_PADDR ==> Self::new_page(paddr, level, prop).paddr() == paddr
1763 & !((PAGE_SIZE - 1) as usize))
1764 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_page(
1765 paddr,
1766 level,
1767 prop,
1768 ).paddr() == paddr)
1769 &&& Self::new_page(paddr, level, prop).prop() == prop
1770 &&& Self::new_page(paddr, level, prop).is_last(level)
1771 },
1772 forall|paddr: Paddr|
1773 #![trigger Self::new_pt(paddr)]
1774 {
1775 &&& Self::new_pt(paddr).is_present()
1776 &&& (paddr < MAX_PADDR ==> Self::new_pt(paddr).paddr() == paddr & !((PAGE_SIZE
1777 - 1) as usize))
1778 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_pt(paddr).paddr()
1779 == paddr)
1780 &&& forall|level: PagingLevel| !Self::new_pt(paddr).is_last(level)
1781 },
1782 ;
1783
1784 proof fn lemma_paddr_is_page_aligned(self)
1785 ensures
1786 self.paddr() % PAGE_SIZE == 0,
1787 ;
1788}
1789
1790#[verifier::external_body]
1805#[verus_spec(
1806 with Tracked(perm): Tracked<&vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1807 requires
1808 perm.is_init(ptr.index as int),
1809 perm.addr() == ptr.addr(),
1810 0 <= ptr.index < NR_ENTRIES,
1811 returns
1812 perm.value()[ptr.index as int],
1813)]
1814pub unsafe fn load_pte<E: PageTableEntryTrait>(
1815 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1816 ordering: Ordering,
1817) -> (pte: E) {
1818 unimplemented!()
1819}
1820
1821#[verifier::external_body]
1834#[verus_spec(
1835 with Tracked(perm): Tracked<&mut vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1836 requires
1837 old(perm).addr() == ptr.addr(),
1838 0 <= ptr.index < NR_ENTRIES,
1839 old(perm).is_init_all(),
1840 ensures
1841 final(perm).wf(),
1842 final(perm).value()[ptr.index as int] == new_val,
1843 final(perm).value() == old(perm).value().update(ptr.index as int, new_val),
1844 final(perm).addr() == old(perm).addr(),
1845 final(perm).is_init_all(),
1846)]
1847pub unsafe fn store_pte<E: PageTableEntryTrait>(
1848 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1849 new_val: E,
1850 ordering: Ordering,
1851);
1852
1853}