1use vstd::arithmetic::power2::*;
3use vstd::atomic::PermissionU64;
4use vstd::prelude::*;
5use vstd::simple_pptr;
6use vstd::std_specs::clone::*;
7
8use vstd_extra::prelude::{lemma_usize_ilog2_ordered, lemma_usize_pow2_ilog2};
9
10use core::{
11 fmt::Debug,
12 intrinsics::transmute_unchecked,
13 ops::{Range, RangeInclusive},
14 sync::atomic::{AtomicUsize, Ordering},
15};
16
17use crate::mm::frame::meta::MetaSlot;
18
19use super::{
20 Paddr, PagingConstsTrait, PagingLevel, Vaddr, io::PodOnce, kspace::KernelPtConfig,
21 lemma_nr_subpage_per_huge_bounded, nr_subpage_per_huge, page_prop::PageProperty,
22 vm_space::UserPtConfig,
23};
24
25use crate::Pod;
26use crate::specs::mm::page_table::*;
27
28use crate::specs::arch::mm::*;
29use crate::specs::arch::paging_consts::PagingConsts;
30use crate::specs::mm::page_table::cursor::*;
31use crate::specs::task::InAtomicMode;
32
33use crate::mm::frame::meta::mapping::frame_to_index;
34use crate::mm::kspace::kvirt_area::disable_preempt;
35use crate::specs::arch::PageTableEntry;
36use crate::specs::mm::frame::meta_owners::MetaPerm;
37use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
38use vstd_extra::ownership::Inv;
39use vstd_extra::panic::may_panic;
40
41mod node;
42pub use node::*;
43mod cursor;
44
45pub(crate) use cursor::*;
46
47#[cfg(ktest)]
48mod test;
49
50verus! {
53
54#[derive(Clone, Copy, PartialEq, Eq, Debug)]
55pub enum PageTableError {
56 InvalidVaddrRange(Vaddr, Vaddr),
58 InvalidVaddr(Vaddr),
60 UnalignedVaddr,
62}
63
64pub trait RCClone: Sized {
65 spec fn clone_requires(self, perm: MetaRegionOwners) -> bool;
66
67 spec fn clone_ensures(
68 self,
69 old_perm: MetaRegionOwners,
70 new_perm: MetaRegionOwners,
71 res: Self,
72 ) -> bool;
73
74 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self)
75 requires
76 self.clone_requires(*old(perm)),
77 ensures
78 res == *self,
79 self.clone_ensures(*old(perm), *final(perm), res),
80 final(perm).inv(),
81 final(perm).slots =~= old(perm).slots,
82 final(perm).slot_owners.dom() =~= old(
83 perm,
84 ).slot_owners.dom(),
85 ;
93}
94
95pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
113 spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize>;
120
121 open spec fn LEADING_BITS_spec() -> usize {
140 0
141 }
142
143 fn TOP_LEVEL_INDEX_RANGE() -> (r: Range<usize>)
144 ensures
145 r == Self::TOP_LEVEL_INDEX_RANGE_spec(),
146 ;
147
148 open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
154 true
155 }
156
157 fn TOP_LEVEL_CAN_UNMAP() -> (b: bool)
158 ensures
159 b == Self::TOP_LEVEL_CAN_UNMAP_spec(),
160 ;
161
162 open spec fn LOCKED_END_BOUND_spec() -> int {
176 0x1_0000_0000_0000_0000int
177 }
178
179 type E: PageTableEntryTrait;
181
182 type C: PagingConstsTrait;
184
185 proof fn axiom_nr_subpage_per_huge_eq_nr_entries()
186 ensures
187 Self::C::BASE_PAGE_SIZE() / Self::C::PTE_SIZE() == NR_ENTRIES,
188 ;
189
190 proof fn axiom_pte_size_eq_size_of()
195 ensures
196 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE_spec(),
197 ;
198
199 proof fn axiom_pte_walk_fills_page()
204 ensures
205 NR_ENTRIES * core::mem::size_of::<Self::E>() == crate::specs::arch::mm::PAGE_SIZE,
206 ;
207
208 proof fn axiom_top_level_index_range_within_nr_entries()
213 ensures
214 Self::TOP_LEVEL_INDEX_RANGE_spec().end <= NR_ENTRIES,
215 ;
216
217 proof fn axiom_pte_align_divides_size()
223 ensures
224 core::mem::size_of::<Self::E>() % core::mem::align_of::<Self::E>() == 0,
225 core::mem::align_of::<Self::E>() > 0,
226 ;
227
228 type Item: RCClone;
241
242 spec fn item_into_raw_spec(item: Self::Item) -> (Paddr, PagingLevel, PageProperty);
248
249 #[verifier::when_used_as_spec(item_into_raw_spec)]
250 fn item_into_raw(item: Self::Item) -> (res: (Paddr, PagingLevel, PageProperty))
251 ensures
252 1 <= res.1 <= NR_LEVELS,
253 res == Self::item_into_raw_spec(item),
254 res.0 % crate::specs::arch::mm::PAGE_SIZE == 0,
255 res.0 < crate::specs::arch::mm::MAX_PADDR,
256 res.0 % crate::mm::page_table::cursor::page_size(res.1) == 0,
257 res.0 + crate::mm::page_table::cursor::page_size(res.1)
258 <= crate::specs::arch::mm::MAX_PADDR,
259 ;
260
261 spec fn item_from_raw_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self::Item;
286
287 #[verifier::when_used_as_spec(item_from_raw_spec)]
288 unsafe fn item_from_raw(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self::Item
289 returns
290 Self::item_from_raw_spec(paddr, level, prop),
291 ;
292
293 spec fn tracked(item: Self::Item) -> bool;
297
298 spec fn item_well_formed(item: Self::Item) -> bool;
305
306 proof fn item_from_raw_well_formed(pa: Paddr, level: PagingLevel, prop: PageProperty)
309 requires
310 crate::mm::frame::meta::has_safe_slot(pa),
311 ensures
312 Self::item_well_formed(Self::item_from_raw_spec(pa, level, prop)),
313 ;
314
315 proof fn clone_ensures_concrete(
322 item: Self::Item,
323 pa: Paddr,
324 old_regions: MetaRegionOwners,
325 new_regions: MetaRegionOwners,
326 res: Self::Item,
327 )
328 requires
329 item.clone_ensures(old_regions, new_regions, res),
330 Self::item_into_raw_spec(item).0 == pa,
331 res == item,
332 new_regions.inv(),
333 new_regions.slots =~= old_regions.slots,
334 new_regions.slot_owners.dom() =~= old_regions.slot_owners.dom(),
335 ensures
336 forall|i: usize|
339 i != frame_to_index(pa) ==> (#[trigger] new_regions.slot_owners[i]
340 == old_regions.slot_owners[i]),
341 Self::tracked(item) ==> {
343 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
344 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value() + 1
345 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.id()
346 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.id()
347 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.storage
348 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.storage
349 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.vtable_ptr
350 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.vtable_ptr
351 &&& new_regions.slot_owners[frame_to_index(pa)].inner_perms.in_list
352 == old_regions.slot_owners[frame_to_index(pa)].inner_perms.in_list
353 &&& new_regions.slot_owners[frame_to_index(pa)].paths_in_pt
354 == old_regions.slot_owners[frame_to_index(pa)].paths_in_pt
355 &&& new_regions.slot_owners[frame_to_index(pa)].self_addr
356 == old_regions.slot_owners[frame_to_index(pa)].self_addr
357 &&& new_regions.slot_owners[frame_to_index(pa)].usage
358 == old_regions.slot_owners[frame_to_index(pa)].usage
359 },
360 !Self::tracked(item) ==> new_regions.slot_owners[frame_to_index(pa)]
361 == old_regions.slot_owners[frame_to_index(pa)],
362 Self::tracked(item) ==> new_regions.frame_obligations
365 =~= old_regions.frame_obligations.insert(frame_to_index(pa)),
366 !Self::tracked(item) ==> new_regions.frame_obligations
367 =~= old_regions.frame_obligations,
368 ;
369
370 proof fn item_roundtrip(item: Self::Item, paddr: Paddr, level: PagingLevel, prop: PageProperty)
371 ensures
372 Self::item_into_raw_spec(item) == (paddr, level, prop) <==> Self::item_from_raw_spec(
373 paddr,
374 level,
375 prop,
376 ) == item,
377 ;
378
379 proof fn clone_requires_concrete(
385 item: Self::Item,
386 pa: Paddr,
387 level: PagingLevel,
388 prop: PageProperty,
389 regions: MetaRegionOwners,
390 )
391 requires
392 regions.inv(),
393 Self::item_from_raw_spec(pa, level, prop) == item,
394 crate::mm::frame::meta::has_safe_slot(pa),
395 regions.slots.contains_key(frame_to_index(pa)),
396 regions.slot_owners.contains_key(frame_to_index(pa)),
397 Self::tracked(item) ==> regions.slot_owners[frame_to_index(
398 pa,
399 )].inner_perms.ref_count.value() > 0,
400 Self::tracked(item) ==> regions.slot_owners[frame_to_index(
402 pa,
403 )].inner_perms.ref_count.value()
404 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED,
405 Self::tracked(item) ==> (regions.slot_owners[frame_to_index(
407 pa,
408 )].inner_perms.ref_count.value() < crate::specs::mm::frame::meta_owners::REF_COUNT_MAX
409 || may_panic()),
410 ensures
411 item.clone_requires(regions),
412 ;
413}
414
415impl<C: PageTableConfig> PagingConstsTrait for C {
418 open spec fn BASE_PAGE_SIZE_spec() -> usize {
419 C::C::BASE_PAGE_SIZE_spec()
420 }
421
422 fn BASE_PAGE_SIZE() -> usize {
423 C::C::BASE_PAGE_SIZE()
424 }
425
426 open spec fn NR_LEVELS_spec() -> PagingLevel {
427 C::C::NR_LEVELS_spec()
428 }
429
430 fn NR_LEVELS() -> PagingLevel {
431 C::C::NR_LEVELS()
432 }
433
434 open spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel {
435 C::C::HIGHEST_TRANSLATION_LEVEL_spec()
436 }
437
438 fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel {
439 C::C::HIGHEST_TRANSLATION_LEVEL()
440 }
441
442 open spec fn PTE_SIZE_spec() -> usize {
443 C::C::PTE_SIZE_spec()
444 }
445
446 fn PTE_SIZE() -> usize {
447 C::C::PTE_SIZE()
448 }
449
450 open spec fn ADDRESS_WIDTH_spec() -> usize {
451 C::C::ADDRESS_WIDTH_spec()
452 }
453
454 fn ADDRESS_WIDTH() -> usize {
455 C::C::ADDRESS_WIDTH()
456 }
457
458 open spec fn VA_SIGN_EXT_spec() -> bool {
459 C::C::VA_SIGN_EXT_spec()
460 }
461
462 fn VA_SIGN_EXT() -> bool {
463 C::C::VA_SIGN_EXT()
464 }
465
466 proof fn lemma_BASE_PAGE_SIZE_properties()
467 ensures
468 0 < Self::BASE_PAGE_SIZE_spec(),
469 is_pow2(Self::BASE_PAGE_SIZE_spec() as int),
470 {
471 C::C::lemma_BASE_PAGE_SIZE_properties();
472 }
473
474 proof fn lemma_NR_LEVELS_eq()
475 ensures
476 Self::NR_LEVELS_spec() as int == NR_LEVELS as int,
477 {
478 C::C::lemma_NR_LEVELS_eq();
479 }
480
481 proof fn lemma_PTE_SIZE_properties()
482 ensures
483 0 < Self::PTE_SIZE_spec() <= Self::BASE_PAGE_SIZE(),
484 is_pow2(Self::PTE_SIZE_spec() as int),
485 {
486 C::C::lemma_PTE_SIZE_properties();
487 }
488}
489
490pub trait PageTableEntryTrait:
494 Clone + Copy + Debug + Sized + Send + Sync + Pod + PodOnce + 'static {
495 spec fn default_spec() -> Self;
496
497 #[verifier::when_used_as_spec(default_spec)]
499 fn default() -> (res: Self)
500 ensures
501 res == Self::default_spec(),
502 ;
503
504 spec fn new_absent_spec() -> Self;
508
509 #[verifier(when_used_as_spec(new_absent_spec))]
510 fn new_absent() -> (res: Self)
511 ensures
512 res == Self::new_absent_spec(),
513 res.paddr() % PAGE_SIZE == 0,
514 res.paddr() < MAX_PADDR,
515 ;
516
517 spec fn is_present_spec(&self) -> bool;
519
520 #[verifier::when_used_as_spec(is_present_spec)]
521 fn is_present(&self) -> (res: bool)
522 ensures
523 res == self.is_present_spec(),
524 ;
525
526 spec fn new_page_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self;
528
529 #[verifier::when_used_as_spec(new_page_spec)]
530 fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res: Self)
531 requires
532 paddr % PAGE_SIZE == 0,
533 paddr < MAX_PADDR,
534 ensures
535 res == Self::new_page_spec(paddr, level, prop),
536 res.paddr() == paddr,
537 res.paddr() % PAGE_SIZE == 0,
538 res.paddr() < MAX_PADDR,
539 ;
540
541 spec fn new_pt_spec(paddr: Paddr) -> Self;
543
544 #[verifier::when_used_as_spec(new_pt_spec)]
545 fn new_pt(paddr: Paddr) -> (res: Self)
546 requires
547 paddr % PAGE_SIZE == 0,
548 paddr < MAX_PADDR,
549 ensures
550 res == Self::new_pt_spec(paddr),
551 res.paddr() == paddr,
552 res.paddr() % PAGE_SIZE == 0,
553 res.paddr() < MAX_PADDR,
554 ;
555
556 proof fn new_properties()
557 ensures
558 !Self::new_absent_spec().is_present(),
559 forall|level: PagingLevel|
560 #![trigger Self::new_absent_spec().is_last(level)]
561 1 < level ==> !Self::new_absent_spec().is_last(level),
562 forall|paddr: Paddr, level: PagingLevel, prop: PageProperty|
563 #![trigger Self::new_page_spec(paddr, level, prop)]
564 {
565 &&& Self::new_page_spec(paddr, level, prop).is_present()
566 &&& Self::new_page_spec(paddr, level, prop).paddr() == paddr
567 &&& Self::new_page_spec(paddr, level, prop).prop() == prop
568 &&& Self::new_page_spec(paddr, level, prop).is_last(level)
569 },
570 forall|paddr: Paddr|
571 #![trigger Self::new_pt_spec(paddr)]
572 {
573 &&& Self::new_pt_spec(paddr).is_present()
574 &&& Self::new_pt_spec(paddr).paddr() == paddr
575 &&& forall|level: PagingLevel| !Self::new_pt_spec(paddr).is_last(level)
576 },
577 ;
578
579 spec fn paddr_spec(&self) -> Paddr;
584
585 #[verifier::when_used_as_spec(paddr_spec)]
586 fn paddr(&self) -> (res: Paddr)
587 ensures
588 res == self.paddr_spec(),
589 ;
590
591 proof fn axiom_present_paddr_aligned(&self)
596 requires
597 self.is_present(),
598 ensures
599 self.paddr() % crate::specs::arch::mm::PAGE_SIZE == 0,
600 ;
601
602 spec fn prop_spec(&self) -> PageProperty;
603
604 #[verifier::when_used_as_spec(prop_spec)]
605 fn prop(&self) -> (res: PageProperty)
606 ensures
607 res == self.prop_spec(),
608 ;
609
610 spec fn set_prop_spec(&self, prop: PageProperty) -> Self;
615
616 fn set_prop(&mut self, prop: PageProperty)
617 ensures
618 old(self).set_prop_spec(prop) == *final(self),
619 ;
620
621 proof fn set_prop_properties(self, prop: PageProperty)
622 ensures
623 self.set_prop_spec(prop).prop() == prop,
624 self.set_prop_spec(prop).paddr() == self.paddr(),
625 self.is_present() ==> self.set_prop_spec(prop).is_present(),
626 forall|level: PagingLevel|
627 #![trigger self.is_last(level)]
628 self.is_last(level) ==> self.set_prop_spec(prop).is_last(level),
629 ;
630
631 spec fn is_last_spec(&self, level: PagingLevel) -> bool;
636
637 #[verifier::when_used_as_spec(is_last_spec)]
638 fn is_last(&self, level: PagingLevel) -> (b: bool)
639 ensures
640 b == self.is_last_spec(level),
641 ;
642
643 spec fn as_usize_spec(self) -> usize;
645
646 #[verifier::external_body]
647 #[verifier::when_used_as_spec(as_usize_spec)]
648 fn as_usize(self) -> (res: usize)
649 ensures
650 res == self.as_usize_spec(),
651 {
652 unimplemented!()
653 }
657
658 #[verifier::external_body]
660 fn from_usize(pte_raw: usize) -> Self {
661 unimplemented!()
662 }
666}
667
668pub struct PageTable<C: PageTableConfig> {
671 pub root: PageTableNode<C>,
672}
673
674#[verifier::inline]
675pub open spec fn nr_pte_index_bits_spec<C: PagingConstsTrait>() -> usize {
676 nr_subpage_per_huge::<C>().ilog2() as usize
677}
678
679#[inline(always)]
681#[verifier::when_used_as_spec(nr_pte_index_bits_spec)]
682pub fn nr_pte_index_bits<C: PagingConstsTrait>() -> (res: usize)
683 ensures
684 res == nr_pte_index_bits_spec::<C>(),
685{
686 proof {
687 lemma_nr_subpage_per_huge_bounded::<C>();
688 }
689 nr_subpage_per_huge::<C>().ilog2() as usize
690}
691
692pub proof fn lemma_nr_pte_index_bits_bounded<C: PagingConstsTrait>()
693 ensures
694 0 <= nr_pte_index_bits::<C>() <= C::BASE_PAGE_SIZE().ilog2(),
695{
696 lemma_nr_subpage_per_huge_bounded::<C>();
697 let nr = nr_subpage_per_huge::<C>();
698 assert(1 <= nr <= C::BASE_PAGE_SIZE());
699 let bits = nr.ilog2();
700 assert(0 <= bits) by {
701 lemma_usize_ilog2_ordered(1, nr);
702 }
703 assert(bits <= C::BASE_PAGE_SIZE().ilog2()) by {
704 lemma_usize_ilog2_ordered(nr, C::BASE_PAGE_SIZE());
705 }
706}
707
708#[verifier::external_body]
733pub fn largest_pages<C: PageTableConfig>(
734 mut va: Vaddr,
735 mut pa: Paddr,
736 mut len: usize,
737) -> impl Iterator<Item = (Paddr, PagingLevel)> {
738 assert_eq!(va % C::BASE_PAGE_SIZE(), 0);
739 assert_eq!(pa % C::BASE_PAGE_SIZE(), 0);
740 assert_eq!(len % C::BASE_PAGE_SIZE(), 0);
741 assert!(is_valid_range::<C>(&(va..(va + len))));
742
743 core::iter::from_fn(
744 move ||
745 {
746 if len == 0 {
747 return None;
748 }
749 let mut level = C::HIGHEST_TRANSLATION_LEVEL();
750 while page_size(level) > len || va % page_size(level) != 0 || pa % page_size(level)
751 != 0 {
752 level -= 1;
753 }
754
755 let item_start = pa;
756 va += page_size(level);
757 pa += page_size(level);
758 len -= page_size(level);
759
760 Some((item_start, level))
761 },
762 )
763}
764
765#[verifier::external_body]
770fn top_level_index_width<C: PageTableConfig>() -> usize {
771 C::ADDRESS_WIDTH() - pte_index_bit_offset::<C>(C::NR_LEVELS())
772}
773
774#[verifier::external_body]
776fn pt_va_range_start<C: PageTableConfig>() -> (ret: Vaddr)
777 ensures
778 ret as int == C::TOP_LEVEL_INDEX_RANGE_spec().start as int * pow2(
779 pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
780 ) as int,
781{
782 C::TOP_LEVEL_INDEX_RANGE().start << pte_index_bit_offset::<C>(C::NR_LEVELS())
783}
784
785#[verifier::external_body]
790fn pt_va_range_end<C: PageTableConfig>() -> (ret: Vaddr)
791 ensures
792 ret as int == (C::TOP_LEVEL_INDEX_RANGE_spec().end as int * pow2(
793 pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
794 ) as int - 1) % 0x1_0000_0000_0000_0000int,
795{
796 C::TOP_LEVEL_INDEX_RANGE().end.unbounded_shl(
797 pte_index_bit_offset::<C>(C::NR_LEVELS()) as u32,
798 ).wrapping_sub(1) }
801
802#[verifier::external_body]
804fn sign_bit_of_va<C: PageTableConfig>(va: Vaddr) -> (ret: bool)
805 ensures
806 ret == ((va as int / pow2((C::ADDRESS_WIDTH() - 1) as nat) as int) % 2 == 1),
807{
808 (va >> (C::ADDRESS_WIDTH() - 1)) & 1 != 0
809}
810
811pub axiom fn axiom_top_level_index_range_bounds<C: PageTableConfig>()
819 ensures
820 (C::TOP_LEVEL_INDEX_RANGE_spec().start as int) < (pow2(
821 (C::ADDRESS_WIDTH() as int - pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS())) as nat,
822 ) as int),
823 C::TOP_LEVEL_INDEX_RANGE_spec().end as int <= pow2(
824 (C::ADDRESS_WIDTH() as int - pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS())) as nat,
825 ) as int,
826 pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) <= C::ADDRESS_WIDTH() as int,
827 pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) >= 0,
828 (C::TOP_LEVEL_INDEX_RANGE_spec().start as int) < (
831 C::TOP_LEVEL_INDEX_RANGE_spec().end as int),
832 C::ADDRESS_WIDTH() as int <= 64,
834;
835
836pub axiom fn axiom_leading_bits_only_when_high_half<C: PageTableConfig>()
847 ensures
848 C::LEADING_BITS_spec() != 0usize ==> (C::VA_SIGN_EXT() && (((
849 C::TOP_LEVEL_INDEX_RANGE_spec().start as int) * (pow2(
850 pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
851 ) as int)) / (pow2((C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1),
852;
853
854#[verifier::inline]
855pub open spec fn pte_index_bit_offset_spec<C: PagingConstsTrait>(level: PagingLevel) -> int {
856 (C::BASE_PAGE_SIZE().ilog2() as int) + (nr_pte_index_bits::<C>() as int) * (level as int - 1)
857}
858
859#[verifier::inline]
864pub open spec fn vaddr_range_spec<C: PageTableConfig>() -> Range<Vaddr> {
865 let idx_range = C::TOP_LEVEL_INDEX_RANGE_spec();
866 let offset = pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat;
867 let start = (idx_range.start as int) * pow2(offset);
868 let end_inclusive = (idx_range.end as int) * pow2(offset) - 1;
869 (start as Vaddr)..((end_inclusive + 1) as Vaddr)
870}
871
872#[verifier::inline]
874pub open spec fn is_valid_range_spec<C: PageTableConfig>(r: &Range<Vaddr>) -> bool {
875 let va_range = vaddr_range_spec::<C>();
876 (r.start == 0 && r.end == 0) || (va_range.start <= r.start && r.end > 0 && r.end - 1
877 <= va_range.end - 1)
878}
879
880fn vaddr_range<C: PageTableConfig>() -> (ret: RangeInclusive<Vaddr>)
887 ensures
888 ret@.start == vaddr_range_bounds_spec::<C>().0,
889 ret@.end == vaddr_range_bounds_spec::<C>().1,
890 ret@.exhausted == false,
891{
892 let mut start = pt_va_range_start::<C>();
893 let mut end = pt_va_range_end::<C>();
894
895 proof {
896 lemma_vaddr_range_bounds_spec_unfold::<C>();
897 axiom_top_level_index_range_bounds::<C>();
898 crate::specs::mm::page_table::vaddr_range_proofs::lemma_idx_times_pow2_bound::<C>(
899 start,
900 end,
901 );
902 }
903 let pt_start = pt_va_range_start::<C>();
904 let va_sign_ext = C::VA_SIGN_EXT();
905 let sign_bit_set = sign_bit_of_va::<C>(pt_start);
906 if va_sign_ext && sign_bit_set {
907 start = apply_sign_ext::<C>(start);
908 end = apply_sign_ext::<C>(end);
909 } else {
910 proof {
911 axiom_leading_bits_only_when_high_half::<C>();
915 assert(!va_sign_ext || !sign_bit_set);
916 assert(va_sign_ext == C::VA_SIGN_EXT());
920 let off = pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat;
921 let aw_m1 = (C::ADDRESS_WIDTH() - 1) as nat;
922 let i_start = C::TOP_LEVEL_INDEX_RANGE_spec().start as int;
923 let p_off = pow2(off) as int;
924 let p_aw_m1 = pow2(aw_m1) as int;
925 assert(pt_start as int == i_start * p_off);
926 assert(sign_bit_set == ((pt_start as int / p_aw_m1) % 2 == 1));
927 assert(sign_bit_set == ((i_start * p_off / p_aw_m1) % 2 == 1));
928 if C::LEADING_BITS_spec() != 0usize {
930 assert(C::VA_SIGN_EXT() && ((i_start * p_off / p_aw_m1) % 2 == 1));
931 assert(va_sign_ext);
932 assert(sign_bit_set);
933 assert(false);
934 }
935 assert(C::LEADING_BITS_spec() == 0usize);
936 }
937 }
938 proof {
939 assert(start as int == (C::LEADING_BITS_spec() as int) * 0x1_0000_0000_0000int + (
944 C::TOP_LEVEL_INDEX_RANGE_spec().start as int) * (pow2(
945 pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
946 ) as int));
947 assert(end as int == (C::LEADING_BITS_spec() as int) * 0x1_0000_0000_0000int + (
948 C::TOP_LEVEL_INDEX_RANGE_spec().end as int) * (pow2(
949 pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
950 ) as int) - 1);
951 }
952 RangeInclusive::new(start, end)
953}
954
955#[verifier::external_body]
965fn apply_sign_ext<C: PageTableConfig>(va: Vaddr) -> (ret: Vaddr)
966 requires
967 (va as int) < pow2(C::ADDRESS_WIDTH() as nat) as int,
968 ensures
969 ret as int == va as int + C::LEADING_BITS_spec() as int * 0x1_0000_0000_0000int,
970{
971 let sign_ext_mask = !0 ^ ((1usize << C::ADDRESS_WIDTH()) - 1);
972 va | sign_ext_mask
973}
974
975#[verifier::external_body]
977fn is_valid_range<C: PageTableConfig>(r: &Range<Vaddr>) -> (ret: bool)
978 ensures
979 ret == is_valid_range_spec::<C>(r),
980{
981 let va_range = vaddr_range::<C>();
982 (r.start == 0 && r.end == 0) || (*va_range.start() <= r.start && r.end - 1 <= *va_range.end())
983}
984
985pub(crate) proof fn lemma_vaddr_range_spec_kernel()
991 ensures
992 vaddr_range_spec::<KernelPtConfig>() == (
993 0x0000_8000_0000_0000_usize..0x0001_0000_0000_0000_usize),
994{
995 use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds};
996 lemma2_to64();
997 lemma2_to64_rest();
998 lemma_usize_pow2_ilog2(12);
999 assert(PagingConsts::BASE_PAGE_SIZE().ilog2() == 12u32);
1000 assert(nr_subpage_per_huge::<PagingConsts>() == 512_usize);
1001 lemma_usize_pow2_ilog2(9);
1002 assert(nr_pte_index_bits::<PagingConsts>() == 9_usize);
1003 assert(pte_index_bit_offset_spec::<PagingConsts>(4) == 39);
1004 lemma_pow2_adds(8, 39);
1005 lemma_pow2_adds(9, 39);
1006 assert((256 as int) * pow2(39) == pow2(47));
1007 assert((512 as int) * pow2(39) == pow2(48));
1008}
1009
1010pub closed spec fn vaddr_range_bounds_spec<C: PageTableConfig>() -> (Vaddr, Vaddr) {
1020 let idx = C::TOP_LEVEL_INDEX_RANGE_spec();
1021 let off = pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat;
1022 let lb = C::LEADING_BITS_spec() as int;
1023 let base = lb * 0x1_0000_0000_0000int;
1024 let start = (base + (idx.start as int) * pow2(off)) as usize;
1025 let end_inclusive = (base + (idx.end as int) * pow2(off) - 1) as usize;
1026 (start, end_inclusive)
1027}
1028
1029pub proof fn lemma_vaddr_range_bounds_spec_unfold<C: PageTableConfig>()
1033 ensures
1034 vaddr_range_bounds_spec::<C>() == {
1035 let idx = C::TOP_LEVEL_INDEX_RANGE_spec();
1036 let off = pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat;
1037 let lb = C::LEADING_BITS_spec() as int;
1038 let base = lb * 0x1_0000_0000_0000int;
1039 let start = (base + (idx.start as int) * pow2(off)) as usize;
1040 let end_inclusive = (base + (idx.end as int) * pow2(off) - 1) as usize;
1041 (start, end_inclusive)
1042 },
1043{
1044}
1045
1046pub(crate) proof fn lemma_vaddr_range_bounds_spec_user()
1049 ensures
1050 vaddr_range_bounds_spec::<crate::mm::vm_space::UserPtConfig>() == (
1051 0_usize,
1052 0x0000_7FFF_FFFF_FFFF_usize,
1053 ),
1054{
1055 use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds};
1056 lemma2_to64();
1057 lemma2_to64_rest();
1058 lemma_usize_pow2_ilog2(12);
1059 lemma_usize_pow2_ilog2(9);
1060 lemma_pow2_adds(8, 39);
1061 assert(nr_subpage_per_huge::<PagingConsts>() == 512_usize);
1062 assert(nr_pte_index_bits::<PagingConsts>() == 9_usize);
1063 assert(pte_index_bit_offset_spec::<PagingConsts>(4) == 39);
1064 assert((0 as int) * pow2(39) == 0);
1065 assert((256 as int) * pow2(39) == pow2(47));
1066 assert(pow2(47) as int - 1 == 0x0000_7FFF_FFFF_FFFF_int);
1067 assert(<crate::mm::vm_space::UserPtConfig as PageTableConfig>::LEADING_BITS_spec() == 0_usize);
1069}
1070
1071pub(crate) proof fn lemma_vaddr_range_bounds_spec_kernel()
1074 ensures
1075 vaddr_range_bounds_spec::<KernelPtConfig>() == (
1076 0xFFFF_8000_0000_0000_usize,
1077 0xFFFF_FFFF_FFFF_FFFF_usize,
1078 ),
1079{
1080 use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds};
1081 lemma2_to64();
1082 lemma2_to64_rest();
1083 lemma_usize_pow2_ilog2(12);
1084 lemma_usize_pow2_ilog2(9);
1085 lemma_pow2_adds(8, 39);
1086 lemma_pow2_adds(9, 39);
1087 assert(nr_subpage_per_huge::<PagingConsts>() == 512_usize);
1088 assert(nr_pte_index_bits::<PagingConsts>() == 9_usize);
1089 assert(PagingConsts::BASE_PAGE_SIZE().ilog2() == 12u32);
1090 assert(pte_index_bit_offset_spec::<PagingConsts>(4) == 39);
1091 assert((256 as int) * pow2(39) == pow2(47));
1092 assert((512 as int) * pow2(39) == pow2(48));
1093 assert(0xffff_int * 0x1_0000_0000_0000int + pow2(47) as int == 0xffff_8000_0000_0000int);
1094 assert(0xffff_int * 0x1_0000_0000_0000int + pow2(48) as int - 1 == 0xffff_ffff_ffff_ffffint);
1095}
1096
1097#[verifier::external_body]
1100fn pte_index<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel) -> (res: usize)
1101 ensures
1102 res == AbstractVaddr::from_vaddr(va).index[level - 1],
1103{
1104 (va >> pte_index_bit_offset::<C>(level)) & (nr_subpage_per_huge::<C>() - 1)
1105}
1106
1107#[verifier::external_body]
1113fn pte_index_bit_offset<C: PagingConstsTrait>(level: PagingLevel) -> usize {
1114 C::BASE_PAGE_SIZE().ilog2() as usize + nr_pte_index_bits::<C>() * (level as usize - 1)
1115}
1116
1117impl PageTable<KernelPtConfig> {
1129 pub open spec fn create_user_pt_panic_condition(root_owner: NodeOwner<KernelPtConfig>) -> bool {
1133 exists|i: usize|
1134 #![trigger root_owner.children_perm.value()[i as int]]
1135 KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().start <= i
1136 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end && {
1137 let pte = root_owner.children_perm.value()[i as int];
1138 ||| !pte.is_present()
1139 ||| pte.is_last(root_owner.level)
1140 }
1141 }
1142
1143 #[verifier::external_body]
1145 pub(crate) fn new_kernel_page_table() -> Self {
1146 unimplemented!()}
1162
1163 #[verus_spec(r =>
1168 with Tracked(kernel_owner): Tracked<&PageTableOwner<KernelPtConfig>>,
1169 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1170 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1171 requires
1172 kernel_owner.inv(),
1173 old(regions).inv(),
1174 kernel_owner.0.value.node is Some,
1175 !Self::create_user_pt_panic_condition(kernel_owner.0.value.node.unwrap()),
1176 self.root.ptr.addr() == kernel_owner.0.value.node.unwrap().meta_addr_self(),
1178 kernel_owner.0.value.metaregion_sound(*old(regions)),
1180 kernel_owner.metaregion_sound(*old(regions)),
1184 old(guards).unlocked(kernel_owner.0.value.node.unwrap().meta_addr_self()),
1186 ensures
1187 final(regions).inv(),
1188 )]
1189 pub(in crate::mm) fn create_user_page_table<'rcu, G: InAtomicMode + 'static>(
1190 &'static self,
1191 ) -> PageTable<UserPtConfig> {
1192 let preempt_guard: &'rcu G = disable_preempt::<G>();
1193
1194 proof_decl! {
1195 let tracked mut new_pt_owner: Option<PageTableOwner<UserPtConfig>> = None;
1196 }
1197 let ghost regions_before_alloc = *regions;
1198 let new_pt: PageTable<UserPtConfig> = (
1199 #[verus_spec(with Tracked(&mut new_pt_owner), Tracked(regions), Tracked(guards))]
1200 PageTable::empty_with_owner());
1201 let new_root = new_pt.root;
1202 let ghost new_idx_g: usize = crate::specs::mm::frame::mapping::frame_to_index(
1204 new_pt_owner@.unwrap().0.value.meta_slot_paddr().unwrap(),
1205 );
1206 let ghost new_pt_owner_snap = new_pt_owner@.unwrap();
1207 proof {
1208 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
1209 kernel_owner.0.value.meta_slot_paddr().unwrap(),
1210 );
1211 let new_idx = new_idx_g;
1212 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1213 KernelPtConfig,
1214 >::active_entry_not_in_free_pool(kernel_owner.0.value, regions_before_alloc, new_idx);
1215 assert(kern_idx != new_idx);
1216 assert(regions.slot_owners[kern_idx] == regions_before_alloc.slot_owners[kern_idx]);
1217 assert(kernel_owner.metaregion_sound(*regions));
1218 assert(!regions.slots.contains_key(new_idx));
1219 }
1220
1221 proof_decl! {
1222 let tracked root_owner: &NodeOwner<KernelPtConfig>
1223 = kernel_owner.0.borrow_value().node.tracked_borrow();
1224 let tracked mut new_pt_owner_val: PageTableOwner<UserPtConfig>
1225 = new_pt_owner.tracked_take();
1226 let tracked mut new_node_owner: NodeOwner<UserPtConfig>
1227 = new_pt_owner_val.0.value.node.tracked_take();
1228 let tracked mut entry_owner: &EntryOwner<KernelPtConfig>;
1229 }
1230
1231 proof {
1234 assert(kernel_owner.0.value.is_node());
1235 assert(kernel_owner.0.value.metaregion_sound(*regions));
1236 }
1237 let ghost regions_before_self_borrow: MetaRegionOwners = *regions;
1238 let mut root_node = {
1239 #[verus_spec(with Tracked(regions))]
1240 let root_ref = self.root.borrow();
1241 #[verus_spec(with Tracked(root_owner), Tracked(guards))]
1242 root_ref.lock(preempt_guard)
1243 };
1244 let ghost regions_after_kroot_borrow: MetaRegionOwners = *regions;
1245 let mut new_node: PageTableGuard<'rcu, UserPtConfig> = {
1246 #[verus_spec(with Tracked(regions))]
1247 let new_ref = new_root.borrow();
1248 #[verus_spec(with Tracked(&new_node_owner), Tracked(guards))]
1249 new_ref.lock(preempt_guard)
1250 };
1251 proof {
1252 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
1253 kernel_owner.0.value.meta_slot_paddr().unwrap(),
1254 );
1255 assert(regions_before_self_borrow.slot_owners
1256 =~= regions_after_kroot_borrow.slot_owners);
1257 assert forall|k: usize|
1258 regions_before_self_borrow.slots.contains_key(
1259 k,
1260 ) implies regions_before_self_borrow.slots[k]
1261 == #[trigger] regions_after_kroot_borrow.slots[k] by {
1262 if k == kern_idx {
1263 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1264 KernelPtConfig,
1265 >::active_entry_not_in_free_pool(
1266 kernel_owner.0.value,
1267 regions_before_self_borrow,
1268 k,
1269 );
1270 }
1271 };
1272 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1273 regions_before_self_borrow,
1274 regions_after_kroot_borrow,
1275 );
1276
1277 let new_idx = new_idx_g;
1278 assert(regions_before_alloc.slots.contains_key(new_idx));
1279 assert(kern_idx != new_idx) by {
1280 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1281 KernelPtConfig,
1282 >::active_entry_not_in_free_pool(
1283 kernel_owner.0.value,
1284 regions_before_alloc,
1285 new_idx,
1286 );
1287 };
1288
1289 assert(!regions_before_self_borrow.slots.contains_key(new_idx));
1290 assert(!regions_after_kroot_borrow.slots.contains_key(new_idx));
1291 assert forall|k: usize|
1292 regions_after_kroot_borrow.slots.contains_key(
1293 k,
1294 ) implies regions_after_kroot_borrow.slots[k] == #[trigger] regions.slots[k] by {
1295 if k != new_idx {
1296 }
1298 };
1299 assert(kernel_owner.metaregion_sound(regions_before_alloc));
1300
1301 kernel_owner.0.map_implies(
1302 kernel_owner.0.value.path,
1303 |
1304 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1305 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1306 |
1307 e.is_frame() && e.parent_level > 1 ==> {
1308 let pa = e.frame.unwrap().mapped_pa;
1309 let nr_pages = crate::mm::page_table::cursor::page_size_spec(e.parent_level)
1310 / crate::specs::arch::mm::PAGE_SIZE;
1311 forall|j: usize|
1312 0 < j < nr_pages ==> {
1313 let sub_idx =
1314 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1315 (pa + j * crate::specs::arch::mm::PAGE_SIZE) as usize,
1316 );
1317 sub_idx != new_idx
1318 }
1319 },
1320 |
1321 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1322 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1323 |
1324 e.is_frame() && e.parent_level > 1 ==> {
1325 let pa = e.frame.unwrap().mapped_pa;
1326 let nr_pages = crate::mm::page_table::cursor::page_size_spec(e.parent_level)
1327 / crate::specs::arch::mm::PAGE_SIZE;
1328 forall|j: usize|
1329 0 < j < nr_pages ==> {
1330 let sub_idx =
1331 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1332 (pa + j * crate::specs::arch::mm::PAGE_SIZE) as usize,
1333 );
1334 sub_idx != new_idx || (regions.slots.contains_key(sub_idx)
1335 && regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1336 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1337 && regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1338 > 0)
1339 }
1340 },
1341 );
1342 kernel_owner.metaregion_sound_preserved_one_slot_changed(
1343 regions_after_kroot_borrow,
1344 *regions,
1345 new_idx,
1346 );
1347 }
1348 let mut i: usize = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start;
1349 while i < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end
1350 invariant
1351 kernel_owner.inv(),
1352 kernel_owner.0.value.node is Some,
1353 regions.inv(),
1354 !Self::create_user_pt_panic_condition(kernel_owner.0.value.node.unwrap()),
1355 i <= KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end,
1356 KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().start <= i,
1357 *root_owner == kernel_owner.0.value.node.unwrap(),
1359 root_owner.relate_guard(root_node),
1360 kernel_owner.metaregion_sound(*regions),
1362 new_node_owner.inv(),
1364 new_node_owner.relate_guard(new_node),
1365 regions.slots.contains_key(new_node_owner.slot_index),
1366 decreases KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end - i,
1367 {
1368 proof {
1369 let kern_node = kernel_owner.0.value.node.unwrap();
1370 assert forall|j: usize|
1371 #![trigger kern_node.children_perm.value()[j as int]]
1372 KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().start <= j
1373 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end implies {
1374 let pte = kern_node.children_perm.value()[j as int];
1375 pte.is_present() && !pte.is_last(kern_node.level)
1376 } by {
1377 let pte = kern_node.children_perm.value()[j as int];
1378 if !pte.is_present() || pte.is_last(kern_node.level) {
1379 assert(Self::create_user_pt_panic_condition(kern_node));
1380 }
1381 }
1382
1383 kernel_owner.pt_inv_unroll(i as int);
1384 let tracked child_opt: &Option<OwnerSubtree<KernelPtConfig>> =
1385 kernel_owner.0.children.tracked_borrow(i as int);
1386 let tracked child_subtree: &OwnerSubtree<KernelPtConfig> =
1387 child_opt.tracked_borrow();
1388 entry_owner = child_subtree.borrow_value();
1389 let kern_node = kernel_owner.0.value.node.unwrap();
1390 assert(entry_owner.match_pte(
1391 kern_node.children_perm.value()[i as int],
1392 entry_owner.parent_level,
1393 ));
1394 assert(entry_owner.parent_level == kern_node.level);
1395 assert(child_subtree.inv());
1396 assert(entry_owner.inv());
1397 assert(!entry_owner.in_scope);
1398 assert(root_owner.relate_guard(root_node));
1399
1400 kernel_owner.0.map_unroll_once(
1401 kernel_owner.0.value.path,
1402 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1403 i as int,
1404 );
1405 assert(child_subtree.tree_predicate_map(
1406 kernel_owner.0.value.path.push_tail(i as usize),
1407 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1408 ));
1409 assert(entry_owner.metaregion_sound(*regions));
1410 }
1411
1412 #[verus_spec(with Tracked(root_owner), Tracked(entry_owner), Tracked(&*regions))]
1413 let root_entry = root_node.entry(i);
1414 let ghost pre_to_ref_regions: MetaRegionOwners = *regions;
1415 #[verus_spec(with Tracked(entry_owner), Tracked(root_owner), Tracked(regions))]
1416 let child = root_entry.to_ref();
1417
1418 proof {
1419 let kern_node = kernel_owner.0.value.node.unwrap();
1420 let pte = kern_node.children_perm.value()[i as int];
1421
1422 assert(pte.is_present() && !pte.is_last(kern_node.level)) by {
1423 if !pte.is_present() || pte.is_last(kern_node.level) {
1424 assert(KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().start <= i
1425 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end);
1426 assert(exists|j: usize|
1427 KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().start <= j
1428 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE_spec().end && {
1429 let p = #[trigger] kern_node.children_perm.value()[j as int];
1430 ||| !p.is_present()
1431 ||| p.is_last(kern_node.level)
1432 });
1433 assert(Self::create_user_pt_panic_condition(kern_node));
1434 }
1435 }
1436 assert(entry_owner.is_node());
1439 assert(child is PageTable);
1443 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1447 pre_to_ref_regions,
1448 *regions,
1449 );
1450 }
1451 let pt = match child {
1452 ChildRef::PageTable(pt) => pt,
1453 _ => vstd::pervasive::unreached(),
1454 };
1455
1456 let ghost entry_node_slot_idx = entry_owner.node.tracked_borrow().slot_index;
1457 let tracked entry_node_slot_perm = regions.slots.tracked_borrow(entry_node_slot_idx);
1458 #[verus_spec(with Tracked(entry_node_slot_perm))]
1459 let pt_addr = pt.start_paddr();
1460 let pte = PageTableEntry::new_pt(pt_addr);
1461
1462 proof {
1463 assert(regions.slots.contains_key(new_node_owner.slot_index));
1464 }
1465 unsafe {
1466 #[verus_spec(with Tracked(&mut new_node_owner), Tracked(&*regions))]
1467 new_node.write_pte(i, pte)
1468 };
1469
1470 i = i + 1;
1471 }
1472
1473 PageTable::<UserPtConfig> { root: new_root }
1474 }}
1500
1501#[verus_verify]
1502impl<C: PageTableConfig> PageTable<C> {
1503 pub uninterp spec fn root_paddr_spec(&self) -> Paddr;
1504
1505 #[verifier::external_body]
1509 pub fn empty() -> Self {
1510 unimplemented!()
1511 }
1512
1513 #[verifier::external_body]
1515 #[verus_spec(r =>
1516 with Tracked(owner): Tracked<&mut Option<PageTableOwner<C>>>,
1517 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1518 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1519 requires
1520 old(regions).inv(),
1521 ensures
1522 final(owner)@ is Some,
1523 final(owner)@.unwrap().inv(),
1524 final(owner)@.unwrap().0.value.is_node(),
1525 final(owner)@.unwrap().0.value.node is Some,
1526 r.root.ptr.addr() == final(owner)@.unwrap().0.value.node.unwrap().meta_addr_self(),
1527 final(owner)@.unwrap().0.value.metaregion_sound(*final(regions)),
1528 final(regions).inv(),
1529 final(guards).unlocked(final(owner)@.unwrap().0.value.node.unwrap().meta_addr_self()),
1530 final(guards).guards == old(guards).guards,
1533 old(regions).slots.contains_key(
1535 crate::specs::mm::frame::mapping::frame_to_index(
1536 final(owner)@.unwrap().0.value.meta_slot_paddr().unwrap())),
1537 !final(regions).slots.contains_key(
1540 crate::specs::mm::frame::mapping::frame_to_index(
1541 final(owner)@.unwrap().0.value.meta_slot_paddr().unwrap())),
1542 forall |i: usize| #![trigger final(regions).slot_owners[i]]
1544 i != crate::specs::mm::frame::mapping::frame_to_index(
1545 final(owner)@.unwrap().0.value.meta_slot_paddr().unwrap())
1546 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
1547 forall |a: usize| old(guards).lock_held(a) ==> final(guards).lock_held(a),
1548 forall |idx: usize| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1549 final(regions).slot_owners[idx].paths_in_pt
1550 == old(regions).slot_owners[idx].paths_in_pt,
1551 forall |kt: PageTableOwner<KernelPtConfig>|
1557 #![trigger kt.metaregion_sound(*final(regions))]
1558 kt.inv() && kt.metaregion_sound(*old(regions))
1559 ==> kt.metaregion_sound(*final(regions)),
1560 forall |kt: PageTableOwner<KernelPtConfig>|
1565 #![trigger kt.metaregion_sound(*old(regions))]
1566 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1567 kt.0.tree_predicate_map(
1568 kt.0.value.path,
1569 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1570 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1571 e.meta_slot_paddr() is Some
1572 ==> crate::specs::mm::frame::mapping::frame_to_index(
1573 e.meta_slot_paddr().unwrap()) !=
1574 crate::specs::mm::frame::mapping::frame_to_index(
1575 final(owner)@.unwrap().0.value.meta_slot_paddr().unwrap()),
1576 ),
1577 forall |kt: PageTableOwner<KernelPtConfig>|
1581 #![trigger kt.metaregion_sound(*old(regions))]
1582 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1583 kt.0.tree_predicate_map(
1584 kt.0.value.path,
1585 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1586 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1587 e.is_frame() && e.parent_level > 1 ==> {
1588 let pa = e.frame.unwrap().mapped_pa;
1589 let nr_pages = crate::mm::page_table::cursor::page_size_spec(
1590 e.parent_level) / crate::specs::arch::mm::PAGE_SIZE;
1591 forall |j: usize| 0 < j < nr_pages ==> {
1592 let sub_idx =
1593 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1594 (pa + j * crate::specs::arch::mm::PAGE_SIZE) as usize);
1595 sub_idx != crate::specs::mm::frame::mapping::frame_to_index(
1596 final(owner)@.unwrap().0.value.meta_slot_paddr().unwrap())
1597 }
1598 },
1599 ),
1600 )]
1601 pub fn empty_with_owner<'rcu>() -> Self {
1602 unimplemented!()
1603 }
1604
1605 #[verifier::external_body]
1606 pub(in crate::mm) unsafe fn first_activate_unchecked(&self) {
1607 unimplemented!()
1608 }
1612
1613 #[verifier::external_body]
1619 #[verifier::when_used_as_spec(root_paddr_spec)]
1620 pub fn root_paddr(&self) -> (r: Paddr)
1621 returns
1622 self.root_paddr_spec(),
1623 {
1624 unimplemented!()
1625 }
1628
1629 #[cfg(ktest)]
1635 pub fn page_walk(&self, vaddr: Vaddr) -> Option<(Paddr, PageProperty)> {
1636 unsafe { page_walk::<C>(self.root_paddr(), vaddr) }
1638 }
1639
1640 #[verus_spec(r =>
1645 with Tracked(owner): Tracked<PageTableOwner<C>>,
1646 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1647 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1648 Tracked(guards): Tracked<&mut Guards<'rcu>>
1649 requires
1650 va.end as int <= C::LOCKED_END_BOUND_spec(),
1652 ensures
1653 Cursor::<C, G>::cursor_new_success_conditions(va) ==> {
1654 &&& r is Ok
1655 &&& r.unwrap().0.0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1656 &&& r.unwrap().1.in_locked_range()
1657 &&& r.unwrap().0.0.level < r.unwrap().0.0.guard_level
1658 &&& r.unwrap().0.0.guard_level == NR_LEVELS as PagingLevel
1659 &&& r.unwrap().0.0.va < r.unwrap().0.0.barrier_va.end
1660 &&& r.unwrap().0.0.va == va.start
1661 &&& r.unwrap().0.0.barrier_va == *va
1662 },
1663 !Cursor::<C, G>::cursor_new_success_conditions(va) ==> r is Err,
1664 forall |item: C::Item| #![trigger CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions))]
1665 CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions)) ==>
1666 CursorMut::<'rcu, C, G>::item_not_mapped(item, *final(regions)),
1667 forall |idx: usize| #![auto]
1669 (*final(regions)).slot_owners[idx].paths_in_pt == (*old(regions)).slot_owners[idx].paths_in_pt,
1670 )]
1671 #[verifier::external_body]
1672 pub fn cursor_mut<'rcu, G: InAtomicMode>(
1673 &'rcu self,
1674 guard: &'rcu G,
1675 va: &Range<Vaddr>,
1676 ) -> Result<(CursorMut<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>), PageTableError> {
1677 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1678 CursorMut::new(self, guard, va)
1679 }
1680
1681 #[verus_spec(r =>
1687 with Tracked(owner): Tracked<PageTableOwner<C>>,
1688 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1689 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1690 Tracked(guards): Tracked<&mut Guards<'rcu>>
1691 requires
1692 owner.inv(),
1693 va.end as int <= C::LOCKED_END_BOUND_spec(),
1695 ensures
1696 Cursor::<C, G>::cursor_new_success_conditions(va) ==> {
1697 &&& r is Ok
1698 &&& r.unwrap().0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1699 &&& r.unwrap().1.in_locked_range()
1700 &&& r.unwrap().0.level == r.unwrap().0.guard_level
1701 &&& r.unwrap().0.va < r.unwrap().0.barrier_va.end
1702 &&& r.unwrap().0.va == va.start
1703 &&& r.unwrap().0.barrier_va == *va
1704 &&& r.unwrap().1@.as_page_table_owner() == owner
1705 &&& r.unwrap().1@.continuations[3].path() == owner.0.value.path
1706 },
1707 !Cursor::<C, G>::cursor_new_success_conditions(va) ==> r is Err,
1708 forall|idx: usize| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1709 old(regions).slot_owners[idx].inner_perms.ref_count.value()
1710 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1711 ==> final(regions).slot_owners[idx].paths_in_pt
1712 == old(regions).slot_owners[idx].paths_in_pt,
1713 (forall |i: usize| #![trigger old(regions).slot_owners[i]]
1715 old(regions).slot_owners.contains_key(i)
1716 && old(regions).slot_owners[i].inner_perms.ref_count.value()
1717 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1718 ==> old(regions).slot_owners[i].inner_perms.ref_count.value() + 1
1719 < crate::specs::mm::frame::meta_owners::REF_COUNT_MAX)
1720 ==>
1721 (forall |i: usize| #![trigger final(regions).slot_owners[i]]
1722 final(regions).slot_owners.contains_key(i)
1723 && final(regions).slot_owners[i].inner_perms.ref_count.value()
1724 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1725 ==> final(regions).slot_owners[i].inner_perms.ref_count.value() + 1
1726 < crate::specs::mm::frame::meta_owners::REF_COUNT_MAX),
1727 forall|idx: usize| #![trigger final(regions).slot_owners[idx].inner_perms.ref_count.value()]
1732 final(regions).slot_owners[idx].inner_perms.ref_count.value()
1733 >= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX
1734 ==> old(regions).slot_owners[idx].inner_perms.ref_count.value()
1735 == final(regions).slot_owners[idx].inner_perms.ref_count.value(),
1736 forall|idx: usize| #![trigger old(regions).slot_owners[idx].inner_perms.ref_count.value()]
1737 old(regions).slot_owners[idx].inner_perms.ref_count.value()
1738 >= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX
1739 ==> final(regions).slot_owners[idx].inner_perms.ref_count.value()
1740 == old(regions).slot_owners[idx].inner_perms.ref_count.value(),
1741 )]
1742 pub fn cursor<'rcu, G: InAtomicMode>(&'rcu self, guard: &'rcu G, va: &Range<Vaddr>) -> Result<
1743 (Cursor<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>),
1744 PageTableError,
1745 > {
1746 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1747 Cursor::new(self, guard, va)
1748 }}
1760
1761#[cfg(ktest)]
1784pub(super) unsafe fn page_walk<C: PageTableConfig>(root_paddr: Paddr, vaddr: Vaddr) -> Option<
1785 (Paddr, PageProperty),
1786> {
1787 use super::paddr_to_vaddr;
1788
1789 let _rcu_guard = disable_preempt();
1790
1791 let mut pt_addr = paddr_to_vaddr(root_paddr);
1792 #[verusfmt::skip]
1793 for cur_level in (1..= C::NR_LEVELS()).rev() {
1794 let offset = pte_index::<C>(vaddr, cur_level);
1795 let cur_pte = unsafe { load_pte((pt_addr as *mut C::E).add(offset), Ordering::Acquire) };
1801
1802 if !cur_pte.is_present() {
1803 return None;
1804 }
1805 if cur_pte.is_last(cur_level) {
1806 debug_assert!(cur_level <= C::HIGHEST_TRANSLATION_LEVEL);
1807 return Some(
1808 (cur_pte.paddr() + (vaddr & (page_size::<C>(cur_level) - 1)), cur_pte.prop()),
1809 );
1810 }
1811 pt_addr = paddr_to_vaddr(cur_pte.paddr());
1812 }
1813
1814 unreachable!("All present PTEs at the level 1 must be last-level PTEs");
1815}
1816
1817#[verifier::external_body]
1832#[verus_spec(
1833 with Tracked(perm): Tracked<&vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1834 requires
1835 perm.is_init(ptr.index as int),
1836 perm.addr() == ptr.addr(),
1837 0 <= ptr.index < NR_ENTRIES,
1838 returns
1839 perm.value()[ptr.index as int],
1840)]
1841pub unsafe fn load_pte<E: PageTableEntryTrait>(
1842 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1843 ordering: Ordering,
1844) -> (pte: E) {
1845 unimplemented!()
1846}
1847
1848#[verifier::external_body]
1861#[verus_spec(
1862 with Tracked(perm): Tracked<&mut vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1863 requires
1864 old(perm).addr() == ptr.addr(),
1865 0 <= ptr.index < NR_ENTRIES,
1866 old(perm).is_init_all(),
1867 ensures
1868 final(perm).value()[ptr.index as int] == new_val,
1869 final(perm).value() == old(perm).value().update(ptr.index as int, new_val),
1870 final(perm).addr() == old(perm).addr(),
1871 final(perm).is_init_all(),
1872)]
1873pub unsafe fn store_pte<E: PageTableEntryTrait>(
1874 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1875 new_val: E,
1876 ordering: Ordering,
1877);
1878
1879}