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::*,
11 vaddr_range_proofs::{lemma_leading_bits_properties, lemma_page_table_managed_bounds},
12 *,
13 },
14 },
15 task::InAtomicMode,
16};
17
18use super::{
19 Paddr, PagingConstsTrait, PagingLevel, PodOnce, Vaddr,
20 kspace::KernelPtConfig,
21 nr_subpage_per_huge,
22 page_prop::{CachePolicy, PageProperty},
23 page_size,
24 vm_space::UserPtConfig,
25};
26use crate::mm::frame::MetaSlot;
27use crate::mm::frame::meta::{
28 REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED, mapping::frame_to_meta,
29};
30use crate::mm::kspace::kvirt_area::disable_preempt;
31use crate::{
32 Pod,
34 arch::mm::{PageTableEntry, PagingConsts},
35};
36use core::{
37 fmt::Debug,
38 intrinsics::transmute_unchecked,
39 ops::{Range, RangeInclusive},
40 sync::atomic::Ordering,
41};
42
43mod node;
44pub use node::*;
45mod cursor;
46
47pub(crate) use cursor::*;
48
49#[cfg(ktest)]
50mod test;
51
52verus! {
55
56#[derive(Clone, Copy, PartialEq, Eq, Debug)]
57pub enum PageTableError {
58 InvalidVaddrRange(Vaddr, Vaddr),
60 InvalidVaddr(Vaddr),
62 UnalignedVaddr,
64}
65
66pub trait RCClone: Sized {
67 spec fn clone_requires(self, perm: MetaRegionOwners) -> bool;
68
69 spec fn clone_ensures(
70 self,
71 old_perm: MetaRegionOwners,
72 new_perm: MetaRegionOwners,
73 res: Self,
74 ) -> bool;
75
76 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self)
77 requires
78 self.clone_requires(*old(perm)),
79 ensures
80 self.clone_ensures(*old(perm), *final(perm), res),
81 final(perm).inv(),
82 final(perm).slots == old(perm).slots,
83 final(perm).slot_owners.dom() == old(perm).slot_owners.dom(),
84 ;
85}
86
87pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
105 spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize>;
106
107 #[verifier::when_used_as_spec(TOP_LEVEL_INDEX_RANGE_spec)]
114 fn TOP_LEVEL_INDEX_RANGE() -> Range<usize>
115 returns
116 Self::TOP_LEVEL_INDEX_RANGE(),
117 ;
118
119 open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
120 true
121 }
122
123 #[verifier::when_used_as_spec(TOP_LEVEL_CAN_UNMAP_spec)]
129 fn TOP_LEVEL_CAN_UNMAP() -> bool
130 returns
131 Self::TOP_LEVEL_CAN_UNMAP(),
132 ;
133
134 type E: PageTableEntryTrait;
136
137 type C: PagingConstsTrait;
139
140 type Item: RCClone;
153
154 type Perm;
157
158 spec fn item_into_raw_spec(item: Self::Item) -> (
159 Paddr,
160 PagingLevel,
161 PageProperty,
162 Tracked<Option<Self::Perm>>,
163 );
164
165 #[verifier::when_used_as_spec(item_into_raw_spec)]
171 fn item_into_raw(item: Self::Item) -> ((paddr, level, prop, perm): (
172 Paddr,
173 PagingLevel,
174 PageProperty,
175 Tracked<Option<Self::Perm>>,
176 ))
177 requires
178 Self::item_well_formed(item),
179 ensures
180 Self::raw_item_well_formed((paddr, level, prop, perm)),
181 1 <= level <= NR_LEVELS,
182 valid_frame_paddr(paddr),
183 paddr % page_size::<PagingConsts>(level) == 0,
184 paddr + page_size::<PagingConsts>(level) <= MAX_PADDR,
185 Self::E::new_page_req(paddr, level, prop),
186 returns
187 Self::item_into_raw(item),
188 ;
189
190 spec fn item_from_raw_spec(
191 paddr: Paddr,
192 level: PagingLevel,
193 prop: PageProperty,
194 perm: Tracked<Option<Self::Perm>>,
195 ) -> Self::Item;
196
197 #[verifier::when_used_as_spec(item_from_raw_spec)]
222 unsafe fn item_from_raw(
223 paddr: Paddr,
224 level: PagingLevel,
225 prop: PageProperty,
226 perm: Tracked<Option<Self::Perm>>,
227 ) -> (res: Self::Item)
228 requires
229 Self::raw_item_well_formed((paddr, level, prop, perm)),
230 ensures
231 Self::item_well_formed(res),
232 returns
233 Self::item_from_raw(paddr, level, prop, perm),
234 ;
235
236 spec fn item_well_formed(item: Self::Item) -> bool;
238
239 spec fn raw_item_well_formed(
241 item: (Paddr, PagingLevel, PageProperty, Tracked<Option<Self::Perm>>),
242 ) -> bool;
243
244 spec fn perm_well_formed_with_region(
246 pa: Paddr,
247 perm: Tracked<Option<Self::Perm>>,
248 regions: MetaRegionOwners,
249 ) -> bool;
250
251 proof fn lemma_none_perm_well_formed(pa: Paddr, regions: MetaRegionOwners)
254 ensures
255 Self::perm_well_formed_with_region(pa, Tracked(None), regions),
256 ;
257
258 proof fn lemma_perm_well_formed_with_region_preserved(
259 pa: Paddr,
260 perm: Tracked<Option<Self::Perm>>,
261 old_regions: MetaRegionOwners,
262 new_regions: MetaRegionOwners,
263 )
264 requires
265 Self::perm_well_formed_with_region(pa, perm, old_regions),
266 old_regions.slots[frame_to_index(pa)] == new_regions.slots[frame_to_index(pa)],
267 old_regions.slot_owners[frame_to_index(pa)].metadata_perm.id()
268 == new_regions.slot_owners[frame_to_index(pa)].metadata_perm.id(),
269 ensures
270 Self::perm_well_formed_with_region(pa, perm, new_regions),
271 ;
272
273 proof fn lemma_raw_item_well_formed_preserved(
275 pa: Paddr,
276 level: PagingLevel,
277 old_prop: PageProperty,
278 new_prop: PageProperty,
279 perm: Tracked<Option<Self::Perm>>,
280 )
281 requires
282 valid_frame_paddr(pa),
283 Self::raw_item_well_formed((pa, level, old_prop, perm)),
284 (Self::item_into_raw(Self::item_from_raw(pa, level, new_prop, perm)).3@ is Some) == (
285 perm@ is Some),
286 ensures
287 Self::raw_item_well_formed((pa, level, new_prop, perm)),
288 ;
289
290 proof fn lemma_raw_item_well_formed_split(
292 pa: Paddr,
293 level: PagingLevel,
294 prop: PageProperty,
295 child_pa: Paddr,
296 child_idx: usize,
297 perm: Tracked<Option<Self::Perm>>,
298 )
299 requires
300 valid_frame_paddr(pa),
301 Self::raw_item_well_formed((pa, level, prop, perm)),
302 Self::E::new_page_req(pa, level, prop),
303 level > 1,
304 child_idx < NR_ENTRIES,
305 child_pa == pa + child_idx * page_size::<PagingConsts>((level - 1) as PagingLevel),
306 ensures
307 Self::raw_item_well_formed((child_pa, (level - 1) as PagingLevel, prop, perm)),
308 Self::E::new_page_req(child_pa, (level - 1) as PagingLevel, prop),
309 ;
310
311 proof fn lemma_huge_raw_item_untracked(
314 pa: Paddr,
315 level: PagingLevel,
316 prop: PageProperty,
317 perm: Tracked<Option<Self::Perm>>,
318 )
319 requires
320 Self::raw_item_well_formed((pa, level, prop, perm)),
321 level > 1,
322 ensures
323 perm@ is None,
324 ;
325
326 proof fn lemma_item_from_raw_well_formed(
328 pa: Paddr,
329 level: PagingLevel,
330 prop: PageProperty,
331 perm: Tracked<Option<Self::Perm>>,
332 )
333 requires
334 valid_frame_paddr(pa),
335 Self::raw_item_well_formed((pa, level, prop, perm)),
336 ensures
337 Self::item_well_formed(Self::item_from_raw(pa, level, prop, perm)),
338 ;
339
340 proof fn lemma_item_into_raw_roundtrip(
342 pa: Paddr,
343 level: PagingLevel,
344 prop: PageProperty,
345 perm: Tracked<Option<Self::Perm>>,
346 )
347 requires
348 valid_frame_paddr(pa),
349 Self::raw_item_well_formed((pa, level, prop, perm)),
350 ensures
351 Self::item_into_raw(Self::item_from_raw(pa, level, prop, perm)) == (
352 pa,
353 level,
354 prop,
355 perm,
356 ),
357 ;
358
359 proof fn lemma_item_from_raw_roundtrip(
361 item: Self::Item,
362 pa: Paddr,
363 level: PagingLevel,
364 prop: PageProperty,
365 perm: Tracked<Option<Self::Perm>>,
366 )
367 requires
368 valid_frame_paddr(pa),
369 Self::item_well_formed(item),
370 Self::item_into_raw(item) == (pa, level, prop, perm),
371 ensures
372 Self::item_from_raw(pa, level, prop, perm) == item,
373 ;
374
375 proof fn lemma_clone_ensures_concrete(
378 item: Self::Item,
379 pa: Paddr,
380 old_regions: MetaRegionOwners,
381 new_regions: MetaRegionOwners,
382 res: Self::Item,
383 )
384 requires
385 item.clone_ensures(old_regions, new_regions, res),
386 Self::item_into_raw(item).0 == pa,
387 new_regions.inv(),
388 new_regions.slots =~= old_regions.slots,
389 new_regions.slot_owners.dom() =~= old_regions.slot_owners.dom(),
390 ensures
391 Self::item_into_raw(res).0 == Self::item_into_raw(item).0,
392 Self::item_into_raw(res).1 == Self::item_into_raw(item).1,
393 Self::item_into_raw(res).2 == Self::item_into_raw(item).2,
394 (Self::item_into_raw(res).3@ is Some) == (Self::item_into_raw(item).3@ is Some),
395 Self::item_into_raw(item).3@ is Some ==> {
396 old_regions.inc_frame_reference_region_spec(pa, new_regions)
397 },
398 Self::item_into_raw(item).3@ is None ==> new_regions == old_regions,
399 ;
400
401 proof fn lemma_clone_requires_concrete(
402 item: Self::Item,
403 pa: Paddr,
404 level: PagingLevel,
405 prop: PageProperty,
406 regions: MetaRegionOwners,
407 )
408 requires
409 regions.inv(),
410 Self::item_from_raw(pa, level, prop, Self::item_into_raw(item).3) == item,
411 Self::raw_item_well_formed((pa, level, prop, Self::item_into_raw(item).3)),
412 Self::perm_well_formed_with_region(pa, Self::item_into_raw(item).3, regions),
413 valid_frame_paddr(pa),
414 regions.contains(frame_to_index(pa)),
415 Self::item_into_raw(item).3@ is Some ==> {
416 &&& 0 < regions.slot_owner(pa).ref_count()
417 &&& regions.slot_owner(pa).ref_count() != REF_COUNT_UNUSED
418 &&& regions.slot_owner(pa).ref_count() >= REF_COUNT_MAX ==> may_panic()
419 },
420 ensures
421 item.clone_requires(regions),
422 ;
423
424 proof fn lemma_page_table_config_constant_requirements()
429 ensures
430 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
431 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end
432 <= nr_subpage_per_huge::<Self::C>(),
433 ;
434
435 proof fn lemma_page_table_config_constant_properties()
439 ensures
440 Self::TOP_LEVEL_INDEX_RANGE().end <= pow2(
443 top_level_index_width_spec::<Self::C>() as nat,
444 ),
445 Self::TOP_LEVEL_INDEX_RANGE().end * pow2(
446 pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
447 ) <= usize::MAX,
448 core::mem::size_of::<Self::E>() == Self::C::PTE_SIZE(),
451 Self::TOP_LEVEL_INDEX_RANGE().start < Self::TOP_LEVEL_INDEX_RANGE().end
452 <= nr_subpage_per_huge::<Self::C>(),
453 {
454 use vstd::arithmetic::mul::{
455 lemma_mul_inequality,
456 lemma_mul_inequality_converse,
457 lemma_mul_is_commutative,
458 };
459
460 Self::C::lemma_paging_consts_properties();
461 Self::lemma_page_table_config_constant_requirements();
462 let level = Self::C::NR_LEVELS();
463 let offset = pte_index_bit_offset_spec::<Self::C>(level);
464 let coverage = nr_page_table_coverage_bits_spec::<Self::C>();
465 let width = Self::C::ADDRESS_WIDTH();
466 lemma_page_size_is_pow2_pte_index_bit_offset::<Self::C>(level);
467 lemma_page_size_is_pow2_pte_index_bit_offset::<Self::C>((level + 1) as PagingLevel);
468 lemma_page_size_next::<Self::C>(level);
469 if coverage < width {
470 lemma_pow2_strictly_increases(coverage as nat, width as nat);
471 }
472 lemma_pow2_strictly_increases(width as nat, usize::BITS as nat);
473 lemma_pow2_adds(top_level_index_width_spec::<Self::C>() as nat, offset as nat);
474 let size = page_size::<Self::C>(level) as int;
475 let fanout = nr_subpage_per_huge::<Self::C>() as int;
476 let end = Self::TOP_LEVEL_INDEX_RANGE().end as int;
477 lemma_mul_is_commutative(size, fanout);
478 lemma_mul_inequality(end, fanout, size);
479 lemma_mul_inequality_converse(
480 end,
481 pow2(top_level_index_width_spec::<Self::C>() as nat) as int,
482 size,
483 );
484 lemma2_to64();
485 }
486}
487
488impl<C: PageTableConfig> PagingConstsTrait for C {
491 open spec fn BASE_PAGE_SIZE_spec() -> usize {
492 C::C::BASE_PAGE_SIZE_spec()
493 }
494
495 fn BASE_PAGE_SIZE() -> usize {
496 C::C::BASE_PAGE_SIZE()
497 }
498
499 open spec fn NR_LEVELS_spec() -> PagingLevel {
500 C::C::NR_LEVELS_spec()
501 }
502
503 fn NR_LEVELS() -> PagingLevel {
504 proof {
505 assert(Self::NR_LEVELS() == C::C::NR_LEVELS());
506 }
507 C::C::NR_LEVELS()
508 }
509
510 open spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel {
511 C::C::HIGHEST_TRANSLATION_LEVEL_spec()
512 }
513
514 fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel {
515 C::C::HIGHEST_TRANSLATION_LEVEL()
516 }
517
518 open spec fn PTE_SIZE_spec() -> usize {
519 C::C::PTE_SIZE_spec()
520 }
521
522 fn PTE_SIZE() -> usize {
523 C::C::PTE_SIZE()
524 }
525
526 open spec fn ADDRESS_WIDTH_spec() -> usize {
527 C::C::ADDRESS_WIDTH_spec()
528 }
529
530 fn ADDRESS_WIDTH() -> usize {
531 C::C::ADDRESS_WIDTH()
532 }
533
534 open spec fn VA_SIGN_EXT_spec() -> bool {
535 C::C::VA_SIGN_EXT_spec()
536 }
537
538 fn VA_SIGN_EXT() -> bool {
539 C::C::VA_SIGN_EXT()
540 }
541
542 proof fn lemma_paging_consts_requirements() {
543 C::C::lemma_paging_consts_requirements();
544 }
545}
546
547#[verifier::external_body]
572pub fn largest_pages<C: PageTableConfig>(
573 mut va: Vaddr,
574 mut pa: Paddr,
575 mut len: usize,
576) -> impl Iterator<Item = (Paddr, PagingLevel)> {
577 assert_eq!(va % C::BASE_PAGE_SIZE(), 0);
578 assert_eq!(pa % C::BASE_PAGE_SIZE(), 0);
579 assert_eq!(len % C::BASE_PAGE_SIZE(), 0);
580 assert!(is_valid_range::<C>(&(va..(va + len))));
581
582 core::iter::from_fn(
583 move ||
584 {
585 if len == 0 {
586 return None;
587 }
588 let mut level = C::HIGHEST_TRANSLATION_LEVEL();
589 while page_size::<C>(level) > len || va % page_size::<C>(level) != 0 || pa
590 % page_size::<C>(level) != 0 {
591 level -= 1;
592 }
593
594 let item_start = pa;
595 va += page_size::<C>(level);
596 pa += page_size::<C>(level);
597 len -= page_size::<C>(level);
598
599 Some((item_start, level))
600 },
601 )
602}
603
604fn top_level_index_width<C: PageTableConfig>() -> (ret: usize)
606 returns
607 top_level_index_width_spec::<C>(),
608{
609 proof {
610 C::lemma_paging_consts_properties();
611 C::lemma_page_table_config_constant_properties();
612 }
613
614 C::ADDRESS_WIDTH() - pte_index_bit_offset::<C>(C::NR_LEVELS())
615}
616
617fn pt_va_range_start<C: PageTableConfig>() -> (ret: Vaddr)
618 ensures
619 ret == page_table_managed_start_spec::<C>() - page_table_coverage_start_spec::<C>(),
620{
621 proof {
622 C::lemma_paging_consts_properties();
623 lemma_page_table_managed_bounds::<C>();
624 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(C::NR_LEVELS());
625 let ghost idx_start = C::TOP_LEVEL_INDEX_RANGE().start;
626 let ghost offset = pte_index_bit_offset_spec::<C>(C::NR_LEVELS());
627 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_start_shift_facts::<C>(
628 idx_start,
629 offset,
630 );
631 vstd::bits::lemma_usize_shl_is_mul(idx_start, offset);
632 }
633
634 C::TOP_LEVEL_INDEX_RANGE().start << pte_index_bit_offset::<C>(C::NR_LEVELS())
635}
636
637fn pt_va_range_end<C: PageTableConfig>() -> (ret: Vaddr)
640 ensures
641 ret == page_table_managed_end_spec::<C>() - page_table_coverage_start_spec::<C>() - 1,
642{
643 let idx_end = C::TOP_LEVEL_INDEX_RANGE().end;
644 proof {
645 C::lemma_paging_consts_properties();
646 }
647 let offset = pte_index_bit_offset::<C>(C::NR_LEVELS());
648
649 proof {
650 crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_end_shift_facts::<C>(
651 idx_end,
652 offset,
653 );
654 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(C::NR_LEVELS());
655 vstd::layout::unsigned_int_max_values();
656 vstd::bits::lemma_usize_shl_is_mul(idx_end, offset);
657 }
658
659 let shifted = idx_end << offset;
660 let ret = shifted.wrapping_sub(1);
661
662 ret
663}
664
665fn sign_bit_of_va<C: PageTableConfig>(va: Vaddr) -> (ret: bool)
666 ensures
667 ret == ((va as int / pow2((C::ADDRESS_WIDTH() - 1) as nat) as int) % 2 == 1),
668{
669 proof {
670 C::lemma_paging_consts_properties();
671 C::lemma_page_table_config_constant_properties();
672 vstd::bits::lemma_usize_shr_is_div(va, (C::ADDRESS_WIDTH() - 1) as usize);
673 vstd::bits::lemma_usize_low_bits_mask_is_mod(va >> (C::ADDRESS_WIDTH() - 1), 1);
674 vstd::bits::lemma_low_bits_mask_values();
675 vstd::arithmetic::power2::lemma2_to64();
676 }
677 (va >> (C::ADDRESS_WIDTH() - 1)) & 1 != 0
678}
679
680fn apply_sign_ext<C: PageTableConfig>(va: Vaddr) -> (ret: Vaddr)
687 requires
688 va < pow2(C::ADDRESS_WIDTH() as nat),
689 C::ADDRESS_WIDTH() < usize::BITS,
690 page_table_coverage_start_spec::<C>() == 0x1_0000_0000_0000_0000int - pow2(
691 C::ADDRESS_WIDTH() as nat,
692 ),
693 ensures
694 ret == va + page_table_coverage_start_spec::<C>(),
695{
696 let address_width = C::ADDRESS_WIDTH();
697 let low_bit = 1usize << address_width;
698 proof {
699 vstd::layout::unsigned_int_max_values();
700 vstd::bits::lemma_usize_pow2_no_overflow(address_width as nat);
701 vstd::bits::lemma_usize_shl_is_mul(1usize, address_width);
702 }
703 let low_mask = low_bit - 1;
704 let sign_ext_mask = !0 ^ low_mask;
705 let ret = va | sign_ext_mask;
706 proof {
707 assert(!0usize == 0xffff_ffff_ffff_ffffusize) by (compute_only);
708 assert(sign_ext_mask == usize::MAX - low_mask) by (bit_vector)
709 requires
710 sign_ext_mask == (!0usize ^ low_mask),
711 !0usize == 0xffff_ffff_ffff_ffffusize,
712 usize::MAX == 0xffff_ffff_ffff_ffffusize,
713 ;
714 assert(pow2(64) == 0x1_0000_0000_0000_0000nat) by {
715 vstd::arithmetic::power2::lemma2_to64();
716 };
717 assert(sign_ext_mask == 0x1_0000_0000_0000_0000int - pow2(address_width as nat));
718 assert(sign_ext_mask == page_table_coverage_start_spec::<C>());
719
720 assert((va & sign_ext_mask) == 0usize) by (bit_vector)
721 requires
722 address_width < usize::BITS,
723 low_bit == 1usize << address_width,
724 low_mask == low_bit - 1,
725 sign_ext_mask == !0usize ^ low_mask,
726 va < low_bit,
727 ;
728 assert(ret == va + sign_ext_mask) by (bit_vector)
729 requires
730 ret == va | sign_ext_mask,
731 (va & sign_ext_mask) == 0usize,
732 ;
733 }
734 ret
735}
736
737#[verusfmt::skip]
744fn vaddr_range<C: PageTableConfig>() -> (ret: RangeInclusive<Vaddr>)
745 ensures
746 ret@ == vaddr_range_spec::<C>(),
747{
748 let mut start = pt_va_range_start::<C>();
749 let mut end = pt_va_range_end::<C>();
750
751 proof {
752 C::lemma_paging_consts_properties();
753 C::lemma_page_table_config_constant_properties();
754 lemma_leading_bits_properties::<C>();
755 lemma_page_table_managed_bounds::<C>();
756 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(C::NR_LEVELS());
757 lemma2_to64();
758 crate::specs::mm::page_table::vaddr_range_proofs::lemma_idx_times_pow2_bound::<C>(
759 start,
760 end,
761 );
762 }
763
764 if C::VA_SIGN_EXT() && sign_bit_of_va::<C>(pt_va_range_start::<C>()) {
765 start = apply_sign_ext::<C>(start);
766 end = apply_sign_ext::<C>(end);
767 }
768 start..=end
769}
770
771fn is_valid_range<C: PageTableConfig>(r: &Range<Vaddr>) -> bool
773 returns
774 is_valid_range_spec::<C>(*r),
775{
776 proof {
777 lemma_page_table_managed_bounds::<C>();
778 }
779 let va_range = vaddr_range::<C>();
780 r.start < r.end && (*va_range.start() <= r.start && r.end - 1 <= *va_range.end())
781}
782
783fn nr_pte_index_bits<C: PagingConstsTrait>() -> usize
786 returns
787 nr_pte_index_bits_spec::<C>(),
788{
789 proof {
790 C::lemma_paging_consts_properties();
791 }
792 nr_subpage_per_huge::<C>().ilog2() as usize
793}
794
795fn pte_index<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel) -> (res: usize)
797 requires
798 1 <= level <= C::NR_LEVELS(),
799 returns
800 pte_index_spec::<C>(va, level),
801{
802 proof {
803 C::lemma_paging_consts_properties();
804 }
805 (va >> pte_index_bit_offset::<C>(level)) & (nr_subpage_per_huge::<C>() - 1)
806}
807
808fn pte_index_bit_offset<C: PagingConstsTrait>(level: PagingLevel) -> usize
814 requires
815 1 <= level <= C::NR_LEVELS(),
816 ensures
817 pte_index_bit_offset_spec::<C>(level) < usize::BITS,
818 returns
819 pte_index_bit_offset_spec::<C>(level),
820{
821 proof {
822 C::lemma_paging_consts_properties();
823 assert(C::BASE_PAGE_SIZE().ilog2() + nr_pte_index_bits_spec::<C>() * (level - 1)
824 < usize::BITS) by (nonlinear_arith)
825 requires
826 level <= C::NR_LEVELS(),
827 C::BASE_PAGE_SIZE().ilog2() + nr_pte_index_bits_spec::<C>() * C::NR_LEVELS()
828 <= C::ADDRESS_WIDTH(),
829 C::ADDRESS_WIDTH() < usize::BITS,
830 ;
831 }
832 C::BASE_PAGE_SIZE().ilog2() as usize + nr_pte_index_bits::<C>() * (level as usize - 1)
833}
834
835pub struct PageTable<C: PageTableConfig> {
838 pub root: PageTableNode<C>,
839}
840
841impl PageTable<KernelPtConfig> {
853 #[verifier::external_body]
855 pub(crate) fn new_kernel_page_table() -> Self {
856 unimplemented!()}
872
873 pub open spec fn create_user_pt_panic_condition(root_owner: NodeOwner<KernelPtConfig>) -> bool {
877 exists|i: usize|
878 #![trigger root_owner.children_perm.value()[i as int]]
879 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
880 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
881 let pte = root_owner.children_perm.value()[i as int];
882 ||| !pte.is_present()
883 ||| pte.is_last(root_owner.level())
884 }
885 }
886
887 #[verus_spec(r =>
892 with Tracked(kernel_owner): Tracked<&PageTableOwner<KernelPtConfig>>,
893 Tracked(regions): Tracked<&mut MetaRegionOwners>,
894 Tracked(guards): Tracked<&mut Guards>,
895 requires
896 kernel_owner.inv(),
897 old(regions).inv(),
898 kernel_owner.0.value().is_node(),
899 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
900 self.root.slot_vaddr() == kernel_owner.0.value().node().slot_vaddr(),
901 self.relates_owner(*kernel_owner, *old(regions)),
902 kernel_owner.0.value().metaregion_sound(*old(regions)),
903 kernel_owner.metaregion_sound(*old(regions)),
904 old(guards).unlocked(kernel_owner.0.value().node().slot_vaddr()),
906 ensures
907 final(regions).inv(),
908 )]
909 pub(in crate::mm) fn create_user_page_table<'rcu, G: InAtomicMode + 'static>(
910 &'static self,
911 ) -> PageTable<UserPtConfig> {
912 let preempt_guard: &'rcu G = disable_preempt::<G>();
913
914 proof_decl! {
915 let tracked mut new_pt_owner: Option<PageTableOwner<UserPtConfig>> = None;
916 }
917 let ghost regions_before_alloc = *regions;
918 let new_pt: PageTable<UserPtConfig> = (
919 #[verus_spec(with Tracked(&mut new_pt_owner), Tracked(regions), Tracked(guards))]
920 PageTable::empty_with_owner());
921 let new_root = new_pt.root;
922 let ghost new_idx_g: int = frame_to_index(
924 new_pt_owner@.unwrap().0.value().meta_slot_paddr().unwrap(),
925 );
926 proof {
927 let kern_idx = frame_to_index(kernel_owner.0.value().meta_slot_paddr().unwrap());
928 let new_idx = new_idx_g;
929 EntryOwner::<KernelPtConfig>::lemma_active_entry_not_in_free_pool(
930 kernel_owner.0.value(),
931 regions_before_alloc,
932 new_idx,
933 );
934 }
935
936 proof_decl! {
937 let tracked root_owner: &NodeOwner<KernelPtConfig>
938 = kernel_owner.0.tracked_borrow_value().tracked_borrow_node();
939 let tracked mut new_pt_owner_val: PageTableOwner<UserPtConfig>
940 = new_pt_owner.tracked_take();
941 let tracked mut new_node_owner: NodeOwner<UserPtConfig> = {
942 let tracked new_pt_value = new_pt_owner_val.0.tracked_borrow_mut_value();
943 new_pt_value.tracked_take_node()
944 };
945 let tracked mut entry_owner: &EntryOwner<KernelPtConfig>;
946 }
947
948 proof {
951 assert(kernel_owner.0.value().is_node());
952 assert(kernel_owner.0.value().metaregion_sound(*regions));
953 }
954 let mut root_node = {
955 #[verus_spec(with Tracked(&root_owner.frame_permission), Tracked(&*regions))]
960 let root_ref = self.root.borrow_with_permission();
961 #[verus_spec(with Tracked(root_owner), Tracked(guards))]
962 root_ref.lock(preempt_guard)
963 };
964 let mut new_node: PageTableGuard<'rcu, UserPtConfig> = {
965 #[verus_spec(with Tracked(&new_node_owner.frame_permission), Tracked(&*regions))]
969 let new_ref = new_root.borrow_with_permission();
970 #[verus_spec(with Tracked(&new_node_owner), Tracked(guards))]
971 new_ref.lock(preempt_guard)
972 };
973 for i in KernelPtConfig::TOP_LEVEL_INDEX_RANGE()
974 invariant
975 kernel_owner.inv(),
976 kernel_owner.0.value().is_node(),
977 regions.inv(),
978 !Self::create_user_pt_panic_condition(kernel_owner.0.value().node()),
979 *root_owner == kernel_owner.0.value().node(),
981 root_owner.relate_guard(root_node),
982 kernel_owner.metaregion_sound(*regions),
984 new_node_owner.inv(),
986 new_node_owner.relate_guard(new_node),
987 regions.contains(new_node_owner.slot_index),
988 {
989 proof {
990 let kern_node = kernel_owner.0.value().node();
991 assert forall|j: usize|
992 #![trigger kern_node.children_perm.value()[j as int]]
993 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
994 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end implies {
995 let pte = kern_node.children_perm.value()[j as int];
996 pte.is_present() && !pte.is_last(kern_node.level())
997 } by {
998 let pte = kern_node.children_perm.value()[j as int];
999 if !pte.is_present() || pte.is_last(kern_node.level()) {
1000 assert(Self::create_user_pt_panic_condition(kern_node));
1001 }
1002 }
1003
1004 lemma_vaddr_range_spec_kernel();
1005 kernel_owner.pt_inv_unroll(i as int);
1006 let tracked child_subtree: &OwnerSubtree<KernelPtConfig> =
1007 kernel_owner.0.tracked_borrow_child(i as int);
1008 entry_owner = child_subtree.tracked_borrow_value();
1009 let kern_node = kernel_owner.0.value().node();
1010 assert(entry_owner.match_pte(
1011 kern_node.children_perm.value()[i as int],
1012 entry_owner.parent_level,
1013 ));
1014 assert(entry_owner.parent_level == kern_node.level());
1015 assert(child_subtree.inv());
1016 assert(entry_owner.inv());
1017 assert(root_owner.relate_guard(root_node));
1018
1019 kernel_owner.0.lemma_subtree_satisfies_unroll_once(
1020 kernel_owner.0.value().path,
1021 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1022 i as int,
1023 );
1024 assert(child_subtree.subtree_satisfies(
1025 kernel_owner.0.value().path.push_tail(i as int),
1026 PageTableOwner::<KernelPtConfig>::metaregion_sound_pred(*regions),
1027 ));
1028 assert(entry_owner.metaregion_sound(*regions));
1029 }
1030
1031 #[verus_spec(with Tracked(root_owner), Tracked(entry_owner), Tracked(&*regions))]
1032 let root_entry = root_node.entry(i);
1033 let ghost pre_to_ref_regions: MetaRegionOwners = *regions;
1034 #[verus_spec(with Tracked(entry_owner), Tracked(root_owner), Tracked(regions))]
1035 let child = root_entry.to_ref();
1036
1037 proof {
1038 let kern_node = kernel_owner.0.value().node();
1039 let pte = kern_node.children_perm.value()[i as int];
1040
1041 assert(pte.is_present() && !pte.is_last(kern_node.level())) by {
1042 if !pte.is_present() || pte.is_last(kern_node.level()) {
1043 assert(KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= i
1044 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end);
1045 assert(exists|j: usize|
1046 KernelPtConfig::TOP_LEVEL_INDEX_RANGE().start <= j
1047 < KernelPtConfig::TOP_LEVEL_INDEX_RANGE().end && {
1048 let p = #[trigger] kern_node.children_perm.value()[j as int];
1049 ||| !p.is_present()
1050 ||| p.is_last(kern_node.level())
1051 });
1052 assert(Self::create_user_pt_panic_condition(kern_node));
1053 }
1054 }
1055 kernel_owner.lemma_metaregion_sound_preserved_slot_owners_eq(
1056 pre_to_ref_regions,
1057 *regions,
1058 );
1059 }
1060 let ChildRef::PageTable(pt) = child else {
1061 panic!("The kernel page table doesn't contain shared nodes");
1062 };
1063
1064 let pt_addr = pt.start_paddr();
1065 let pte = PageTableEntry::new_pt(pt_addr);
1066
1067 proof {
1068 assert(regions.contains(new_node_owner.slot_index));
1069 }
1070 unsafe {
1071 #[verus_spec(with Tracked(&mut new_node_owner), Tracked(&*regions))]
1072 new_node.write_pte(i, pte)
1073 };
1074 }
1075
1076 PageTable::<UserPtConfig> { root: new_root }
1077 }}
1103
1104#[verus_verify]
1105impl<C: PageTableConfig> PageTable<C> {
1106 pub open spec fn relates_owner(
1108 &self,
1109 owner: PageTableOwner<C>,
1110 regions: MetaRegionOwners,
1111 ) -> bool {
1112 &&& owner.inv()
1113 &&& self.root.slot_vaddr() == owner.0.value().node().slot_vaddr()
1114 &&& self.root.external_meta_wf(owner.0.value().node().frame_permission.resource(), ())
1115 &&& self.root.tracked_slot_perm@ == regions.slots[owner.0.value().node().slot_index]
1116 &&& owner.0.value().node().level() == NR_LEVELS
1117 &&& owner.0.value().path == vstd_extra::ghost_tree::TreePath::<NR_ENTRIES>::new(
1118 Seq::empty(),
1119 )
1120 &&& owner.metaregion_sound(regions)
1121 }
1122
1123 #[verifier::external_body]
1127 pub fn empty() -> Self {
1128 unimplemented!()
1129 }
1130
1131 #[verifier::external_body]
1133 #[verus_spec(r =>
1134 with Tracked(owner): Tracked<&mut Option<PageTableOwner<C>>>,
1135 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1136 Tracked(guards): Tracked<&mut Guards>,
1137 requires
1138 old(regions).inv(),
1139 ensures
1140 final(owner)@ is Some,
1141 final(owner)@->0.inv(),
1142 (final(owner)@->0).0.value().is_node(),
1143 r.root.slot_vaddr() == (final(owner)@->0).0.value().node().slot_vaddr(),
1144 (final(owner)@->0).0.value().metaregion_sound(*final(regions)),
1145 r.relates_owner(final(owner)@->0, *final(regions)),
1146 final(regions).inv(),
1147 final(guards).unlocked((final(owner)@->0).0.value().node().slot_vaddr()),
1148 final(guards).guards == old(guards).guards,
1151 old(regions).contains(
1152 frame_to_index(
1153 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1154 final(regions).contains(
1155 frame_to_index(
1156 (final(owner)@->0).0.value().meta_slot_paddr()->0)),
1157 MetaSlot::claim_unused_slot_region_spec(
1158 (final(owner)@->0).0.value().meta_slot_paddr()->0,
1159 false, *old(regions), *final(regions)),
1160 forall |kt: PageTableOwner<KernelPtConfig>|
1164 #![trigger kt.metaregion_sound(*final(regions))]
1165 kt.inv() && kt.metaregion_sound(*old(regions))
1166 ==> kt.metaregion_sound(*final(regions)),
1167 forall |kt: PageTableOwner<KernelPtConfig>|
1168 #![trigger kt.metaregion_sound(*old(regions))]
1169 kt.inv() && kt.metaregion_sound(*old(regions)) ==>
1170 kt.0.subtree_satisfies(
1171 kt.0.value().path,
1172 |e: EntryOwner<KernelPtConfig>,
1173 p: vstd_extra::ghost_tree::TreePath<NR_ENTRIES>|
1174 e.is_node() || (e.is_frame() && e.frame_is_tracked()) ==>
1175 frame_to_index(e.meta_slot_paddr()->0) !=
1176 frame_to_index((final(owner)@->0).0.value().meta_slot_paddr()->0),
1177 ),
1178 )]
1179 pub fn empty_with_owner<'rcu>() -> Self {
1180 unimplemented!()
1181 }
1182
1183 #[verifier::external_body]
1184 pub(in crate::mm) unsafe fn first_activate_unchecked(&self) {
1185 unimplemented!()
1186 }
1190
1191 pub uninterp spec fn root_paddr_spec(&self) -> Paddr;
1192
1193 #[verifier::external_body]
1199 #[verifier::when_used_as_spec(root_paddr_spec)]
1200 pub fn root_paddr(&self) -> (r: Paddr)
1201 returns
1202 self.root_paddr_spec(),
1203 {
1204 unimplemented!()
1205 }
1208
1209 #[cfg(ktest)]
1215 pub fn page_walk(&self, vaddr: Vaddr) -> Option<(Paddr, PageProperty)> {
1216 unsafe { page_walk::<C>(self.root_paddr(), vaddr) }
1218 }
1219
1220 #[verus_spec(r =>
1225 with Tracked(owner): Tracked<PageTableOwner<C>>,
1226 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1227 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1228 Tracked(guards): Tracked<&mut Guards>
1229 requires
1230 self.relates_owner(owner, *old(regions)),
1231 Cursor::<C, G>::cursor_new_input_valid(*va)
1232 ==> Cursor::<C, G>::cursor_new_success_conditions(*va),
1233 owner.0.value().node().relate_guard(root_guard),
1234 va.end > 0,
1235 ensures
1236 final(regions).slots == old(regions).slots,
1237 forall|idx: int| #![trigger final(regions).slot_owners[idx]]
1238 old(regions).contains(idx) && old(regions).ref_count(idx) != REF_COUNT_UNUSED ==>
1239 final(regions).slot_owners[idx] == old(regions).slot_owners[idx],
1240 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1241 &&& r is Ok
1242 &&& r.unwrap().0.0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1243 &&& r.unwrap().1.in_barrier_va()
1244 &&& r.unwrap().0.0.level == r.unwrap().0.0.guard_level
1245 &&& r.unwrap().0.0.va < r.unwrap().0.0.barrier_va.end
1246 &&& r.unwrap().0.0.va == va.start
1247 &&& r.unwrap().0.0.barrier_va == *va
1248 },
1249 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1250 forall |item: C::Item| #![trigger CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions))]
1251 CursorMut::<'rcu, C, G>::item_not_mapped(item, *old(regions)) ==>
1252 CursorMut::<'rcu, C, G>::item_not_mapped(item, *final(regions)),
1253 forall |idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1257 old(regions).contains(idx) && old(regions).ref_count(idx)
1258 != REF_COUNT_UNUSED
1259 ==> final(regions).slot_owners[idx].paths_in_pt
1260 == old(regions).slot_owners[idx].paths_in_pt,
1261 forall|idx: int| #![trigger final(regions).slot_owners[idx]]
1262 old(regions).contains(idx)
1263 && old(regions).ref_count(idx)
1264 != REF_COUNT_UNUSED
1265 ==> final(regions).ref_count(idx)
1266 == old(regions).ref_count(idx)
1267 && final(regions).slot_owners[idx].usage
1268 == old(regions).slot_owners[idx].usage,
1269 )]
1270 pub fn cursor_mut<'rcu, G: InAtomicMode>(
1271 &'rcu self,
1272 guard: &'rcu G,
1273 va: &Range<Vaddr>,
1274 ) -> Result<(CursorMut<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>), PageTableError> {
1275 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1276 CursorMut::new(self, guard, va)
1277 }
1278
1279 #[verus_spec(r =>
1285 with Tracked(owner): Tracked<PageTableOwner<C>>,
1286 Ghost(root_guard): Ghost<PageTableGuard<'rcu, C>>,
1287 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1288 Tracked(guards): Tracked<&mut Guards>
1289 requires
1290 self.relates_owner(owner, *old(regions)),
1291 Cursor::<C, G>::cursor_new_input_valid(*va)
1292 ==> Cursor::<C, G>::cursor_new_success_conditions(*va),
1293 owner.0.value().node().relate_guard(root_guard),
1294 va.end > 0,
1295 ensures
1296 final(regions).slots == old(regions).slots,
1297 forall|idx: int| #![trigger final(regions).slot_owners[idx]]
1298 old(regions).contains(idx) && old(regions).ref_count(idx) != REF_COUNT_UNUSED ==>
1299 final(regions).slot_owners[idx] == old(regions).slot_owners[idx],
1300 Cursor::<C, G>::cursor_new_success_conditions(*va) ==> {
1301 &&& r is Ok
1302 &&& r.unwrap().0.invariants(*r.unwrap().1, *final(regions), *final(guards))
1303 &&& r.unwrap().1.in_barrier_va()
1304 &&& r.unwrap().0.level == r.unwrap().0.guard_level
1305 &&& r.unwrap().0.va < r.unwrap().0.barrier_va.end
1306 &&& r.unwrap().0.va == va.start
1307 &&& r.unwrap().0.barrier_va == *va
1308 &&& r.unwrap().1@.as_page_table_owner() == owner
1309 &&& r.unwrap().1@.continuations[3].path() == owner.0.value().path
1310 },
1311 !Cursor::<C, G>::cursor_new_success_conditions(*va) ==> r is Err,
1312 forall|idx: int| #![trigger final(regions).slot_owners[idx].paths_in_pt]
1313 old(regions).contains(idx) && old(regions).ref_count(idx)
1314 != REF_COUNT_UNUSED
1315 ==> final(regions).slot_owners[idx].paths_in_pt
1316 == old(regions).slot_owners[idx].paths_in_pt,
1317 (forall |i: int| #![trigger old(regions).slot_owners[i]]
1319 old(regions).contains(i)
1320 && old(regions).ref_count(i)
1321 != REF_COUNT_UNUSED
1322 ==> old(regions).ref_count(i) + 1
1323 < REF_COUNT_MAX)
1324 ==>
1325 (forall |i: int| #![trigger final(regions).slot_owners[i]]
1326 final(regions).contains(i)
1327 && final(regions).ref_count(i)
1328 != REF_COUNT_UNUSED
1329 ==> final(regions).ref_count(i) + 1
1330 < REF_COUNT_MAX),
1331 forall|idx: int| #![trigger final(regions).slot_owners[idx].ref_count()]
1332 final(regions).ref_count(idx)
1333 >= REF_COUNT_MAX
1334 ==> old(regions).ref_count(idx)
1335 == final(regions).ref_count(idx),
1336 forall|idx: int| #![trigger old(regions).slot_owners[idx].ref_count()]
1337 old(regions).ref_count(idx)
1338 >= REF_COUNT_MAX
1339 ==> final(regions).ref_count(idx)
1340 == old(regions).ref_count(idx),
1341 )]
1342 pub fn cursor<'rcu, G: InAtomicMode>(&'rcu self, guard: &'rcu G, va: &Range<Vaddr>) -> Result<
1343 (Cursor<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>),
1344 PageTableError,
1345 > {
1346 #[verus_spec(with Tracked(owner), Ghost(root_guard), Tracked(regions), Tracked(guards))]
1347 Cursor::new(self, guard, va)
1348 }}
1360
1361#[cfg(ktest)]
1384pub(super) unsafe fn page_walk<C: PageTableConfig>(root_paddr: Paddr, vaddr: Vaddr) -> Option<
1385 (Paddr, PageProperty),
1386> {
1387 use super::paddr_to_vaddr;
1388
1389 let _rcu_guard = disable_preempt();
1390
1391 let mut pt_addr = paddr_to_vaddr(root_paddr);
1392 #[verusfmt::skip]
1393 for cur_level in (1..= C::NR_LEVELS()).rev() {
1394 let offset = pte_index::<C>(vaddr, cur_level);
1395 let cur_pte = unsafe { load_pte((pt_addr as *mut C::E).add(offset), Ordering::Acquire) };
1401
1402 if !cur_pte.is_present() {
1403 return None;
1404 }
1405 if cur_pte.is_last(cur_level) {
1406 debug_assert!(cur_level <= C::HIGHEST_TRANSLATION_LEVEL);
1407 return Some(
1408 (cur_pte.paddr() + (vaddr & (page_size::<C>(cur_level) - 1)), cur_pte.prop()),
1409 );
1410 }
1411 pt_addr = paddr_to_vaddr(cur_pte.paddr());
1412 }
1413
1414 unreachable!("All present PTEs at the level 1 must be last-level PTEs");
1415}
1416
1417pub trait PageTableEntryTrait:
1421 Clone + Copy + Debug + Default + Sized + Pod + PodOnce + Send + Sync + 'static {
1422 spec fn new_absent_spec() -> Self;
1423
1424 #[verifier(when_used_as_spec(new_absent_spec))]
1428 fn new_absent() -> (res: Self)
1429 ensures
1430 valid_frame_paddr(res.paddr()),
1431 !res.is_present(),
1432 returns
1433 Self::new_absent(),
1434 ;
1435
1436 spec fn is_present_spec(&self) -> bool;
1437
1438 #[verifier::when_used_as_spec(is_present_spec)]
1444 fn is_present(&self) -> bool
1445 returns
1446 self.is_present_spec(),
1447 ;
1448
1449 spec fn new_page_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self;
1450
1451 spec fn new_page_req(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> bool;
1453
1454 #[verifier::when_used_as_spec(new_page_spec)]
1456 fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res: Self)
1457 requires
1458 paddr < MAX_PADDR,
1459 Self::new_page_req(paddr, level, prop),
1460 ensures
1461 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1462 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1463 valid_frame_paddr(res.paddr()),
1464 res.is_present(),
1465 res.is_last(level),
1466 res.prop() == prop,
1467 returns
1468 Self::new_page(paddr, level, prop),
1469 ;
1470
1471 spec fn new_pt_spec(paddr: Paddr) -> Self;
1472
1473 #[verifier::when_used_as_spec(new_pt_spec)]
1475 fn new_pt(paddr: Paddr) -> (res: Self)
1476 requires
1477 paddr < MAX_PADDR,
1478 ensures
1479 res.paddr() == paddr & !((PAGE_SIZE - 1) as usize),
1480 paddr % PAGE_SIZE == 0 ==> res.paddr() == paddr,
1481 valid_frame_paddr(res.paddr()),
1482 res.is_present(),
1483 forall|level: PagingLevel| level > 1 ==> !res.is_last(level),
1484 returns
1485 Self::new_pt(paddr),
1486 ;
1487
1488 spec fn paddr_spec(&self) -> Paddr;
1494
1495 #[verifier::when_used_as_spec(paddr_spec)]
1496 fn paddr(&self) -> (res: Paddr)
1497 ensures
1498 res % PAGE_SIZE == 0,
1499 returns
1500 self.paddr(),
1501 ;
1502
1503 spec fn prop_spec(&self) -> PageProperty;
1504
1505 #[verifier::when_used_as_spec(prop_spec)]
1506 fn prop(&self) -> PageProperty
1507 returns
1508 self.prop(),
1509 ;
1510
1511 spec fn set_prop_req(self, prop: PageProperty) -> bool;
1513
1514 fn set_prop(&mut self, prop: PageProperty)
1515 requires
1516 old(self).set_prop_req(prop),
1517 ensures
1518 !old(self).is_present() ==> *old(self) == *final(self),
1519 old(self).is_present() ==> {
1520 &&& final(self).prop() == prop
1521 &&& final(self).paddr() == old(self).paddr()
1522 &&& final(self).is_present()
1523 &&& forall|level: PagingLevel|
1524 #![trigger old(self).is_last(level)]
1525 old(self).is_last(level) ==> final(self).is_last(level)
1526 },
1527 ;
1528
1529 spec fn is_last_spec(&self, level: PagingLevel) -> bool;
1530
1531 #[verifier::when_used_as_spec(is_last_spec)]
1536 fn is_last(&self, level: PagingLevel) -> bool
1537 returns
1538 self.is_last_spec(level),
1539 ;
1540
1541 spec fn as_usize_spec(self) -> usize;
1542
1543 #[verifier::external_body]
1545 #[verifier::when_used_as_spec(as_usize_spec)]
1546 fn as_usize(self) -> usize
1547 returns
1548 self.as_usize(),
1549 {
1550 unimplemented!()
1551 }
1556
1557 #[verifier::external_body]
1559 fn from_usize(pte_raw: usize) -> Self {
1560 unimplemented!()
1561 }
1566
1567 proof fn lemma_page_table_entry_properties()
1569 ensures
1570 core::mem::size_of::<Self>() == core::mem::size_of::<usize>(),
1571 core::mem::size_of::<Self>() % core::mem::align_of::<Self>() == 0,
1572 core::mem::align_of::<Self>() > 0,
1573 valid_frame_paddr(Self::new_absent().paddr()),
1574 !Self::new_absent().is_present(),
1575 forall|level: PagingLevel|
1576 #![trigger Self::new_absent().is_last(level)]
1577 1 < level ==> !Self::new_absent().is_last(level),
1578 forall|paddr: Paddr, level: PagingLevel, prop: PageProperty|
1579 #![trigger Self::new_page(paddr, level, prop)]
1580 Self::new_page_req(paddr, level, prop) && (prop.cache is Writeback
1581 || prop.cache is Writethrough || prop.cache is Uncacheable) ==> {
1582 &&& Self::new_page(paddr, level, prop).is_present()
1583 &&& (paddr < MAX_PADDR ==> Self::new_page(paddr, level, prop).paddr() == paddr
1584 & !((PAGE_SIZE - 1) as usize))
1585 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_page(
1586 paddr,
1587 level,
1588 prop,
1589 ).paddr() == paddr)
1590 &&& Self::new_page(paddr, level, prop).prop() == prop
1591 &&& Self::new_page(paddr, level, prop).is_last(level)
1592 },
1593 forall|paddr: Paddr|
1594 #![trigger Self::new_pt(paddr)]
1595 {
1596 &&& Self::new_pt(paddr).is_present()
1597 &&& (paddr < MAX_PADDR ==> Self::new_pt(paddr).paddr() == paddr & !((PAGE_SIZE
1598 - 1) as usize))
1599 &&& (paddr < MAX_PADDR && paddr % PAGE_SIZE == 0 ==> Self::new_pt(paddr).paddr()
1600 == paddr)
1601 &&& forall|level: PagingLevel| level > 1 ==> !Self::new_pt(paddr).is_last(level)
1602 },
1603 ;
1604
1605 proof fn lemma_paddr_is_page_aligned(self)
1606 ensures
1607 self.paddr() % PAGE_SIZE == 0,
1608 ;
1609}
1610
1611#[verifier::external_body]
1626#[verus_spec(
1627 with Tracked(perm): Tracked<&vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1628 requires
1629 perm.is_init(ptr.index as int),
1630 perm.addr() == ptr.addr(),
1631 0 <= ptr.index < NR_ENTRIES,
1632 returns
1633 perm.value()[ptr.index as int],
1634)]
1635pub unsafe fn load_pte<E: PageTableEntryTrait>(
1636 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1637 ordering: Ordering,
1638) -> (pte: E) {
1639 unimplemented!()
1640}
1641
1642#[verifier::external_body]
1655#[verus_spec(
1656 with Tracked(perm): Tracked<&mut vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
1657 requires
1658 old(perm).addr() == ptr.addr(),
1659 0 <= ptr.index < NR_ENTRIES,
1660 old(perm).is_init_all(),
1661 ensures
1662 final(perm).wf(),
1663 final(perm).value()[ptr.index as int] == new_val,
1664 final(perm).value() == old(perm).value().update(ptr.index as int, new_val),
1665 final(perm).addr() == old(perm).addr(),
1666 final(perm).is_init_all(),
1667)]
1668pub unsafe fn store_pte<E: PageTableEntryTrait>(
1669 ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
1670 new_val: E,
1671 ordering: Ordering,
1672);
1673
1674}