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 if k != new_idx {
1059 }
1061 };
1062 assert(kernel_owner.metaregion_sound(regions_before_alloc));
1063
1064 kernel_owner.0.lemma_subtree_satisfies_implies(
1065 kernel_owner.0.value().path,
1066 |
1067 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1068 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1069 |
1070 e.is_frame() && e.parent_level > 1 ==> {
1071 let pa = e.frame().mapped_pa;
1072 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1073 forall|j: usize|
1074 0 < j < nr_pages ==> {
1075 let sub_idx =
1076 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1077 (pa + j * PAGE_SIZE) as usize,
1078 );
1079 sub_idx != new_idx
1080 }
1081 },
1082 |
1083 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1084 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1085 |
1086 e.is_frame() && e.parent_level > 1 ==> {
1087 let pa = e.frame().mapped_pa;
1088 let nr_pages = page_size(e.parent_level) / PAGE_SIZE;
1089 forall|j: usize|
1090 0 < j < nr_pages ==> {
1091 let sub_idx =
1092 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1093 (pa + j * PAGE_SIZE) as usize,
1094 );
1095 sub_idx != new_idx || (regions.contains(sub_idx)
1096 && regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1097 && regions.slot_owners[sub_idx].ref_count() > 0
1098 && regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX)
1099 }
1100 },
1101 );
1102 kernel_owner.metaregion_sound_preserved_one_slot_changed(
1103 regions_after_kroot_borrow,
1104 *regions,
1105 new_idx,
1106 );
1107 }
1108 let mut i: usize = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start;
1109 while i < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end
1110 invariant
1111 kernel_owner.inv(),
1112 kernel_owner.0.value().is_node(),
1113 regions.inv(),
1114 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
1115 i <= KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end,
1116 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i,
1117 *root_owner == kernel_owner.0.value().node(),
1119 root_owner.relate_guard(root_node),
1120 kernel_owner.metaregion_sound(*regions),
1122 new_node_owner.inv(),
1124 new_node_owner.relate_guard(new_node),
1125 regions.contains(new_node_owner.slot_index),
1126 decreases KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end - i,
1127 {
1128 proof {
1129 let kern_node = kernel_owner.0.value().node();
1130 assert forall|j: usize|
1131 #![trigger kern_node.children_perm.value()[j as int]]
1132 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1133 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end implies {
1134 let pte = kern_node.children_perm.value()[j as int];
1135 pte.is_present() && !pte.is_last(kern_node.level)
1136 } by {
1137 let pte = kern_node.children_perm.value()[j as int];
1138 if !pte.is_present() || pte.is_last(kern_node.level) {
1139 assert(Self::create_user_pt_panic_condition(kern_node));
1140 }
1141 }
1142
1143 kernel_owner.pt_inv_unroll(i as int);
1144 let tracked child_subtree: &OwnerSubtree<KernelPtConfig> =
1145 kernel_owner.0.tracked_borrow_child(i as int);
1146 entry_owner = child_subtree.tracked_borrow_value();
1147 let kern_node = kernel_owner.0.value().node();
1148 assert(entry_owner.match_pte(
1149 kern_node.children_perm.value()[i as int],
1150 entry_owner.parent_level,
1151 ));
1152 assert(entry_owner.parent_level == kern_node.level);
1153 assert(child_subtree.inv());
1154 assert(entry_owner.inv());
1155 assert(root_owner.relate_guard(root_node));
1156
1157 kernel_owner.0.lemma_subtree_satisfies_unroll_once(
1158 kernel_owner.0.value().path,
1159 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1160 i as int,
1161 );
1162 assert(child_subtree.subtree_satisfies(
1163 kernel_owner.0.value().path.push_tail(i as int),
1164 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1165 ));
1166 assert(entry_owner.metaregion_sound(*regions));
1167 }
1168
1169 #[verus_spec(with Tracked(root_owner), Tracked(entry_owner), Tracked(&*regions))]
1170 let root_entry = root_node.entry(i);
1171 let ghost pre_to_ref_regions: MetaRegionOwners = *regions;
1172 #[verus_spec(with Tracked(entry_owner), Tracked(root_owner), Tracked(regions))]
1173 let child = root_entry.to_ref();
1174
1175 proof {
1176 let kern_node = kernel_owner.0.value().node();
1177 let pte = kern_node.children_perm.value()[i as int];
1178
1179 assert(pte.is_present() && !pte.is_last(kern_node.level)) by {
1180 if !pte.is_present() || pte.is_last(kern_node.level) {
1181 assert(KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
1182 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end);
1183 assert(exists|j: usize|
1184 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1185 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
1186 let p = #[trigger] kern_node.children_perm.value()[j as int];
1187 ||| !p.is_present()
1188 ||| p.is_last(kern_node.level)
1189 });
1190 assert(Self::create_user_pt_panic_condition(kern_node));
1191 }
1192 }
1193 assert(entry_owner.is_node());
1196 assert(child is PageTable);
1200 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1204 pre_to_ref_regions,
1205 *regions,
1206 );
1207 }
1208 let pt = match child {
1209 ChildRef::PageTable(pt) => pt,
1210 _ => vstd::pervasive::unreached(),
1211 };
1212
1213 let ghost entry_node_slot_idx = entry_owner.tracked_borrow_node().slot_index;
1214 let tracked entry_node_slot_perm = regions.slots.tracked_borrow(entry_node_slot_idx);
1215 #[verus_spec(with Tracked(entry_node_slot_perm))]
1216 let pt_addr = pt.start_paddr();
1217 let pte = PageTableEntry::new_pt(pt_addr);
1218
1219 proof {
1220 assert(regions.contains(new_node_owner.slot_index));
1221 }
1222 unsafe {
1223 #[verus_spec(with Tracked(&mut new_node_owner), Tracked(&*regions))]
1224 new_node.write_pte(i, pte)
1225 };
1226
1227 i = i + 1;
1228 }
1229
1230 PageTable::<UserPtConfig> { root: new_root }
1231 }}
1257
1258#[verus_verify]
1259impl<C: PageTableConfig> PageTable<C> {
1260 pub open spec fn relates_owner(
1262 &self,
1263 owner: PageTableOwner<C>,
1264 regions: MetaRegionOwners,
1265 ) -> bool {
1266 &&& owner.inv()
1267 &&& self.root.ptr.addr() == owner.0.value().node().meta_vaddr()
1268 &&& owner.metaregion_sound(regions)
1269 }
1270
1271 #[verifier::external_body]
1275 pub fn empty() -> Self {
1276 unimplemented!()
1277 }
1278
1279 #[verifier::external_body]
1281 #[verus_spec(r =>
1282 with Tracked(owner): Tracked<&mut Option<PageTableOwner<C>>>,
1283 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1284 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1285 requires
1286 old(regions).inv(),
1287 ensures
1288 final(owner)@ is Some,
1289 final(owner)@->0.inv(),
1290 (final(owner)@->0).0.value().is_node(),
1291 (final(owner)@->0).0.value().is_node(),
1292 r.root.ptr.addr() == (final(owner)@->0).0.value().node().meta_vaddr(),
1293 (final(owner)@->0).0.value().metaregion_sound(*final(regions)),
1294 final(regions).inv(),
1295 final(guards).unlocked((final(owner)@->0).0.value().node().meta_vaddr()),
1296 final(guards).guards == old(guards).guards,
1299 old(regions).contains(
1301 crate::specs::mm::frame::mapping::frame_to_index(
1302 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1303 !final(regions).contains(
1306 crate::specs::mm::frame::mapping::frame_to_index(
1307 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1308 forall |i: int| #![trigger final(regions).slot_owners[i]]
1310 i != crate::specs::mm::frame::mapping::frame_to_index(
1311 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1312 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
1313 forall |a: usize| old(guards).lock_held(a) ==> final(guards).lock_held(a),
1314 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1315 final(regions).slot_owners[idx].paths_in_pt
1316 == old(regions).slot_owners[idx].paths_in_pt,
1317 forall |kt: PageTableOwner<KernelPtConfig>|
1323 #![trigger kt.metaregion_sound(*final(regions))]
1324 kt.inv() && kt.metaregion_sound(*old(regions))
1325 ==> kt.metaregion_sound(*final(regions)),
1326 forall |kt: PageTableOwner<KernelPtConfig>|
1331 #![trigger kt.metaregion_sound(*old(regions))]
1332 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1333 kt.0.subtree_satisfies(
1334 kt.0.value().path,
1335 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1336 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1337 e.meta_slot_paddr() is Some
1338 ==> crate::specs::mm::frame::mapping::frame_to_index(
1339 e.meta_slot_paddr()->0) !=
1340 crate::specs::mm::frame::mapping::frame_to_index(
1341 (final(owner)@->0).0.value().meta_slot_paddr()->0),
1342 ),
1343 forall |kt: PageTableOwner<KernelPtConfig>|
1347 #![trigger kt.metaregion_sound(*old(regions))]
1348 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1349 kt.0.subtree_satisfies(
1350 kt.0.value().path,
1351 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1352 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1353 e.is_frame() && e.parent_level > 1 ==> {
1354 let pa = e.frame().mapped_pa;
1355 let nr_pages = page_size(
1356 e.parent_level) / PAGE_SIZE;
1357 forall |j: usize| 0 < j < nr_pages ==> {
1358 let sub_idx =
1359 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1360 (pa + j * PAGE_SIZE) as usize);
1361 sub_idx != crate::specs::mm::frame::mapping::frame_to_index(
1362 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1363 }
1364 },
1365 ),
1366 )]
1367 pub fn empty_with_owner<'rcu>() -> Self {
1368 unimplemented!()
1369 }
1370
1371 #[verifier::external_body]
1372 pub(in crate::mm) unsafe fn first_activate_unchecked(&self) {
1373 unimplemented!()
1374 }
1378
1379 pub uninterp spec fn root_paddr_spec(&self) -> Paddr;
1380
1381 #[verifier::external_body]
1387 #[verifier::when_used_as_spec(root_paddr_spec)]
1388 pub fn root_paddr(&self) -> (r: Paddr)
1389 returns
1390 self.root_paddr_spec(),
1391 {
1392 unimplemented!()
1393 }
1396
1397 #[cfg(ktest)]
1403 pub fn page_walk(&self, vaddr: Vaddr) -> Option<(Paddr, PageProperty)> {
1404 unsafe { page_walk::<C>(self.root_paddr(), vaddr) }
1406 }
1407
1408 #[verus_spec(r =>
1413 with Tracked(owner): Tracked<PageTableOwner<C>>,
1414 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1415 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1416 Tracked(guards): Tracked<&mut Guards<'rcu>>
1417 requires
1418 self.relates_owner(owner, *old(regions)),
1419 owner.0.value().node().relate_guard(root_guard),
1420 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1422 ensures
1423 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1424 &&& r is Ok
1425 &&& r.unwrap().0.0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1426 &&& r.unwrap().1.in_locked_range()
1427 &&& r.unwrap().0.0.level == r.unwrap().0.0.guard_level
1428 &&& r.unwrap().0.0.guard_level == NR_LEVELS as PagingLevel
1429 &&& r.unwrap().0.0.va < r.unwrap().0.0.barrier_va.end
1430 &&& r.unwrap().0.0.va == va.start
1431 &&& r.unwrap().0.0.barrier_va == *va
1432 },
1433 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1434 forall |item: C::Item| #![trigger CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions))]
1435 CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions)) ==>
1436 CursorMut::<'rcu, C, G>::item_not_mapped(item, *final(regions)),
1437 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1441 old(regions).slot_owners[idx].ref_count()
1442 != REF_COUNT_UNUSED
1443 ==> final(regions).slot_owners[idx].paths_in_pt
1444 == old(regions).slot_owners[idx].paths_in_pt,
1445 forall|idx: int| #![trigger final(regions).slot_owners[idx]]
1446 old(regions).contains(idx)
1447 && old(regions).slot_owners[idx].ref_count()
1448 != REF_COUNT_UNUSED
1449 ==> final(regions).slot_owners[idx].ref_count()
1450 == old(regions).slot_owners[idx].ref_count()
1451 && final(regions).slot_owners[idx].usage
1452 == old(regions).slot_owners[idx].usage,
1453 )]
1454 pub fn cursor_mut<'rcu, G: InAtomicMode>(
1455 &'rcu self,
1456 guard: &'rcu G,
1457 va: &Range<Vaddr>,
1458 ) -> Result<(CursorMut<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>), PageTableError> {
1459 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1460 CursorMut::new(self, guard, va)
1461 }
1462
1463 #[verus_spec(r =>
1469 with Tracked(owner): Tracked<PageTableOwner<C>>,
1470 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1471 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1472 Tracked(guards): Tracked<&mut Guards<'rcu>>
1473 requires
1474 self.relates_owner(owner, *old(regions)),
1475 owner.0.value().node().relate_guard(root_guard),
1476 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1478 ensures
1479 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1480 &&& r is Ok
1481 &&& r.unwrap().0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1482 &&& r.unwrap().1.in_locked_range()
1483 &&& r.unwrap().0.level == r.unwrap().0.guard_level
1484 &&& r.unwrap().0.va < r.unwrap().0.barrier_va.end
1485 &&& r.unwrap().0.va == va.start
1486 &&& r.unwrap().0.barrier_va == *va
1487 &&& r.unwrap().1@.as_page_table_owner() == owner
1488 &&& r.unwrap().1@.continuations[3].path() == owner.0.value().path
1489 },
1490 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1491 forall|idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1492 old(regions).slot_owners[idx].ref_count()
1493 != REF_COUNT_UNUSED
1494 ==> final(regions).slot_owners[idx].paths_in_pt
1495 == old(regions).slot_owners[idx].paths_in_pt,
1496 (forall |i: int| #![trigger old(regions).slot_owners[i]]
1498 old(regions).contains(i)
1499 && old(regions).slot_owners[i].ref_count()
1500 != REF_COUNT_UNUSED
1501 ==> old(regions).slot_owners[i].ref_count() + 1
1502 < REF_COUNT_MAX)
1503 ==>
1504 (forall |i: int| #![trigger final(regions).slot_owners[i]]
1505 final(regions).contains(i)
1506 && final(regions).slot_owners[i].ref_count()
1507 != REF_COUNT_UNUSED
1508 ==> final(regions).slot_owners[i].ref_count() + 1
1509 < REF_COUNT_MAX),
1510 forall|idx: int| #![trigger final(regions).slot_owners[idx].ref_count()]
1515 final(regions).slot_owners[idx].ref_count()
1516 >= REF_COUNT_MAX
1517 ==> old(regions).slot_owners[idx].ref_count()
1518 == final(regions).slot_owners[idx].ref_count(),
1519 forall|idx: int| #![trigger old(regions).slot_owners[idx].ref_count()]
1520 old(regions).slot_owners[idx].ref_count()
1521 >= REF_COUNT_MAX
1522 ==> final(regions).slot_owners[idx].ref_count()
1523 == old(regions).slot_owners[idx].ref_count(),
1524 )]
1525 pub fn cursor<'rcu, G: InAtomicMode>(&'rcu self, guard: &'rcu G, va: &Range<Vaddr>) -> Result<
1526 (Cursor<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>),
1527 PageTableError,
1528 > {
1529 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1530 Cursor::new(self, guard, va)
1531 }}
1543
1544#[cfg(ktest)]
1567pub(super) unsafe fn page_walk<C: PageTableConfig>(root_paddr: Paddr, vaddr: Vaddr) -> Option<
1568 (Paddr, PageProperty),
1569> {
1570 use super::paddr_to_vaddr;
1571
1572 let _rcu_guard = disable_preempt();
1573
1574 let mut pt_addr = paddr_to_vaddr(root_paddr);
1575 #[verusfmt::skip]
1576 for cur_level in (1..= C::NR_LEVELS()).rev() {
1577 let offset = pte_index::<C>(vaddr, cur_level);
1578 let cur_pte = unsafe { load_pte((pt_addr as *mut C::E).add(offset), Ordering::Acquire) };
1584
1585 if !cur_pte.is_present() {
1586 return None;
1587 }
1588 if cur_pte.is_last(cur_level) {
1589 debug_assert!(cur_level <= C::HIGHEST_TRANSLATION_LEVEL);
1590 return Some(
1591 (cur_pte.paddr() + (vaddr & (page_size::<C>(cur_level) - 1)), cur_pte.prop()),
1592 );
1593 }
1594 pt_addr = paddr_to_vaddr(cur_pte.paddr());
1595 }
1596
1597 unreachable!("All present PTEs at the level 1 must be last-level PTEs");
1598}
1599
1600pub trait PageTableEntryTrait:
1604 Clone + Copy + Debug + Default + Sized + Pod + PodOnce + Send + Sync + 'static {
1605 spec fn new_absent_spec() -> Self;
1606
1607 #[verifier(when_used_as_spec(new_absent_spec))]
1611 fn new_absent() -> (res: Self)
1612 ensures
1613 valid_frame_paddr(res.paddr()),
1614 !res.is_present(),
1615 returns
1616 Self::new_absent(),
1617 ;
1618
1619 spec fn is_present_spec(&self) -> bool;
1620
1621 #[verifier::when_used_as_spec(is_present_spec)]
1627 fn is_present(&self) -> bool
1628 returns
1629 self.is_present_spec(),
1630 ;
1631
1632 spec fn new_page_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self;
1633
1634 spec fn new_page_req(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> bool;
1636
1637 #[verifier::when_used_as_spec(new_page_spec)]
1639 fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res: Self)
1640 requires
1641 paddr < MAX_PADDR,
1642 Self::new_page_req(paddr, level, prop),
1643 ensures
1644 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1645 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1646 valid_frame_paddr(res.paddr()),
1647 res.is_present(),
1648 res.is_last(level),
1649 res.prop() == prop,
1650 returns
1651 Self::new_page(paddr, level, prop),
1652 ;
1653
1654 spec fn new_pt_spec(paddr: Paddr) -> Self;
1655
1656 #[verifier::when_used_as_spec(new_pt_spec)]
1658 fn new_pt(paddr: Paddr) -> (res: Self)
1659 requires
1660 paddr < MAX_PADDR,
1661 ensures
1662 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1663 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1664 valid_frame_paddr(res.paddr()),
1665 res.is_present(),
1666 forall|level: PagingLevel| !res.is_last(level),
1667 returns
1668 Self::new_pt(paddr),
1669 ;
1670
1671 spec fn paddr_spec(&self) -> Paddr;
1677
1678 #[verifier::when_used_as_spec(paddr_spec)]
1679 fn paddr(&self) -> (res: Paddr)
1680 ensures
1681 valid_frame_paddr(res),
1682 returns
1683 self.paddr(),
1684 ;
1685
1686 spec fn prop_spec(&self) -> PageProperty;
1687
1688 #[verifier::when_used_as_spec(prop_spec)]
1689 fn prop(&self) -> PageProperty
1690 returns
1691 self.prop(),
1692 ;
1693
1694 spec fn set_prop_req(self, prop: PageProperty) -> bool;
1696
1697 fn set_prop(&mut self, prop: PageProperty)
1698 requires
1699 old(self).set_prop_req(prop),
1700 ensures
1701 !old(self).is_present() ==> *old(self) == *final(self),
1702 old(self).is_present() ==> {
1703 &&& final(self).prop() == prop
1704 &&& final(self).paddr() == old(self).paddr()
1705 &&& final(self).is_present()
1706 &&& forall|level: PagingLevel|
1707 #![trigger old(self).is_last(level)]
1708 old(self).is_last(level) ==> final(self).is_last(level)
1709 },
1710 ;
1711
1712 spec fn is_last_spec(&self, level: PagingLevel) -> bool;
1713
1714 #[verifier::when_used_as_spec(is_last_spec)]
1719 fn is_last(&self, level: PagingLevel) -> bool
1720 returns
1721 self.is_last_spec(level),
1722 ;
1723
1724 spec fn as_usize_spec(self) -> usize;
1725
1726 #[verifier::external_body]
1728 #[verifier::when_used_as_spec(as_usize_spec)]
1729 fn as_usize(self) -> usize
1730 returns
1731 self.as_usize(),
1732 {
1733 unimplemented!()
1734 }
1739
1740 #[verifier::external_body]
1742 fn from_usize(pte_raw: usize) -> Self {
1743 unimplemented!()
1744 }
1749
1750 proof fn lemma_page_table_entry_properties()
1752 ensures
1753 core::mem::size_of::<Self>() == core::mem::size_of::<usize>(),
1754 core::mem::size_of::<Self>() % core::mem::align_of::<Self>() == 0,
1755 core::mem::align_of::<Self>() > 0,
1756 valid_frame_paddr(Self::new_absent().paddr()),
1757 !Self::new_absent().is_present(),
1758 forall|level: PagingLevel|
1759 #![trigger Self::new_absent().is_last(level)]
1760 1 < level ==> !Self::new_absent().is_last(level),
1761 forall|paddr: Paddr, level: PagingLevel, prop: PageProperty|
1762 #![trigger Self::new_page(paddr, level, prop)]
1763 Self::new_page_req(paddr, level, prop) && (prop.cache is Writeback
1764 || prop.cache is Writethrough || prop.cache is Uncacheable) ==> {
1765 &&& Self::new_page(paddr, level, prop).is_present()
1766 &&& (paddr < MAX_PADDR ==> Self::new_page(paddr, level, prop).paddr() == paddr
1767 & !((PAGE_SIZE - 1) as usize))
1768 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_page(
1769 paddr,
1770 level,
1771 prop,
1772 ).paddr() == paddr)
1773 &&& Self::new_page(paddr, level, prop).prop() == prop
1774 &&& Self::new_page(paddr, level, prop).is_last(level)
1775 },
1776 forall|paddr: Paddr|
1777 #![trigger Self::new_pt(paddr)]
1778 {
1779 &&& Self::new_pt(paddr).is_present()
1780 &&& (paddr < MAX_PADDR ==> Self::new_pt(paddr).paddr() == paddr & !((PAGE_SIZE
1781 - 1) as usize))
1782 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_pt(paddr).paddr()
1783 == paddr)
1784 &&& forall|level: PagingLevel| !Self::new_pt(paddr).is_last(level)
1785 },
1786 ;
1787
1788 proof fn lemma_paddr_is_page_aligned(self)
1789 ensures
1790 self.paddr() % PAGE_SIZE == 0,
1791 ;
1792}
1793
1794#[verifier::external_body]
1809#[verus_spec(
1810 with Tracked(perm): Tracked<&vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1811 requires
1812 perm.is_init(ptr.index as int),
1813 perm.addr() == ptr.addr(),
1814 0 <= ptr.index < NR_ENTRIES,
1815 returns
1816 perm.value()[ptr.index as int],
1817)]
1818pub unsafe fn load_pte<E: PageTableEntryTrait>(
1819 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1820 ordering: Ordering,
1821) -> (pte: E) {
1822 unimplemented!()
1823}
1824
1825#[verifier::external_body]
1838#[verus_spec(
1839 with Tracked(perm): Tracked<&mut vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1840 requires
1841 old(perm).addr() == ptr.addr(),
1842 0 <= ptr.index < NR_ENTRIES,
1843 old(perm).is_init_all(),
1844 ensures
1845 final(perm).wf(),
1846 final(perm).value()[ptr.index as int] == new_val,
1847 final(perm).value() == old(perm).value().update(ptr.index as int, new_val),
1848 final(perm).addr() == old(perm).addr(),
1849 final(perm).is_init_all(),
1850)]
1851pub unsafe fn store_pte<E: PageTableEntryTrait>(
1852 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1853 new_val: E,
1854 ordering: Ordering,
1855);
1856
1857}