1mod child;
27mod entry;
28
29#[path = "../../../../specs/mm/page_table/node/child.rs"]
30mod child_specs;
31#[path = "../../../../specs/mm/page_table/node/entry.rs"]
32mod entry_specs;
33
34use vstd::{atomic::PAtomicU8, cell::pcell_maybe_uninit, prelude::*, simple_pptr::PPtr};
35use vstd_extra::{array_ptr, cast_ptr::*, ghost_tree::*, ownership::*};
36
37pub use crate::specs::mm::page_table::node::{entry_owners::*, owners::*};
38use crate::specs::mm::{
39 frame::{
40 mapping::{frame_to_index, lemma_frame_to_index_injective, meta_to_index},
41 meta_owners::{
42 FracMetadataPerm, MetaSlotOwner, MetadataPerm, typed_meta_value, typed_meta_wf,
43 },
44 meta_region_owners::MetaRegionOwners,
45 },
46 page_table::node::owners::*,
47};
48
49use super::{PageTableConfig, PageTableEntryTrait, nr_subpage_per_huge};
50use crate::mm::frame::{
51 allocator::FrameAllocOptions,
52 meta::{
53 META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, REF_COUNT_UNUSED,
54 mapping::{frame_to_meta, meta_to_frame},
55 },
56};
57use crate::mm::page_table::*;
58use crate::mm::{Paddr, Vaddr};
59use crate::{
60 mm::{
61 PagingConstsTrait,
62 PagingLevel,
63 frame::{Frame, FrameRef, meta::AnyFrameMeta},
66 paddr_to_vaddr,
67 page_table::{load_pte, store_pte},
68 },
69 specs::task::InAtomicMode,
70};
71pub use child::*;
72use core::{marker::PhantomData, ops::Deref, sync::atomic::Ordering};
73pub use entry::*;
74
75verus! {
76
77pub struct PageTablePageMeta<C: PageTableConfig> {
80 pub nr_children: pcell_maybe_uninit::PCell<u16>,
82 pub stray: pcell_maybe_uninit::PCell<bool>,
88 pub level: PagingLevel,
91 pub lock: PAtomicU8,
93 pub _phantom: core::marker::PhantomData<C>,
94}
95
96pub type PageTableNode<C> = Frame<PageTablePageMeta<C>>;
106
107unsafe impl<C: PageTableConfig> AnyFrameMeta for PageTablePageMeta<C> {
108 open spec fn on_drop_pre(
126 &self,
127 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
128 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
129 vm_io_owner: crate::specs::mm::io::VmIoOwner,
130 ) -> bool {
131 &&& reader.inv()
132 &&& reader.wf(vm_io_owner)
133 &&& reader.remain_spec() >= crate::specs::arch::PAGE_SIZE
134 &&& reader.cursor.vaddr % core::mem::align_of::<C::E>() == 0
135 &&& vm_io_owner.inv()
136 &&& vm_io_owner.read_view_initialized()
137 &&& regions.inv()
138 &&& Self::child_perms_embedding(regions, vstd::set::Set::empty())
139 &&& self.walk_coverage_from_view(reader, vm_io_owner.read_view_of(), regions.slots.dom())
140 &&& self.walk_uniqueness_from_view(reader, vm_io_owner.read_view_of())
141 }
142
143 #[verifier::external_body]
149 fn on_drop(
150 &mut self,
151 reader: &mut crate::mm::VmReader<'_, crate::mm::Infallible>,
152 Tracked(regions): Tracked<
153 &mut crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
154 >,
155 Tracked(_vm_io_owner): Tracked<&mut crate::specs::mm::io::VmIoOwner>,
156 ) {
157 let level = self.level;
158 let range = if level == C::NR_LEVELS() {
159 C::TOP_LEVEL_INDEX_RANGE()
160 } else {
161 0..nr_subpage_per_huge::<C>()
162 };
163
164 reader.skip_in_place(range.start * core::mem::size_of::<C::E>());
165
166 let mut i = range.start;
167 while i < range.end {
168 let pte = reader.read_once::<C::E>().unwrap();
170 if pte.is_present() {
171 let paddr = pte.paddr();
172 if !pte.is_last(level) {
176 let frame = unsafe { Frame::<Self>::from_raw(paddr) };
179 frame.drop(Tracked(regions));
180 } else {
181 proof_decl! {
182 let tracked item_perm: Option<C::Perm>;
183 }
184 let _item = unsafe {
187 C::item_from_raw(paddr, level, pte.prop(), Tracked(item_perm))
188 };
189 }
190 }
191 i += 1;
192 }
193 }
194
195 fn is_untyped(&self) -> bool {
196 false
197 }
198
199 uninterp spec fn vtable_ptr(&self) -> usize;
200}
201
202#[verus_verify]
203impl<C: PageTableConfig> PageTableNode<C> {
204 #[verus_spec(
213 with
214 Tracked(owner): Tracked<&NodeOwner<C>>,
215 )]
216 pub(super) fn level(&self) -> PagingLevel
217 requires
218 self.external_meta_wf(owner.frame_permission.resource(), ()),
219 returns
220 owner.level(),
221 {
222 #[verus_spec(with
223 Tracked(Some(owner.tracked_borrow_metadata_perm())),
224 Tracked(&())
225 )]
226 let meta = self.meta();
227 meta.level
228 }
229
230 #[verus_spec(res =>
232 with Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
233 Tracked(regions): Tracked<&mut MetaRegionOwners>,
234 Tracked(guards): Tracked<&Guards>,
235 Ghost(idx): Ghost<usize>,
236 -> owner: Tracked<OwnerSubtree<C>>,
237 requires
238 1 <= level < NR_LEVELS,
239 idx < NR_ENTRIES,
240 old(regions).inv(),
241 old(parent_owner).inv(),
242 ensures
243 final(regions).inv(),
244 final(parent_owner).inv(),
245 allocated_empty_node_owner(owner@, level),
246 allocated_empty_node_grandchildren_none(owner@),
247 res.ptr.addr() == owner@.value().node().slot_vaddr(),
248 res.inv(),
249 res.wf_with_region(*final(regions)),
250 guards.unlocked(owner@.value().node().slot_vaddr()),
251 MetaSlot::get_node_from_unused_spec(meta_to_frame(owner@.value().node().slot_vaddr()), *old(regions), *final(regions)),
252 MetaSlot::slot_perm_reparked_spec(meta_to_frame(owner@.value().node().slot_vaddr()), *old(regions), *final(regions)),
253
254 old(regions).contains(meta_to_index(owner@.value().node().slot_vaddr())),
255
256 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
257 meta_to_frame(owner@.value().node().slot_vaddr())),
258 owner@.value().metaregion_sound(*final(regions)),
259 forall|i: int|
260 #[trigger] old(regions).ref_count(i) != REF_COUNT_UNUSED
261 ==> i != meta_to_index(owner@.value().node().slot_vaddr()),
262 owner@.value().match_pte(C::E::new_pt_spec(meta_to_frame(owner@.value().node().slot_vaddr())), level as PagingLevel),
263 final(parent_owner).meta_own == old(parent_owner).meta_own,
264 final(parent_owner).frame_permission == old(parent_owner).frame_permission,
265 final(parent_owner).slot_index == old(parent_owner).slot_index,
266 final(parent_owner).level() == old(parent_owner).level(),
267 final(parent_owner).tree_level == old(parent_owner).tree_level,
268 final(parent_owner).children_perm.addr() == old(parent_owner).children_perm.addr(),
269 final(parent_owner).children_perm.value() == old(parent_owner).children_perm.value().update(
270 idx as int,
271 C::E::new_pt_spec(meta_to_frame(owner@.value().node().slot_vaddr())),
272 ),
273 final(regions).contains(owner@.value().node().slot_index),
274 owner@.value().node().metaregion_sound_node(*final(regions)),
275 )]
276 #[verifier::external_body]
277 pub fn alloc<'rcu>(level: PagingLevel) -> Self {
278 let tracked entry_owner = EntryOwner::tracked_new_absent(
279 TreePath::new(Seq::empty()),
280 level,
281 );
282
283 let tracked mut owner = OwnerSubtree::<C>::tracked_new_val(entry_owner, level as nat);
284 let meta = PageTablePageMeta::new(level);
285 let mut frame = FrameAllocOptions::new();
286 frame.zeroed(true);
287 let allocated_frame = frame.alloc_frame_with(meta).expect(
288 "Failed to allocate a page table node",
289 );
290 proof_with!(|= Tracked(owner));
294
295 allocated_frame
296 }}
347
348#[verus_verify]
349impl<'a, C: PageTableConfig> PageTableNodeRef<'a, C> {
350 pub open spec fn locks_preserved_except<'rcu>(
351 addr: usize,
352 guards0: Guards,
353 guards1: Guards,
354 ) -> bool {
355 &&& OwnerSubtree::implies(
356 CursorOwner::<'rcu, C>::node_unlocked(guards0),
357 CursorOwner::<'rcu, C>::node_unlocked_except(guards1, addr),
358 )
359 &&& forall|i: usize| guards0.lock_held(i) ==> guards1.lock_held(i)
360 &&& forall|i: usize| guards0.unlocked(i) && i != addr ==> guards1.unlocked(i)
361 }
362
363 #[verifier::external_body]
372 #[verus_spec(res =>
373 with Tracked(owner): Tracked<&NodeOwner<C>>,
374 Tracked(guards): Tracked<&mut Guards>
375 requires
376 self.inner@.invariants(*owner),
377 self.inner@.external_meta_wf(owner.frame_permission.resource(), ()),
378 old(guards).unlocked(owner.slot_vaddr()),
379 ensures
380 final(guards).lock_held(owner.slot_vaddr()),
381 Self::locks_preserved_except(owner.slot_vaddr(), *old(guards), *final(guards)),
382 owner.relate_guard(res),
383 )]
384 pub fn lock<'rcu, A: InAtomicMode>(self, _guard: &'rcu A) -> PageTableGuard<'rcu, C> where
385 'a: 'rcu,
386 {
387 unimplemented!()
388 }
389
390 #[verus_spec(res =>
399 with Tracked(owner): Tracked<&NodeOwner<C>>,
400 Tracked(guards): Tracked<&mut Guards>,
401 requires
402 self.inner@.invariants(*owner),
403 self.inner@.external_meta_wf(owner.frame_permission.resource(), ()),
404 old(guards).unlocked(owner.slot_vaddr()),
405 ensures
406 final(guards).lock_held(owner.slot_vaddr()),
407 Self::locks_preserved_except(owner.slot_vaddr(), *old(guards), *final(guards)),
408 owner.relate_guard(res),
409 )]
410 pub unsafe fn make_guard_unchecked<'rcu, A: InAtomicMode>(
411 self,
412 _guard: &'rcu A,
413 ) -> PageTableGuard<'rcu, C> where 'a: 'rcu {
414 let guard = PageTableGuard { inner: self };
415
416 proof {
417 guards.guards = guards.guards.insert(owner.slot_vaddr());
418 }
419
420 guard
421 }
422}
423
424impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
425 #[verus_spec(res =>
432 with Tracked(owner): Tracked<&NodeOwner<C>>,
433 Tracked(child_owner): Tracked<&EntryOwner<C>>,
434 Tracked(regions): Tracked<&MetaRegionOwners>,
435 requires
436 owner.inv(),
437 child_owner.inv(),
438 owner.relate_guard(*old(self)),
439 child_owner.match_pte(
440 owner.children_perm.value()[idx as int],
441 child_owner.parent_level,
442 ),
443 regions.inv(),
444 regions.contains(owner.slot_index),
445 idx < NR_ENTRIES,
447 ensures
448 res.wf(*child_owner),
449 res.idx == idx,
450 *res.node == *old(self),
451 *final(self) == *final(res.node),
452 owner.relate_guard(*res.node),
453 )]
454 pub fn entry<'a>(&'a mut self, idx: usize) -> Entry<'a, 'rcu, C> {
455 #[cfg(feature = "allow_panic")]
456 assert!(idx < nr_subpage_per_huge::<C>());
457 unsafe {
460 #[verus_spec(with Tracked(child_owner), Tracked(owner), Tracked(regions))]
461 Entry::new_at(self, idx)
462 }
463 }
464
465 #[verus_spec(nr =>
474 with Tracked(owner) : Tracked<&NodeOwner<C>>,
475 requires
476 owner.meta_own.nr_children.id() == owner.meta_value().nr_children.id(),
477 self.inner.inner@.invariants(*owner),
478 self.inner.inner@.external_meta_wf(owner.frame_permission.resource(), ()),
479 returns
480 owner.meta_own.nr_children.value(),
481 )]
482 pub fn nr_children(&self) -> u16 {
483 #[verus_spec(with
484 Tracked(Some(owner.tracked_borrow_metadata_perm())),
485 Tracked(&())
486 )]
487 let meta = self.meta();
488
489 *meta.nr_children.borrow(Tracked(&owner.meta_own.nr_children))
490 }
491
492 #[verus_spec(res =>
494 with
495 Tracked(metadata_perms): Tracked<&'a MetadataPerm>,
496 Tracked(repr_perm): Tracked<&'a ()>,
497 Ghost(stray_id): Ghost<vstd::cell::CellId>,
498 requires
499 old(self).inner.inner@.external_meta_wf(*metadata_perms, *repr_perm),
500 typed_meta_value::<PageTablePageMeta<C>>(
501 *metadata_perms,
502 *repr_perm,
503 ).stray.id()
504 == stray_id,
505 ensures
506 res.id() == stray_id,
507 *final(self) == *old(self),
508 )]
509 pub(super) fn stray_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<bool> {
510 #[verus_spec(with
512 Tracked(Some(metadata_perms)),
513 Tracked(repr_perm)
514 )]
515 let meta = self.meta();
516 &meta.stray
517 }
518
519 #[verus_spec(pte =>
529 with Tracked(owner): Tracked<&NodeOwner<C>>,
530 Tracked(regions): Tracked<&MetaRegionOwners>,
531 requires
532 self.inner.inner@.invariants(*owner),
533 regions.inv(),
534 regions.contains(owner.slot_index),
535 idx < NR_ENTRIES,
536 ensures
537 pte == owner.children_perm.value()[idx as int],
538 )]
539 pub unsafe fn read_pte(&self, idx: usize) -> C::E {
540 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
542 paddr_to_vaddr(self.start_paddr()),
543 );
544
545 unsafe {
549 #[verus_spec(with Tracked(&owner.children_perm))]
550 load_pte(ptr.add(idx), Ordering::Relaxed)
551 }
552 }
553
554 #[verus_spec(
567 with Tracked(owner): Tracked<&mut NodeOwner<C>>,
568 Tracked(regions): Tracked<&MetaRegionOwners>,
569 requires
570 old(self).inner.inner@.invariants(*old(owner)),
571 regions.inv(),
572 regions.contains(old(owner).slot_index),
573 idx < NR_ENTRIES,
574 ensures
575 final(owner).inv(),
576 final(owner).level() == old(owner).level(),
577 final(owner).meta_own == old(owner).meta_own,
578 final(owner).frame_permission == old(owner).frame_permission,
579 final(owner).slot_index == old(owner).slot_index,
580 final(owner).children_perm.value() == old(owner).children_perm.value().update(
581 idx as int,
582 pte,
583 ),
584 *final(self) == *old(self),
585 )]
586 pub unsafe fn write_pte(&mut self, idx: usize, pte: C::E) {
587 #[verusfmt::skip]
589 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
590 paddr_to_vaddr(self.start_paddr())
591 );
592
593 unsafe {
597 #[verus_spec(with Tracked(&mut owner.children_perm))]
598 store_pte(ptr.add(idx), pte, Ordering::Release)
599 }
600 proof {
601 assert(owner.children_perm.wf());
602 }
603 }
604
605 #[verus_spec(res =>
607 with
608 Tracked(metadata_perms): Tracked<&'a MetadataPerm>,
609 Ghost(nr_children_id): Ghost<vstd::cell::CellId>,
610 requires
611 old(self).inner.inner@.external_meta_wf(*metadata_perms, ()),
612 typed_meta_value::<PageTablePageMeta<C>>(
613 *metadata_perms,
614 (),
615 ).nr_children.id()
616 == nr_children_id,
617 ensures
618 res.id() == nr_children_id,
619 *final(self) == *old(self),
620 )]
621 fn nr_children_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<u16> {
622 #[verus_spec(with
624 Tracked(Some(metadata_perms)),
625 Tracked(&())
626 )]
627 let meta = self.meta();
628 &meta.nr_children
629 }
630}
631
632impl<C: PageTableConfig> PageTablePageMeta<C> {
639 pub fn new(level: PagingLevel) -> Self {
640 Self {
641 nr_children: pcell_maybe_uninit::PCell::new(0).0,
642 stray: pcell_maybe_uninit::PCell::new(false).0,
643 level,
644 lock: PAtomicU8::new(0).0,
645 _phantom: PhantomData,
646 }
647 }
648
649 pub open spec fn walk_pte_at_view(view: crate::specs::mm::virt_mem::MemView, c: usize) -> C::E {
654 ostd_pod::decode_pod::<C::E>(view.read_bytes(c, core::mem::size_of::<C::E>()))
655 }
656
657 pub open spec fn walk_coverage_at(
662 self,
663 view: crate::specs::mm::virt_mem::MemView,
664 dom: vstd::set::Set<int>,
665 c: usize,
666 ) -> bool {
667 let pte = Self::walk_pte_at_view(view, c);
668 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(frame_to_index(pte.paddr()))
669 }
670
671 pub proof fn lemma_coverage_at(
673 self,
674 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
675 view: crate::specs::mm::virt_mem::MemView,
676 dom: vstd::set::Set<int>,
677 c: usize,
678 )
679 requires
680 self.walk_coverage_from_view(reader, view, dom),
681 reader.cursor.vaddr <= c,
682 c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
683 (c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
684 ensures
685 self.walk_coverage_at(view, dom, c),
686 {
687 }
688
689 pub proof fn lemma_uniqueness_at_pair(
691 self,
692 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
693 view: crate::specs::mm::virt_mem::MemView,
694 c1: usize,
695 c2: usize,
696 )
697 requires
698 self.walk_uniqueness_from_view(reader, view),
699 reader.cursor.vaddr <= c1,
700 c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
701 (c1 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
702 reader.cursor.vaddr <= c2,
703 c2 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
704 (c2 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
705 c1 != c2,
706 Self::walk_pte_at_view(view, c1).is_present(),
707 !Self::walk_pte_at_view(view, c1).is_last(self.level),
708 Self::walk_pte_at_view(view, c2).is_present(),
709 !Self::walk_pte_at_view(view, c2).is_last(self.level),
710 ensures
711 Self::walk_pte_at_view(view, c1).paddr() != Self::walk_pte_at_view(view, c2).paddr(),
712 {
713 }
714
715 pub open spec fn walk_coverage_from_view(
721 self,
722 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
723 view: crate::specs::mm::virt_mem::MemView,
724 dom: vstd::set::Set<int>,
725 ) -> bool {
726 forall|c: usize|
727 #![trigger Self::walk_pte_at_view(view, c)]
728 reader.cursor.vaddr <= c && c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
729 + reader.remain_spec() && (c - reader.cursor.vaddr) % core::mem::size_of::<
730 C::E,
731 >() as int == 0 ==> {
732 let pte = Self::walk_pte_at_view(view, c);
733 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(
734 frame_to_index(pte.paddr()),
735 )
736 }
737 }
738
739 pub open spec fn walk_uniqueness_from_view(
742 self,
743 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
744 view: crate::specs::mm::virt_mem::MemView,
745 ) -> bool {
746 forall|c1: usize, c2: usize|
747 #![trigger Self::walk_pte_at_view(view, c1), Self::walk_pte_at_view(view, c2)]
748 reader.cursor.vaddr <= c1 && c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
749 + reader.remain_spec() && (c1 - reader.cursor.vaddr) % core::mem::size_of::<
750 C::E,
751 >() as int == 0 && reader.cursor.vaddr <= c2 && c2 + core::mem::size_of::<C::E>()
752 <= reader.cursor.vaddr + reader.remain_spec() && (c2 - reader.cursor.vaddr)
753 % core::mem::size_of::<C::E>() as int == 0 && c1 != c2 ==> {
754 let pte1 = Self::walk_pte_at_view(view, c1);
755 let pte2 = Self::walk_pte_at_view(view, c2);
756 pte1.is_present() && !pte1.is_last(self.level) && pte2.is_present()
757 && !pte2.is_last(self.level) ==> pte1.paddr() != pte2.paddr()
758 }
759 }
760
761 pub open spec fn child_perms_embedding(
766 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
767 excluded: vstd::set::Set<int>,
768 ) -> bool {
769 forall|paddr: crate::mm::Paddr|
770 #![trigger regions.slot_owner(paddr)]
771 regions.slots.dom().contains(frame_to_index(paddr)) && !excluded.contains(
772 frame_to_index(paddr),
773 ) ==> {
774 let idx = frame_to_index(paddr);
775 let so = regions.slot_owners[idx];
776 &&& <Frame<Self>>::from_raw_requires(regions, paddr)
777 &&& 0 < so.ref_count() <= REF_COUNT_MAX
778 &&& so.storage_perm().is_init()
779 &&& so.ref_count() == 1 ==> {
780 &&& so.in_list_perm.value() == 0
781 &&& so.paths_in_pt.is_empty()
782 }
783 }
784 }
785}
786
787}