1use vstd::{arithmetic::power2::*, prelude::*, std_specs::clone::*};
3use vstd_extra::{assert, panic::may_panic, prelude::*};
4
5use crate::specs::{
6 arch::*,
7 mm::{
8 frame::{mapping::frame_to_index, meta_region_owners::MetaRegionOwners},
9 page_table::{
10 cursor::*, is_valid_range_spec, nr_pte_index_bits_spec, pte_index_bit_offset_spec,
11 top_level_index_width_spec, vaddr_range_spec, *,
12 },
13 },
14 task::InAtomicMode,
15};
16
17use super::{
18 Paddr, PagingConstsTrait, PagingLevel, PodOnce, Vaddr,
19 kspace::KernelPtConfig,
20 nr_subpage_per_huge,
21 page_prop::{CachePolicy, PageProperty},
22 page_size,
23 vm_space::UserPtConfig,
24};
25use crate::mm::frame::MetaSlot;
26use crate::mm::frame::meta::{
27 REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED, mapping::frame_to_meta,
28};
29use crate::mm::kspace::kvirt_area::disable_preempt;
30use crate::{
31 Pod,
33 arch::mm::{PageTableEntry, PagingConsts},
34};
35use core::{
36 fmt::Debug,
37 intrinsics::transmute_unchecked,
38 ops::{Range, RangeInclusive},
39 sync::atomic::Ordering,
40};
41
42mod node;
43pub use node::*;
44mod cursor;
45
46pub(crate) use cursor::*;
47
48#[cfg(ktest)]
49mod test;
50
51verus! {
54
55#[derive(Clone, Copy, PartialEq, Eq, Debug)]
56pub enum PageTableError {
57 InvalidVaddrRange(Vaddr, Vaddr),
59 InvalidVaddr(Vaddr),
61 UnalignedVaddr,
63}
64
65pub trait RCClone: Sized {
66 spec fn clone_requires(self, perm: MetaRegionOwners) -> bool;
67
68 spec fn clone_ensures(
69 self,
70 old_perm: MetaRegionOwners,
71 new_perm: MetaRegionOwners,
72 res: Self,
73 ) -> bool;
74
75 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self)
76 requires
77 self.clone_requires(*old(perm)),
78 ensures
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(perm).slot_owners.dom(),
83 ;
84}
85
86pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
104 spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize>;
105
106 #[verifier::when_used_as_spec(TOP_LEVEL_INDEX_RANGE_spec)]
113 fn TOP_LEVEL_INDEX_RANGE() -> Range<usize>
114 returns
115 Self::TOP_LEVEL_INDEX_RANGE(),
116 ;
117
118 open spec fn LEADING_BITS_spec() -> usize {
137 0
138 }
139
140 open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
141 true
142 }
143
144 #[verifier::when_used_as_spec(TOP_LEVEL_CAN_UNMAP_spec)]
150 fn TOP_LEVEL_CAN_UNMAP() -> bool
151 returns
152 Self::TOP_LEVEL_CAN_UNMAP(),
153 ;
154
155 open spec fn LOCKED_END_BOUND_spec() -> int {
169 0x1_0000_0000_0000_0000int
170 }
171
172 type E: PageTableEntryTrait;
174
175 type C: PagingConstsTrait;
177
178 type Item: RCClone;
191
192 type Perm;
195
196 spec fn item_into_raw_spec(item: Self::Item) -> (
197 Paddr,
198 PagingLevel,
199 PageProperty,
200 Tracked<Option<Self::Perm>>,
201 );
202
203 #[verifier::when_used_as_spec(item_into_raw_spec)]
209 fn item_into_raw(item: Self::Item) -> ((paddr, level, prop, perm): (
210 Paddr,
211 PagingLevel,
212 PageProperty,
213 Tracked<Option<Self::Perm>>,
214 ))
215 requires
216 Self::item_well_formed(item),
217 ensures
218 Self::raw_item_well_formed((paddr, level, prop, perm)),
219 1 <= level <= NR_LEVELS,
220 valid_frame_paddr(paddr),
221 paddr % page_size::<PagingConsts>(level) == 0,
222 paddr + page_size::<PagingConsts>(level) <= MAX_PADDR,
223 Self::E::new_page_req(paddr, level, prop),
224 returns
225 Self::item_into_raw(item),
226 ;
227
228 spec fn item_from_raw_spec(
229 paddr: Paddr,
230 level: PagingLevel,
231 prop: PageProperty,
232 perm: Tracked<Option<Self::Perm>>,
233 ) -> Self::Item;
234
235 #[verifier::when_used_as_spec(item_from_raw_spec)]
260 unsafe fn item_from_raw(
261 paddr: Paddr,
262 level: PagingLevel,
263 prop: PageProperty,
264 perm: Tracked<Option<Self::Perm>>,
265 ) -> (res: Self::Item)
266 requires
267 Self::raw_item_well_formed((paddr, level, prop, perm)),
268 ensures
269 Self::item_well_formed(res),
270 returns
271 Self::item_from_raw(paddr, level, prop, perm),
272 ;
273
274 spec fn item_well_formed(item: Self::Item) -> bool;
276
277 spec fn raw_item_well_formed(
279 item: (Paddr, PagingLevel, PageProperty, Tracked<Option<Self::Perm>>),
280 ) -> bool;
281
282 spec fn perm_well_formed_with_region(
284 pa: Paddr,
285 perm: Tracked<Option<Self::Perm>>,
286 regions: MetaRegionOwners,
287 ) -> bool;
288
289 proof fn lemma_none_perm_well_formed(pa: Paddr, regions: MetaRegionOwners)
292 ensures
293 Self::perm_well_formed_with_region(pa, Tracked(None), regions),
294 ;
295
296 proof fn lemma_perm_well_formed_with_region_preserved(
297 pa: Paddr,
298 perm: Tracked<Option<Self::Perm>>,
299 old_regions: MetaRegionOwners,
300 new_regions: MetaRegionOwners,
301 )
302 requires
303 Self::perm_well_formed_with_region(pa, perm, old_regions),
304 old_regions.slots[frame_to_index(pa)] == new_regions.slots[frame_to_index(pa)],
305 old_regions.slot_owners[frame_to_index(pa)].metadata_perm.id()
306 == new_regions.slot_owners[frame_to_index(pa)].metadata_perm.id(),
307 ensures
308 Self::perm_well_formed_with_region(pa, perm, new_regions),
309 ;
310
311 proof fn lemma_raw_item_well_formed_preserved(
313 pa: Paddr,
314 level: PagingLevel,
315 old_prop: PageProperty,
316 new_prop: PageProperty,
317 perm: Tracked<Option<Self::Perm>>,
318 )
319 requires
320 valid_frame_paddr(pa),
321 Self::raw_item_well_formed((pa, level, old_prop, perm)),
322 (Self::item_into_raw(Self::item_from_raw(pa, level, new_prop, perm)).3@ is Some) == (
323 perm@ is Some),
324 ensures
325 Self::raw_item_well_formed((pa, level, new_prop, perm)),
326 ;
327
328 proof fn lemma_raw_item_well_formed_split(
330 pa: Paddr,
331 level: PagingLevel,
332 prop: PageProperty,
333 child_pa: Paddr,
334 child_idx: usize,
335 perm: Tracked<Option<Self::Perm>>,
336 )
337 requires
338 valid_frame_paddr(pa),
339 Self::raw_item_well_formed((pa, level, prop, perm)),
340 Self::E::new_page_req(pa, level, prop),
341 level > 1,
342 child_idx < NR_ENTRIES,
343 child_pa == pa + child_idx * page_size::<PagingConsts>((level - 1) as PagingLevel),
344 ensures
345 Self::raw_item_well_formed((child_pa, (level - 1) as PagingLevel, prop, perm)),
346 Self::E::new_page_req(child_pa, (level - 1) as PagingLevel, prop),
347 ;
348
349 proof fn lemma_huge_raw_item_untracked(
352 pa: Paddr,
353 level: PagingLevel,
354 prop: PageProperty,
355 perm: Tracked<Option<Self::Perm>>,
356 )
357 requires
358 Self::raw_item_well_formed((pa, level, prop, perm)),
359 level > 1,
360 ensures
361 perm@ is None,
362 ;
363
364 proof fn lemma_item_from_raw_well_formed(
366 pa: Paddr,
367 level: PagingLevel,
368 prop: PageProperty,
369 perm: Tracked<Option<Self::Perm>>,
370 )
371 requires
372 valid_frame_paddr(pa),
373 Self::raw_item_well_formed((pa, level, prop, perm)),
374 ensures
375 Self::item_well_formed(Self::item_from_raw(pa, level, prop, perm)),
376 ;
377
378 proof fn lemma_item_into_raw_roundtrip(
380 pa: Paddr,
381 level: PagingLevel,
382 prop: PageProperty,
383 perm: Tracked<Option<Self::Perm>>,
384 )
385 requires
386 valid_frame_paddr(pa),
387 Self::raw_item_well_formed((pa, level, prop, perm)),
388 ensures
389 Self::item_into_raw(Self::item_from_raw(pa, level, prop, perm)) == (
390 pa,
391 level,
392 prop,
393 perm,
394 ),
395 ;
396
397 proof fn lemma_item_from_raw_roundtrip(
399 item: Self::Item,
400 pa: Paddr,
401 level: PagingLevel,
402 prop: PageProperty,
403 perm: Tracked<Option<Self::Perm>>,
404 )
405 requires
406 valid_frame_paddr(pa),
407 Self::item_well_formed(item),
408 Self::item_into_raw(item) == (pa, level, prop, perm),
409 ensures
410 Self::item_from_raw(pa, level, prop, perm) == item,
411 ;
412
413 proof fn lemma_clone_ensures_concrete(
416 item: Self::Item,
417 pa: Paddr,
418 old_regions: MetaRegionOwners,
419 new_regions: MetaRegionOwners,
420 res: Self::Item,
421 )
422 requires
423 item.clone_ensures(old_regions, new_regions, res),
424 Self::item_into_raw(item).0 == pa,
425 new_regions.inv(),
426 new_regions.slots =~= old_regions.slots,
427 new_regions.slot_owners.dom() =~= old_regions.slot_owners.dom(),
428 ensures
429 Self::item_into_raw(res).0 == Self::item_into_raw(item).0,
430 Self::item_into_raw(res).1 == Self::item_into_raw(item).1,
431 Self::item_into_raw(res).2 == Self::item_into_raw(item).2,
432 (Self::item_into_raw(res).3@ is Some) == (Self::item_into_raw(item).3@ is Some),
433 Self::item_into_raw(item).3@ is Some ==> {
434 old_regions.inc_frame_reference_region_spec(pa, new_regions)
435 },
436 Self::item_into_raw(item).3@ is None ==> new_regions == old_regions,
437 ;
438
439 proof fn lemma_clone_requires_concrete(
440 item: Self::Item,
441 pa: Paddr,
442 level: PagingLevel,
443 prop: PageProperty,
444 regions: MetaRegionOwners,
445 )
446 requires
447 regions.inv(),
448 Self::item_from_raw(pa, level, prop, Self::item_into_raw(item).3) == item,
449 Self::raw_item_well_formed((pa, level, prop, Self::item_into_raw(item).3)),
450 Self::perm_well_formed_with_region(pa, Self::item_into_raw(item).3, regions),
451 valid_frame_paddr(pa),
452 regions.contains(frame_to_index(pa)),
453 Self::item_into_raw(item).3@ is Some ==> {
454 &&& 0 < regions.slot_owner(pa).ref_count()
455 &&& regions.slot_owner(pa).ref_count() != REF_COUNT_UNUSED
456 &&& regions.slot_owner(pa).ref_count() >= REF_COUNT_MAX ==> may_panic()
457 },
458 ensures
459 item.clone_requires(regions),
460 ;
461
462 proof fn lemma_page_table_config_constant_requirements()
469 ensures
470 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
471 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end,
472 Self::TOP_LEVEL_INDEX_RANGE().end <= pow2(
473 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
474 Self::C::NR_LEVELS(),
475 )) as nat,
476 ),
477 Self::TOP_LEVEL_INDEX_RANGE().end * pow2(
478 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
479 ) <= usize::MAX,
480 Self::LEADING_BITS_spec() != 0usize ==> (Self::C::VA_SIGN_EXT() && ((
481 Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
482 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
483 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1),
484 (Self::C::VA_SIGN_EXT() && (((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::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int
488 - pow2(Self::C::ADDRESS_WIDTH() as nat)
489 },
490 Self::LEADING_BITS_spec() < 0x1_0000_usize,
491 pow2(
493 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
494 Self::C::NR_LEVELS(),
495 )) as nat,
496 ) == NR_ENTRIES,
497 ;
498
499 proof fn lemma_page_table_config_constant_properties()
503 ensures
504 Self::TOP_LEVEL_INDEX_RANGE().end <= NR_ENTRIES,
507 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
510 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end,
511 Self::TOP_LEVEL_INDEX_RANGE().end <= pow2(
512 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
513 Self::C::NR_LEVELS(),
514 )) as nat,
515 ),
516 Self::TOP_LEVEL_INDEX_RANGE().end * pow2(
517 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
518 ) <= usize::MAX,
519 Self::LEADING_BITS_spec() != 0usize ==> (Self::C::VA_SIGN_EXT() && ((
520 Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
521 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
522 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1),
523 (Self::C::VA_SIGN_EXT() && (((Self::TOP_LEVEL_INDEX_RANGE().start * pow2(
524 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
525 )) / (pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int)) % 2 == 1)) ==> {
526 &&& Self::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int
527 - pow2(Self::C::ADDRESS_WIDTH() as nat)
528 },
529 Self::LEADING_BITS_spec() < 0x1_0000_usize,
530 pow2(
532 (Self::C::ADDRESS_WIDTH() - pte_index_bit_offset_spec::<Self::C>(
533 Self::C::NR_LEVELS(),
534 )) as nat,
535 ) == NR_ENTRIES,
536 {
537 Self::C::lemma_paging_consts_properties();
538 Self::lemma_page_table_config_constant_requirements();
539 }
540}
541
542impl<C: PageTableConfig> PagingConstsTrait for C {
545 open spec fn BASE_PAGE_SIZE_spec() -> usize {
546 C::C::BASE_PAGE_SIZE_spec()
547 }
548
549 fn BASE_PAGE_SIZE() -> usize {
550 C::C::BASE_PAGE_SIZE()
551 }
552
553 open spec fn NR_LEVELS_spec() -> PagingLevel {
554 C::C::NR_LEVELS_spec()
555 }
556
557 fn NR_LEVELS() -> PagingLevel {
558 proof {
559 assert(Self::NR_LEVELS() == C::C::NR_LEVELS());
560 }
561 C::C::NR_LEVELS()
562 }
563
564 open spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel {
565 C::C::HIGHEST_TRANSLATION_LEVEL_spec()
566 }
567
568 fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel {
569 C::C::HIGHEST_TRANSLATION_LEVEL()
570 }
571
572 open spec fn PTE_SIZE_spec() -> usize {
573 C::C::PTE_SIZE_spec()
574 }
575
576 fn PTE_SIZE() -> usize {
577 C::C::PTE_SIZE()
578 }
579
580 open spec fn ADDRESS_WIDTH_spec() -> usize {
581 C::C::ADDRESS_WIDTH_spec()
582 }
583
584 fn ADDRESS_WIDTH() -> usize {
585 C::C::ADDRESS_WIDTH()
586 }
587
588 open spec fn VA_SIGN_EXT_spec() -> bool {
589 C::C::VA_SIGN_EXT_spec()
590 }
591
592 fn VA_SIGN_EXT() -> bool {
593 C::C::VA_SIGN_EXT()
594 }
595
596 proof fn lemma_paging_consts_requirements() {
597 C::C::lemma_paging_consts_requirements();
598 }
599}
600
601#[verifier::external_body]
626pub fn largest_pages<C: PageTableConfig>(
627 mut va: Vaddr,
628 mut pa: Paddr,
629 mut len: usize,
630) -> impl Iterator<Item = (Paddr, PagingLevel)> {
631 assert_eq!(va % C::BASE_PAGE_SIZE(), 0);
632 assert_eq!(pa % C::BASE_PAGE_SIZE(), 0);
633 assert_eq!(len % C::BASE_PAGE_SIZE(), 0);
634 assert!(is_valid_range::<C>(&(va..(va + len))));
635
636 core::iter::from_fn(
637 move ||
638 {
639 if len == 0 {
640 return None;
641 }
642 let mut level = C::HIGHEST_TRANSLATION_LEVEL();
643 while page_size::<C>(level) > len || va % page_size::<C>(level) != 0 || pa
644 % page_size::<C>(level) != 0 {
645 level -= 1;
646 }
647
648 let item_start = pa;
649 va += page_size::<C>(level);
650 pa += page_size::<C>(level);
651 len -= page_size::<C>(level);
652
653 Some((item_start, level))
654 },
655 )
656}
657
658fn top_level_index_width<C: PageTableConfig>() -> (ret: usize)
660 returns
661 top_level_index_width_spec::<C>(),
662{
663 proof {
664 C::lemma_paging_consts_properties();
665 C::lemma_page_table_config_constant_properties();
666 }
667
668 C::ADDRESS_WIDTH() - pte_index_bit_offset::<C>(C::NR_LEVELS())
669}
670
671fn pt_va_range_start<C: PageTableConfig>() -> (ret: Vaddr)
672 ensures
673 ret == C::TOP_LEVEL_INDEX_RANGE().start * pow2(
674 pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat,
675 ),
676{
677 proof {
678 C::lemma_paging_consts_properties();
679 let ghost idx_start = C::TOP_LEVEL_INDEX_RANGE().start;
680 let ghost offset = pte_index_bit_offset_spec::<C>(C::NR_LEVELS());
681 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_start_shift_facts::<C>(
682 idx_start,
683 offset,
684 );
685 vstd::bits::lemma_usize_shl_is_mul(idx_start, offset);
686 }
687
688 C::TOP_LEVEL_INDEX_RANGE().start << pte_index_bit_offset::<C>(C::NR_LEVELS())
689}
690
691fn pt_va_range_end<C: PageTableConfig>() -> (ret: Vaddr)
697 ensures
698 ret == (C::TOP_LEVEL_INDEX_RANGE().end * pow2(
699 pte_index_bit_offset_spec::<C>(C::NR_LEVELS()) as nat,
700 ) - 1) % 0x1_0000_0000_0000_0000int,
701{
702 let idx_end = C::TOP_LEVEL_INDEX_RANGE().end;
703 proof {
704 C::lemma_paging_consts_properties();
705 }
706 let offset = pte_index_bit_offset::<C>(C::NR_LEVELS());
707
708 proof {
709 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_end_shift_facts::<C>(
710 idx_end,
711 offset,
712 );
713 vstd::bits::lemma_usize_shl_is_mul(idx_end, offset);
714 }
715
716 let shifted = idx_end << offset;
717 let ret = shifted.wrapping_sub(1);
718
719 proof {
720 assert(shifted == idx_end * pow2(offset as nat));
721 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_end_wrapping_sub::<C>(
722 idx_end,
723 offset,
724 shifted,
725 ret,
726 );
727 }
728 ret
729}
730
731fn sign_bit_of_va<C: PageTableConfig>(va: Vaddr) -> (ret: bool)
732 ensures
733 ret == ((va as int / pow2((C::ADDRESS_WIDTH() - 1) as nat) as int) % 2 == 1),
734{
735 proof {
736 C::lemma_paging_consts_properties();
737 C::lemma_page_table_config_constant_properties();
738 vstd::bits::lemma_usize_shr_is_div(va, (C::ADDRESS_WIDTH() - 1) as usize);
739 vstd::bits::lemma_usize_low_bits_mask_is_mod(va >> (C::ADDRESS_WIDTH() - 1), 1);
740 vstd::bits::lemma_low_bits_mask_values();
741 vstd::arithmetic::power2::lemma2_to64();
742 }
743 (va >> (C::ADDRESS_WIDTH() - 1)) & 1 != 0
744}
745
746fn apply_sign_ext<C: PageTableConfig>(va: Vaddr) -> (ret: Vaddr)
753 requires
754 va < pow2(C::ADDRESS_WIDTH() as nat),
755 C::ADDRESS_WIDTH() < usize::BITS,
756 C::LEADING_BITS_spec() * 0x1_0000_0000_0000int == 0x1_0000_0000_0000_0000int - pow2(
757 C::ADDRESS_WIDTH() as nat,
758 ),
759 ensures
760 ret == va + C::LEADING_BITS_spec() * 0x1_0000_0000_0000int,
761{
762 let address_width = C::ADDRESS_WIDTH();
763 let low_bit = 1usize << address_width;
764 proof {
765 vstd::layout::unsigned_int_max_values();
766 vstd::bits::lemma_usize_pow2_no_overflow(address_width as nat);
767 vstd::bits::lemma_usize_shl_is_mul(1usize, address_width);
768 }
769 let low_mask = low_bit - 1;
770 let sign_ext_mask = !0 ^ low_mask;
771 let ret = va | sign_ext_mask;
772 proof {
773 assert(!0usize == 0xffff_ffff_ffff_ffffusize) by (compute_only);
774 assert(sign_ext_mask == usize::MAX - low_mask) by (bit_vector)
775 requires
776 sign_ext_mask == (!0usize ^ low_mask),
777 !0usize == 0xffff_ffff_ffff_ffffusize,
778 usize::MAX == 0xffff_ffff_ffff_ffffusize,
779 ;
780 assert(pow2(64) == 0x1_0000_0000_0000_0000nat) by {
781 vstd::arithmetic::power2::lemma2_to64();
782 };
783 assert(sign_ext_mask == 0x1_0000_0000_0000_0000int - pow2(address_width as nat));
784 assert(sign_ext_mask == C::LEADING_BITS_spec() * 0x1_0000_0000_0000int);
785
786 assert((va & sign_ext_mask) == 0usize) by (bit_vector)
787 requires
788 address_width < usize::BITS,
789 low_bit == 1usize << address_width,
790 low_mask == low_bit - 1,
791 sign_ext_mask == !0usize ^ low_mask,
792 va < low_bit,
793 ;
794 assert(ret == va + sign_ext_mask) by (bit_vector)
795 requires
796 ret == va | sign_ext_mask,
797 (va & sign_ext_mask) == 0usize,
798 ;
799 }
800 ret
801}
802
803#[verusfmt::skip]
810fn vaddr_range<C: PageTableConfig>() -> (ret: RangeInclusive<Vaddr>)
811 ensures
812 ret@ == vaddr_range_spec::<C>(),
813{
814 let mut start = pt_va_range_start::<C>();
815 let mut end = pt_va_range_end::<C>();
816
817 proof {
818 C::lemma_paging_consts_properties();
819 C::lemma_page_table_config_constant_properties();
820 crate::specs::mm::page_table::vaddr_range_proofs::lemma_idx_times_pow2_bound::<C>(
821 start,
822 end,
823 );
824 }
825
826 if C::VA_SIGN_EXT() && sign_bit_of_va::<C>(pt_va_range_start::<C>()) {
827 start = apply_sign_ext::<C>(start);
828 end = apply_sign_ext::<C>(end);
829 }
830 start..=end
831}
832
833fn is_valid_range<C: PageTableConfig>(r: &Range<Vaddr>) -> bool
835 requires
836 r.end > 0,
837 returns
838 is_valid_range_spec::<C>(*r),
839{
840 let va_range = vaddr_range::<C>();
841 (r.start == 0 && r.end == 0) || (*va_range.start() <= r.start && r.end - 1 <= *va_range.end())
842}
843
844fn nr_pte_index_bits<C: PagingConstsTrait>() -> usize
847 returns
848 nr_pte_index_bits_spec::<C>(),
849{
850 proof {
851 C::lemma_paging_consts_properties();
852 }
853 nr_subpage_per_huge::<C>().ilog2() as usize
854}
855
856fn pte_index<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel) -> (res: usize)
858 requires
859 1 <= level <= C::NR_LEVELS(),
860 returns
861 pte_index_spec::<C>(va, level),
862{
863 proof {
864 C::lemma_paging_consts_properties();
865 }
866 (va >> pte_index_bit_offset::<C>(level)) & (nr_subpage_per_huge::<C>() - 1)
867}
868
869fn pte_index_bit_offset<C: PagingConstsTrait>(level: PagingLevel) -> usize
875 requires
876 1 <= level <= C::NR_LEVELS(),
877 ensures
878 pte_index_bit_offset_spec::<C>(level) < usize::BITS,
879 returns
880 pte_index_bit_offset_spec::<C>(level),
881{
882 proof {
883 C::lemma_paging_consts_properties();
884 assert(C::BASE_PAGE_SIZE().ilog2() + nr_pte_index_bits_spec::<C>() * (level - 1)
885 < usize::BITS) by (nonlinear_arith)
886 requires
887 level <= C::NR_LEVELS(),
888 C::BASE_PAGE_SIZE().ilog2() + nr_pte_index_bits_spec::<C>() * C::NR_LEVELS()
889 <= C::ADDRESS_WIDTH(),
890 C::ADDRESS_WIDTH() < usize::BITS,
891 ;
892 }
893 C::BASE_PAGE_SIZE().ilog2() as usize + nr_pte_index_bits::<C>() * (level as usize - 1)
894}
895
896pub struct PageTable<C: PageTableConfig> {
899 pub root: PageTableNode<C>,
900}
901
902impl PageTable<KernelPtConfig> {
914 #[verifier::external_body]
916 pub(crate) fn new_kernel_page_table() -> Self {
917 unimplemented!()}
933
934 pub open spec fn create_user_pt_panic_condition(root_owner: NodeOwner<KernelPtConfig>) -> bool {
938 exists|i: usize|
939 #![trigger root_owner.children_perm.value()[i as int]]
940 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
941 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
942 let pte = root_owner.children_perm.value()[i as int];
943 ||| !pte.is_present()
944 ||| pte.is_last(root_owner.level())
945 }
946 }
947
948 #[verus_spec(r =>
953 with Tracked(kernel_owner): Tracked<&PageTableOwner<KernelPtConfig>>,
954 Tracked(regions): Tracked<&mut MetaRegionOwners>,
955 Tracked(guards): Tracked<&mut Guards>,
956 requires
957 kernel_owner.inv(),
958 old(regions).inv(),
959 kernel_owner.0.value().is_node(),
960 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
961 self.root.ptr.addr() == kernel_owner.0.value().node().slot_vaddr(),
963 kernel_owner.0.value().metaregion_sound(*old(regions)),
965 kernel_owner.metaregion_sound(*old(regions)),
969 old(guards).unlocked(kernel_owner.0.value().node().slot_vaddr()),
971 ensures
972 final(regions).inv(),
973 )]
974 pub(in crate::mm) fn create_user_page_table<'rcu, G: InAtomicMode + 'static>(
975 &'static self,
976 ) -> PageTable<UserPtConfig> {
977 let preempt_guard: &'rcu G = disable_preempt::<G>();
978
979 proof_decl! {
980 let tracked mut new_pt_owner: Option<PageTableOwner<UserPtConfig>> = None;
981 }
982 let ghost regions_before_alloc = *regions;
983 let new_pt: PageTable<UserPtConfig> = (
984 #[verus_spec(with Tracked(&mut new_pt_owner), Tracked(regions), Tracked(guards))]
985 PageTable::empty_with_owner());
986 let new_root = new_pt.root;
987 let ghost new_idx_g: int = crate::specs::mm::frame::mapping::frame_to_index(
989 new_pt_owner@.unwrap().0.value().meta_slot_paddr().unwrap(),
990 );
991 let ghost new_pt_owner_snap = new_pt_owner@.unwrap();
992 proof {
993 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
994 kernel_owner.0.value().meta_slot_paddr().unwrap(),
995 );
996 let new_idx = new_idx_g;
997 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
998 KernelPtConfig,
999 >::lemma_active_entry_not_in_free_pool(
1000 kernel_owner.0.value(),
1001 regions_before_alloc,
1002 new_idx,
1003 );
1004 assert(kern_idx != new_idx);
1005 assert(regions.slot_owners[kern_idx] == regions_before_alloc.slot_owners[kern_idx]);
1006 assert(kernel_owner.metaregion_sound(*regions));
1007 assert(!regions.contains(new_idx));
1008 }
1009
1010 proof_decl! {
1011 let tracked root_owner: &NodeOwner<KernelPtConfig>
1012 = kernel_owner.0.tracked_borrow_value().tracked_borrow_node();
1013 let tracked mut new_pt_owner_val: PageTableOwner<UserPtConfig>
1014 = new_pt_owner.tracked_take();
1015 let tracked mut new_node_owner: NodeOwner<UserPtConfig> = {
1016 let tracked new_pt_value = new_pt_owner_val.0.tracked_borrow_mut_value();
1017 new_pt_value.tracked_take_node()
1018 };
1019 let tracked mut entry_owner: &EntryOwner<KernelPtConfig>;
1020 }
1021
1022 proof {
1025 assert(kernel_owner.0.value().is_node());
1026 assert(kernel_owner.0.value().metaregion_sound(*regions));
1027 }
1028 let ghost regions_before_self_borrow: MetaRegionOwners = *regions;
1029 let mut root_node = {
1030 let root_ref = self.root.borrow();
1031 #[verus_spec(with Tracked(root_owner), Tracked(guards))]
1032 root_ref.lock(preempt_guard)
1033 };
1034 let ghost regions_after_kroot_borrow: MetaRegionOwners = *regions;
1035 let mut new_node: PageTableGuard<'rcu, UserPtConfig> = {
1036 let new_ref = new_root.borrow();
1037 #[verus_spec(with Tracked(&new_node_owner), Tracked(guards))]
1038 new_ref.lock(preempt_guard)
1039 };
1040 proof {
1041 let kern_idx = crate::specs::mm::frame::mapping::frame_to_index(
1042 kernel_owner.0.value().meta_slot_paddr().unwrap(),
1043 );
1044 assert(regions_before_self_borrow.slot_owners
1045 == regions_after_kroot_borrow.slot_owners);
1046 assert forall|k: int|
1047 regions_before_self_borrow.contains(k) implies regions_before_self_borrow.slots[k]
1048 == #[trigger] regions_after_kroot_borrow.slots[k] by {
1049 if k == kern_idx {
1050 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1051 KernelPtConfig,
1052 >::lemma_active_entry_not_in_free_pool(
1053 kernel_owner.0.value(),
1054 regions_before_self_borrow,
1055 k,
1056 );
1057 }
1058 };
1059 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1060 regions_before_self_borrow,
1061 regions_after_kroot_borrow,
1062 );
1063
1064 let new_idx = new_idx_g;
1065 assert(regions_before_alloc.contains(new_idx));
1066 assert(kern_idx != new_idx) by {
1067 crate::specs::mm::page_table::node::entry_owners::EntryOwner::<
1068 KernelPtConfig,
1069 >::lemma_active_entry_not_in_free_pool(
1070 kernel_owner.0.value(),
1071 regions_before_alloc,
1072 new_idx,
1073 );
1074 };
1075
1076 assert(!regions_before_self_borrow.contains(new_idx));
1077 assert(!regions_after_kroot_borrow.contains(new_idx));
1078 assert forall|k: int|
1079 regions_after_kroot_borrow.contains(k) implies regions_after_kroot_borrow.slots[k]
1080 == #[trigger] regions.slots[k] by {};
1081 assert(kernel_owner.metaregion_sound(regions_before_alloc));
1082
1083 kernel_owner.0.lemma_subtree_satisfies_implies(
1084 kernel_owner.0.value().path,
1085 |
1086 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1087 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1088 |
1089 e.is_frame() && e.parent_level > 1 ==> {
1090 let pa = e.frame().mapped_pa;
1091 let nr_pages = page_size::<PagingConsts>(e.parent_level) / PAGE_SIZE;
1092 forall|j: usize|
1093 0 < j < nr_pages ==> {
1094 let sub_idx =
1095 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1096 (pa + j * PAGE_SIZE) as usize,
1097 );
1098 sub_idx != new_idx
1099 }
1100 },
1101 |
1102 e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1103 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>,
1104 |
1105 e.is_frame() && e.parent_level > 1 ==> {
1106 let pa = e.frame().mapped_pa;
1107 let nr_pages = page_size::<PagingConsts>(e.parent_level) / PAGE_SIZE;
1108 forall|j: usize|
1109 0 < j < nr_pages ==> {
1110 let sub_idx =
1111 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1112 (pa + j * PAGE_SIZE) as usize,
1113 );
1114 sub_idx != new_idx || (regions.contains(sub_idx)
1115 && regions.ref_count(sub_idx) != REF_COUNT_UNUSED
1116 && regions.ref_count(sub_idx) > 0 && regions.ref_count(sub_idx)
1117 <= REF_COUNT_MAX)
1118 }
1119 },
1120 );
1121 kernel_owner.metaregion_sound_preserved_one_slot_changed(
1122 regions_after_kroot_borrow,
1123 *regions,
1124 new_idx,
1125 );
1126 }
1127 let mut i: usize = KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start;
1128 while i < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end
1129 invariant
1130 kernel_owner.inv(),
1131 kernel_owner.0.value().is_node(),
1132 regions.inv(),
1133 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
1134 i <= KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end,
1135 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i,
1136 *root_owner == kernel_owner.0.value().node(),
1138 root_owner.relate_guard(root_node),
1139 kernel_owner.metaregion_sound(*regions),
1141 new_node_owner.inv(),
1143 new_node_owner.relate_guard(new_node),
1144 regions.contains(new_node_owner.slot_index),
1145 decreases KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end - i,
1146 {
1147 proof {
1148 let kern_node = kernel_owner.0.value().node();
1149 assert forall|j: usize|
1150 #![trigger kern_node.children_perm.value()[j as int]]
1151 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1152 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end implies {
1153 let pte = kern_node.children_perm.value()[j as int];
1154 pte.is_present() && !pte.is_last(kern_node.level())
1155 } by {
1156 let pte = kern_node.children_perm.value()[j as int];
1157 if !pte.is_present() || pte.is_last(kern_node.level()) {
1158 assert(Self::create_user_pt_panic_condition(kern_node));
1159 }
1160 }
1161
1162 kernel_owner.pt_inv_unroll(i as int);
1163 let tracked child_subtree: &OwnerSubtree<KernelPtConfig> =
1164 kernel_owner.0.tracked_borrow_child(i as int);
1165 entry_owner = child_subtree.tracked_borrow_value();
1166 let kern_node = kernel_owner.0.value().node();
1167 assert(entry_owner.match_pte(
1168 kern_node.children_perm.value()[i as int],
1169 entry_owner.parent_level,
1170 ));
1171 assert(entry_owner.parent_level == kern_node.level());
1172 assert(child_subtree.inv());
1173 assert(entry_owner.inv());
1174 assert(root_owner.relate_guard(root_node));
1175
1176 kernel_owner.0.lemma_subtree_satisfies_unroll_once(
1177 kernel_owner.0.value().path,
1178 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1179 i as int,
1180 );
1181 assert(child_subtree.subtree_satisfies(
1182 kernel_owner.0.value().path.push_tail(i as int),
1183 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1184 ));
1185 assert(entry_owner.metaregion_sound(*regions));
1186 }
1187
1188 #[verus_spec(with Tracked(root_owner), Tracked(entry_owner), Tracked(&*regions))]
1189 let root_entry = root_node.entry(i);
1190 let ghost pre_to_ref_regions: MetaRegionOwners = *regions;
1191 #[verus_spec(with Tracked(entry_owner), Tracked(root_owner), Tracked(regions))]
1192 let child = root_entry.to_ref();
1193
1194 proof {
1195 let kern_node = kernel_owner.0.value().node();
1196 let pte = kern_node.children_perm.value()[i as int];
1197
1198 assert(pte.is_present() && !pte.is_last(kern_node.level())) by {
1199 if !pte.is_present() || pte.is_last(kern_node.level()) {
1200 assert(KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
1201 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end);
1202 assert(exists|j: usize|
1203 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1204 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
1205 let p = #[trigger] kern_node.children_perm.value()[j as int];
1206 ||| !p.is_present()
1207 ||| p.is_last(kern_node.level())
1208 });
1209 assert(Self::create_user_pt_panic_condition(kern_node));
1210 }
1211 }
1212 assert(entry_owner.is_node());
1215 assert(child is PageTable);
1219 kernel_owner.metaregion_sound_preserved_slot_owners_eq(
1223 pre_to_ref_regions,
1224 *regions,
1225 );
1226 }
1227 let pt = match child {
1228 ChildRef::PageTable(pt) => pt,
1229 _ => vstd::pervasive::unreached(),
1230 };
1231
1232 let pt_addr = pt.start_paddr();
1233 let pte = PageTableEntry::new_pt(pt_addr);
1234
1235 proof {
1236 assert(regions.contains(new_node_owner.slot_index));
1237 }
1238 unsafe {
1239 #[verus_spec(with Tracked(&mut new_node_owner), Tracked(&*regions))]
1240 new_node.write_pte(i, pte)
1241 };
1242
1243 i = i + 1;
1244 }
1245
1246 PageTable::<UserPtConfig> { root: new_root }
1247 }}
1273
1274#[verus_verify]
1275impl<C: PageTableConfig> PageTable<C> {
1276 pub open spec fn relates_owner(
1278 &self,
1279 owner: PageTableOwner<C>,
1280 regions: MetaRegionOwners,
1281 ) -> bool {
1282 &&& owner.inv()
1283 &&& self.root.ptr.addr() == owner.0.value().node().slot_vaddr()
1284 &&& owner.metaregion_sound(regions)
1285 }
1286
1287 #[verifier::external_body]
1291 pub fn empty() -> Self {
1292 unimplemented!()
1293 }
1294
1295 #[verifier::external_body]
1297 #[verus_spec(r =>
1298 with Tracked(owner): Tracked<&mut Option<PageTableOwner<C>>>,
1299 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1300 Tracked(guards): Tracked<&mut Guards>,
1301 requires
1302 old(regions).inv(),
1303 ensures
1304 final(owner)@ is Some,
1305 final(owner)@->0.inv(),
1306 (final(owner)@->0).0.value().is_node(),
1307 (final(owner)@->0).0.value().is_node(),
1308 r.root.ptr.addr() == (final(owner)@->0).0.value().node().slot_vaddr(),
1309 (final(owner)@->0).0.value().metaregion_sound(*final(regions)),
1310 final(regions).inv(),
1311 final(guards).unlocked((final(owner)@->0).0.value().node().slot_vaddr()),
1312 final(guards).guards == old(guards).guards,
1315 old(regions).contains(
1317 crate::specs::mm::frame::mapping::frame_to_index(
1318 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1319 !final(regions).contains(
1322 crate::specs::mm::frame::mapping::frame_to_index(
1323 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1324 forall |i: int| #![trigger final(regions).slot_owners[i]]
1326 i != crate::specs::mm::frame::mapping::frame_to_index(
1327 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1328 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
1329 forall |a: usize| old(guards).lock_held(a) ==> final(guards).lock_held(a),
1330 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1331 final(regions).slot_owners[idx].paths_in_pt
1332 == old(regions).slot_owners[idx].paths_in_pt,
1333 forall |kt: PageTableOwner<KernelPtConfig>|
1339 #![trigger kt.metaregion_sound(*final(regions))]
1340 kt.inv() && kt.metaregion_sound(*old(regions))
1341 ==> kt.metaregion_sound(*final(regions)),
1342 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.meta_slot_paddr() is Some
1354 ==> crate::specs::mm::frame::mapping::frame_to_index(
1355 e.meta_slot_paddr()->0) !=
1356 crate::specs::mm::frame::mapping::frame_to_index(
1357 (final(owner)@->0).0.value().meta_slot_paddr()->0),
1358 ),
1359 forall |kt: PageTableOwner<KernelPtConfig>|
1363 #![trigger kt.metaregion_sound(*old(regions))]
1364 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1365 kt.0.subtree_satisfies(
1366 kt.0.value().path,
1367 |e: crate::specs::mm::page_table::node::entry_owners::EntryOwner<KernelPtConfig>,
1368 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1369 e.is_frame() && e.parent_level > 1 ==> {
1370 let pa = e.frame().mapped_pa;
1371 let nr_pages = page_size::<PagingConsts>(
1372 e.parent_level) / PAGE_SIZE;
1373 forall |j: usize| 0 < j < nr_pages ==> {
1374 let sub_idx =
1375 #[trigger] crate::specs::mm::frame::mapping::frame_to_index(
1376 (pa + j * PAGE_SIZE) as usize);
1377 sub_idx != crate::specs::mm::frame::mapping::frame_to_index(
1378 (final(owner)@->0).0.value().meta_slot_paddr()->0)
1379 }
1380 },
1381 ),
1382 )]
1383 pub fn empty_with_owner<'rcu>() -> Self {
1384 unimplemented!()
1385 }
1386
1387 #[verifier::external_body]
1388 pub(in crate::mm) unsafe fn first_activate_unchecked(&self) {
1389 unimplemented!()
1390 }
1394
1395 pub uninterp spec fn root_paddr_spec(&self) -> Paddr;
1396
1397 #[verifier::external_body]
1403 #[verifier::when_used_as_spec(root_paddr_spec)]
1404 pub fn root_paddr(&self) -> (r: Paddr)
1405 returns
1406 self.root_paddr_spec(),
1407 {
1408 unimplemented!()
1409 }
1412
1413 #[cfg(ktest)]
1419 pub fn page_walk(&self, vaddr: Vaddr) -> Option<(Paddr, PageProperty)> {
1420 unsafe { page_walk::<C>(self.root_paddr(), vaddr) }
1422 }
1423
1424 #[verus_spec(r =>
1429 with Tracked(owner): Tracked<PageTableOwner<C>>,
1430 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1431 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1432 Tracked(guards): Tracked<&mut Guards>
1433 requires
1434 self.relates_owner(owner, *old(regions)),
1435 owner.0.value().node().relate_guard(root_guard),
1436 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1438 ensures
1439 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1440 &&& r is Ok
1441 &&& r.unwrap().0.0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1442 &&& r.unwrap().1.in_locked_range()
1443 &&& r.unwrap().0.0.level == r.unwrap().0.0.guard_level
1444 &&& r.unwrap().0.0.guard_level == NR_LEVELS as PagingLevel
1445 &&& r.unwrap().0.0.va < r.unwrap().0.0.barrier_va.end
1446 &&& r.unwrap().0.0.va == va.start
1447 &&& r.unwrap().0.0.barrier_va == *va
1448 },
1449 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1450 forall |item: C::Item| #![trigger CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions))]
1451 CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions)) ==>
1452 CursorMut::<'rcu, C, G>::item_not_mapped(item, *final(regions)),
1453 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1457 old(regions).ref_count(idx)
1458 != REF_COUNT_UNUSED
1459 ==> final(regions).slot_owners[idx].paths_in_pt
1460 == old(regions).slot_owners[idx].paths_in_pt,
1461 forall|idx: int| #![trigger final(regions).slot_owners[idx]]
1462 old(regions).contains(idx)
1463 && old(regions).ref_count(idx)
1464 != REF_COUNT_UNUSED
1465 ==> final(regions).ref_count(idx)
1466 == old(regions).ref_count(idx)
1467 && final(regions).slot_owners[idx].usage
1468 == old(regions).slot_owners[idx].usage,
1469 )]
1470 pub fn cursor_mut<'rcu, G: InAtomicMode>(
1471 &'rcu self,
1472 guard: &'rcu G,
1473 va: &Range<Vaddr>,
1474 ) -> Result<(CursorMut<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>), PageTableError> {
1475 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1476 CursorMut::new(self, guard, va)
1477 }
1478
1479 #[verus_spec(r =>
1485 with Tracked(owner): Tracked<PageTableOwner<C>>,
1486 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1487 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1488 Tracked(guards): Tracked<&mut Guards>
1489 requires
1490 self.relates_owner(owner, *old(regions)),
1491 owner.0.value().node().relate_guard(root_guard),
1492 0 < va.end <= C::LOCKED_END_BOUND_spec(),
1494 ensures
1495 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1496 &&& r is Ok
1497 &&& r.unwrap().0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1498 &&& r.unwrap().1.in_locked_range()
1499 &&& r.unwrap().0.level == r.unwrap().0.guard_level
1500 &&& r.unwrap().0.va < r.unwrap().0.barrier_va.end
1501 &&& r.unwrap().0.va == va.start
1502 &&& r.unwrap().0.barrier_va == *va
1503 &&& r.unwrap().1@.as_page_table_owner() == owner
1504 &&& r.unwrap().1@.continuations[3].path() == owner.0.value().path
1505 },
1506 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1507 forall|idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1508 old(regions).ref_count(idx)
1509 != REF_COUNT_UNUSED
1510 ==> final(regions).slot_owners[idx].paths_in_pt
1511 == old(regions).slot_owners[idx].paths_in_pt,
1512 (forall |i: int| #![trigger old(regions).slot_owners[i]]
1514 old(regions).contains(i)
1515 && old(regions).ref_count(i)
1516 != REF_COUNT_UNUSED
1517 ==> old(regions).ref_count(i) + 1
1518 < REF_COUNT_MAX)
1519 ==>
1520 (forall |i: int| #![trigger final(regions).slot_owners[i]]
1521 final(regions).contains(i)
1522 && final(regions).ref_count(i)
1523 != REF_COUNT_UNUSED
1524 ==> final(regions).ref_count(i) + 1
1525 < REF_COUNT_MAX),
1526 forall|idx: int| #![trigger final(regions).slot_owners[idx].ref_count()]
1527 final(regions).ref_count(idx)
1528 >= REF_COUNT_MAX
1529 ==> old(regions).ref_count(idx)
1530 == final(regions).ref_count(idx),
1531 forall|idx: int| #![trigger old(regions).slot_owners[idx].ref_count()]
1532 old(regions).ref_count(idx)
1533 >= REF_COUNT_MAX
1534 ==> final(regions).ref_count(idx)
1535 == old(regions).ref_count(idx),
1536 )]
1537 pub fn cursor<'rcu, G: InAtomicMode>(&'rcu self, guard: &'rcu G, va: &Range<Vaddr>) -> Result<
1538 (Cursor<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>),
1539 PageTableError,
1540 > {
1541 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1542 Cursor::new(self, guard, va)
1543 }}
1555
1556#[cfg(ktest)]
1579pub(super) unsafe fn page_walk<C: PageTableConfig>(root_paddr: Paddr, vaddr: Vaddr) -> Option<
1580 (Paddr, PageProperty),
1581> {
1582 use super::paddr_to_vaddr;
1583
1584 let _rcu_guard = disable_preempt();
1585
1586 let mut pt_addr = paddr_to_vaddr(root_paddr);
1587 #[verusfmt::skip]
1588 for cur_level in (1..= C::NR_LEVELS()).rev() {
1589 let offset = pte_index::<C>(vaddr, cur_level);
1590 let cur_pte = unsafe { load_pte((pt_addr as *mut C::E).add(offset), Ordering::Acquire) };
1596
1597 if !cur_pte.is_present() {
1598 return None;
1599 }
1600 if cur_pte.is_last(cur_level) {
1601 debug_assert!(cur_level <= C::HIGHEST_TRANSLATION_LEVEL);
1602 return Some(
1603 (cur_pte.paddr() + (vaddr & (page_size::<C>(cur_level) - 1)), cur_pte.prop()),
1604 );
1605 }
1606 pt_addr = paddr_to_vaddr(cur_pte.paddr());
1607 }
1608
1609 unreachable!("All present PTEs at the level 1 must be last-level PTEs");
1610}
1611
1612pub trait PageTableEntryTrait:
1616 Clone + Copy + Debug + Default + Sized + Pod + PodOnce + Send + Sync + 'static {
1617 spec fn new_absent_spec() -> Self;
1618
1619 #[verifier(when_used_as_spec(new_absent_spec))]
1623 fn new_absent() -> (res: Self)
1624 ensures
1625 valid_frame_paddr(res.paddr()),
1626 !res.is_present(),
1627 returns
1628 Self::new_absent(),
1629 ;
1630
1631 spec fn is_present_spec(&self) -> bool;
1632
1633 #[verifier::when_used_as_spec(is_present_spec)]
1639 fn is_present(&self) -> bool
1640 returns
1641 self.is_present_spec(),
1642 ;
1643
1644 spec fn new_page_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self;
1645
1646 spec fn new_page_req(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> bool;
1648
1649 #[verifier::when_used_as_spec(new_page_spec)]
1651 fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res: Self)
1652 requires
1653 paddr < MAX_PADDR,
1654 Self::new_page_req(paddr, level, prop),
1655 ensures
1656 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1657 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1658 valid_frame_paddr(res.paddr()),
1659 res.is_present(),
1660 res.is_last(level),
1661 res.prop() == prop,
1662 returns
1663 Self::new_page(paddr, level, prop),
1664 ;
1665
1666 spec fn new_pt_spec(paddr: Paddr) -> Self;
1667
1668 #[verifier::when_used_as_spec(new_pt_spec)]
1670 fn new_pt(paddr: Paddr) -> (res: Self)
1671 requires
1672 paddr < MAX_PADDR,
1673 ensures
1674 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1675 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1676 valid_frame_paddr(res.paddr()),
1677 res.is_present(),
1678 forall|level: PagingLevel| !res.is_last(level),
1679 returns
1680 Self::new_pt(paddr),
1681 ;
1682
1683 spec fn paddr_spec(&self) -> Paddr;
1689
1690 #[verifier::when_used_as_spec(paddr_spec)]
1691 fn paddr(&self) -> (res: Paddr)
1692 ensures
1693 valid_frame_paddr(res),
1694 returns
1695 self.paddr(),
1696 ;
1697
1698 spec fn prop_spec(&self) -> PageProperty;
1699
1700 #[verifier::when_used_as_spec(prop_spec)]
1701 fn prop(&self) -> PageProperty
1702 returns
1703 self.prop(),
1704 ;
1705
1706 spec fn set_prop_req(self, prop: PageProperty) -> bool;
1708
1709 fn set_prop(&mut self, prop: PageProperty)
1710 requires
1711 old(self).set_prop_req(prop),
1712 ensures
1713 !old(self).is_present() ==> *old(self) == *final(self),
1714 old(self).is_present() ==> {
1715 &&& final(self).prop() == prop
1716 &&& final(self).paddr() == old(self).paddr()
1717 &&& final(self).is_present()
1718 &&& forall|level: PagingLevel|
1719 #![trigger old(self).is_last(level)]
1720 old(self).is_last(level) ==> final(self).is_last(level)
1721 },
1722 ;
1723
1724 spec fn is_last_spec(&self, level: PagingLevel) -> bool;
1725
1726 #[verifier::when_used_as_spec(is_last_spec)]
1731 fn is_last(&self, level: PagingLevel) -> bool
1732 returns
1733 self.is_last_spec(level),
1734 ;
1735
1736 spec fn as_usize_spec(self) -> usize;
1737
1738 #[verifier::external_body]
1740 #[verifier::when_used_as_spec(as_usize_spec)]
1741 fn as_usize(self) -> usize
1742 returns
1743 self.as_usize(),
1744 {
1745 unimplemented!()
1746 }
1751
1752 #[verifier::external_body]
1754 fn from_usize(pte_raw: usize) -> Self {
1755 unimplemented!()
1756 }
1761
1762 proof fn lemma_page_table_entry_properties()
1764 ensures
1765 core::mem::size_of::<Self>() == core::mem::size_of::<usize>(),
1766 core::mem::size_of::<Self>() % core::mem::align_of::<Self>() == 0,
1767 core::mem::align_of::<Self>() > 0,
1768 valid_frame_paddr(Self::new_absent().paddr()),
1769 !Self::new_absent().is_present(),
1770 forall|level: PagingLevel|
1771 #![trigger Self::new_absent().is_last(level)]
1772 1 < level ==> !Self::new_absent().is_last(level),
1773 forall|paddr: Paddr, level: PagingLevel, prop: PageProperty|
1774 #![trigger Self::new_page(paddr, level, prop)]
1775 Self::new_page_req(paddr, level, prop) && (prop.cache is Writeback
1776 || prop.cache is Writethrough || prop.cache is Uncacheable) ==> {
1777 &&& Self::new_page(paddr, level, prop).is_present()
1778 &&& (paddr < MAX_PADDR ==> Self::new_page(paddr, level, prop).paddr() == paddr
1779 & !((PAGE_SIZE - 1) as usize))
1780 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_page(
1781 paddr,
1782 level,
1783 prop,
1784 ).paddr() == paddr)
1785 &&& Self::new_page(paddr, level, prop).prop() == prop
1786 &&& Self::new_page(paddr, level, prop).is_last(level)
1787 },
1788 forall|paddr: Paddr|
1789 #![trigger Self::new_pt(paddr)]
1790 {
1791 &&& Self::new_pt(paddr).is_present()
1792 &&& (paddr < MAX_PADDR ==> Self::new_pt(paddr).paddr() == paddr & !((PAGE_SIZE
1793 - 1) as usize))
1794 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_pt(paddr).paddr()
1795 == paddr)
1796 &&& forall|level: PagingLevel| !Self::new_pt(paddr).is_last(level)
1797 },
1798 ;
1799
1800 proof fn lemma_paddr_is_page_aligned(self)
1801 ensures
1802 self.paddr() % PAGE_SIZE == 0,
1803 ;
1804}
1805
1806#[verifier::external_body]
1821#[verus_spec(
1822 with Tracked(perm): Tracked<&vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1823 requires
1824 perm.is_init(ptr.index as int),
1825 perm.addr() == ptr.addr(),
1826 0 <= ptr.index < NR_ENTRIES,
1827 returns
1828 perm.value()[ptr.index as int],
1829)]
1830pub unsafe fn load_pte<E: PageTableEntryTrait>(
1831 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1832 ordering: Ordering,
1833) -> (pte: E) {
1834 unimplemented!()
1835}
1836
1837#[verifier::external_body]
1850#[verus_spec(
1851 with Tracked(perm): Tracked<&mut vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1852 requires
1853 old(perm).addr() == ptr.addr(),
1854 0 <= ptr.index < NR_ENTRIES,
1855 old(perm).is_init_all(),
1856 ensures
1857 final(perm).wf(),
1858 final(perm).value()[ptr.index as int] == new_val,
1859 final(perm).value() == old(perm).value().update(ptr.index as int, new_val),
1860 final(perm).addr() == old(perm).addr(),
1861 final(perm).is_init_all(),
1862)]
1863pub unsafe fn store_pte<E: PageTableEntryTrait>(
1864 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1865 new_val: E,
1866 ordering: Ordering,
1867);
1868
1869}