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::{mapping::*, meta_owners::*, meta_region_owners::MetaRegionOwners},
40 page_table::node::owners::*,
41};
42
43use super::{PageTableConfig, PageTableEntryTrait, nr_subpage_per_huge};
44use crate::mm::frame::{
45 allocator::FrameAllocOptions,
46 meta::{
47 META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX,
48 mapping::{frame_to_meta, meta_to_frame},
49 },
50};
51use crate::mm::page_table::*;
52use crate::mm::{Paddr, Vaddr};
53use crate::{
54 mm::{
55 PagingConstsTrait,
56 PagingLevel,
57 frame::{Frame, FrameRef, meta::AnyFrameMeta},
60 paddr_to_vaddr,
61 page_table::{load_pte, store_pte},
62 },
63 specs::task::InAtomicMode,
64};
65pub use child::*;
66use core::{marker::PhantomData, ops::Deref, sync::atomic::Ordering};
67pub use entry::*;
68
69verus! {
70
71pub struct PageTablePageMeta<C: PageTableConfig> {
74 pub nr_children: pcell_maybe_uninit::PCell<u16>,
76 pub stray: pcell_maybe_uninit::PCell<bool>,
82 pub level: PagingLevel,
85 pub lock: PAtomicU8,
87 pub _phantom: core::marker::PhantomData<C>,
88}
89
90pub type PageTableNode<C> = Frame<PageTablePageMeta<C>>;
100
101unsafe impl<C: PageTableConfig> AnyFrameMeta for PageTablePageMeta<C> {
102 open spec fn on_drop_pre(
120 &self,
121 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
122 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
123 vm_io_owner: crate::specs::mm::io::VmIoOwner,
124 ) -> bool {
125 &&& reader.inv()
126 &&& reader.wf(vm_io_owner)
127 &&& reader.remain_spec() >= crate::specs::arch::PAGE_SIZE
128 &&& reader.cursor.vaddr % core::mem::align_of::<C::E>() == 0
129 &&& vm_io_owner.inv()
130 &&& vm_io_owner.read_view_initialized()
131 &&& regions.inv()
132 &&& Self::child_perms_embedding(regions, vstd::set::Set::empty())
133 &&& self.walk_coverage_from_view(reader, vm_io_owner.read_view_of(), regions.slots.dom())
134 &&& self.walk_uniqueness_from_view(reader, vm_io_owner.read_view_of())
135 }
136
137 #[verifier::external_body]
143 fn on_drop(
144 &mut self,
145 reader: &mut crate::mm::VmReader<'_, crate::mm::Infallible>,
146 Tracked(regions): Tracked<
147 &mut crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
148 >,
149 Tracked(_vm_io_owner): Tracked<&mut crate::specs::mm::io::VmIoOwner>,
150 ) {
151 let level = self.level;
152 let range = if level == C::NR_LEVELS() {
153 C::TOP_LEVEL_INDEX_RANGE()
154 } else {
155 0..nr_subpage_per_huge::<C>()
156 };
157
158 reader.skip_in_place(range.start * core::mem::size_of::<C::E>());
159
160 for _ in range {
161 let pte = reader.read_once::<C::E>().unwrap();
163 if pte.is_present() {
164 let paddr = pte.paddr();
165 if !pte.is_last(level) {
169 let frame = unsafe { Frame::<Self>::from_raw(paddr) };
172 frame.drop(Tracked(regions));
173 } else {
174 proof_decl! {
175 let tracked item_perm: Option<C::Perm>;
176 }
177 let _item = unsafe {
180 C::item_from_raw(paddr, level, pte.prop(), Tracked(item_perm))
181 };
182 }
183 }
184 }
185 }
186
187 fn is_untyped(&self) -> bool {
188 false
189 }
190
191 uninterp spec fn vtable_ptr(&self) -> usize;
192}
193
194#[verus_verify]
195impl<C: PageTableConfig> PageTableNode<C> {
196 #[verus_spec(
205 with
206 Tracked(owner): Tracked<&NodeOwner<C>>,
207 )]
208 pub(super) fn level(&self) -> PagingLevel
209 requires
210 self.external_meta_wf(owner.frame_permission.resource(), ()),
211 returns
212 owner.level(),
213 {
214 #[verus_spec(with
215 Tracked(Some(owner.tracked_borrow_metadata_perm())),
216 Tracked(&())
217 )]
218 let meta = self.meta();
219 meta.level
220 }
221
222 #[verus_spec(res =>
224 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
225 Tracked(guards): Tracked<&Guards>,
226 -> owner: Tracked<OwnerSubtree<C>>,
227 requires
228 1 <= level < NR_LEVELS,
229 old(regions).inv(),
230 ensures
231 final(regions).inv(),
232 allocated_empty_node_owner(owner@, level),
233 allocated_empty_node_grandchildren_none(owner@),
234 res.slot_vaddr() == owner@.value().node().slot_vaddr(),
235 res.external_meta_wf(owner@.value().node().frame_permission.resource(), ()),
236 res.tracked_slot_perm@ == final(regions).slots[owner@.value().node().slot_index],
237 guards.unlocked(owner@.value().node().slot_vaddr()),
238 MetaSlot::claim_unused_slot_region_spec(
239 meta_to_frame(owner@.value().node().slot_vaddr()),
240 false, *old(regions), *final(regions)),
241
242 old(regions).contains(meta_to_index(owner@.value().node().slot_vaddr())),
243
244 final(regions).slot_owners[owner@.value().node().slot_index].paths_in_pt.is_empty(),
245 owner@.value().match_pte(C::E::new_pt_spec(meta_to_frame(owner@.value().node().slot_vaddr())), (level + 1) as PagingLevel),
246 final(regions).contains(owner@.value().node().slot_index),
247 owner@.value().node().metaregion_sound_node(*final(regions)),
248 )]
249 #[verifier::external_body]
250 pub fn alloc<'rcu>(level: PagingLevel) -> Self {
251 let tracked entry_owner = EntryOwner::tracked_new_absent(
252 TreePath::new(Seq::empty()),
253 level,
254 );
255
256 let tracked mut owner = OwnerSubtree::<C>::tracked_new_val(entry_owner, level as nat);
257 let meta = PageTablePageMeta::new(level);
258 let mut frame = FrameAllocOptions::new();
259 frame.zeroed(true);
260 let allocated_frame = frame.alloc_frame_with(meta).expect(
261 "Failed to allocate a page table node",
262 );
263 proof_with!(|= Tracked(owner));
267
268 allocated_frame
269 }}
320
321#[verus_verify]
322impl<'a, C: PageTableConfig> PageTableNodeRef<'a, C> {
323 pub open spec fn locks_preserved_except<'rcu>(
324 addr: usize,
325 guards0: Guards,
326 guards1: Guards,
327 ) -> bool {
328 &&& OwnerSubtree::implies(
329 CursorOwner::<'rcu, C>::node_unlocked(guards0),
330 CursorOwner::<'rcu, C>::node_unlocked_except(guards1, addr),
331 )
332 &&& forall|i: usize| guards0.lock_held(i) ==> guards1.lock_held(i)
333 &&& forall|i: usize| guards0.unlocked(i) && i != addr ==> guards1.unlocked(i)
334 }
335
336 #[verifier::external_body]
345 #[verus_spec(res =>
346 with Tracked(owner): Tracked<&NodeOwner<C>>,
347 Tracked(guards): Tracked<&mut Guards>
348 requires
349 self.inner@.invariants(*owner),
350 self.inner@.external_meta_wf(owner.frame_permission.resource(), ()),
351 old(guards).unlocked(owner.slot_vaddr()),
352 ensures
353 final(guards).lock_held(owner.slot_vaddr()),
354 Self::locks_preserved_except(owner.slot_vaddr(), *old(guards), *final(guards)),
355 owner.relate_guard(res),
356 )]
357 pub fn lock<'rcu, A: InAtomicMode>(self, _guard: &'rcu A) -> PageTableGuard<'rcu, C> where
358 'a: 'rcu,
359 {
360 unimplemented!()
361 }
362
363 #[verus_spec(res =>
372 with Tracked(owner): Tracked<&NodeOwner<C>>,
373 Tracked(guards): Tracked<&mut Guards>,
374 requires
375 self.inner@.invariants(*owner),
376 self.inner@.external_meta_wf(owner.frame_permission.resource(), ()),
377 old(guards).unlocked(owner.slot_vaddr()),
378 ensures
379 final(guards).lock_held(owner.slot_vaddr()),
380 Self::locks_preserved_except(owner.slot_vaddr(), *old(guards), *final(guards)),
381 owner.relate_guard(res),
382 )]
383 pub unsafe fn make_guard_unchecked<'rcu, A: InAtomicMode>(
384 self,
385 _guard: &'rcu A,
386 ) -> PageTableGuard<'rcu, C> where 'a: 'rcu {
387 let guard = PageTableGuard { inner: self };
388
389 proof {
390 guards.guards = guards.guards.insert(owner.slot_vaddr());
391 }
392
393 guard
394 }
395}
396
397impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
398 #[verus_spec(res =>
405 with Tracked(owner): Tracked<&NodeOwner<C>>,
406 Tracked(child_owner): Tracked<&EntryOwner<C>>,
407 Tracked(regions): Tracked<&MetaRegionOwners>,
408 requires
409 owner.inv(),
410 child_owner.inv(),
411 owner.relate_guard(*old(self)),
412 child_owner.match_pte(
413 owner.children_perm.value()[idx as int],
414 child_owner.parent_level,
415 ),
416 regions.inv(),
417 regions.contains(owner.slot_index),
418 idx < NR_ENTRIES,
420 ensures
421 res.wf(*child_owner),
422 res.idx == idx,
423 *res.node == *old(self),
424 *final(self) == *final(res.node),
425 owner.relate_guard(*res.node),
426 )]
427 pub fn entry<'a>(&'a mut self, idx: usize) -> Entry<'a, 'rcu, C> {
428 #[cfg(feature = "allow_panic")]
429 assert!(idx < nr_subpage_per_huge::<C>());
430 unsafe {
433 #[verus_spec(with Tracked(child_owner), Tracked(owner), Tracked(regions))]
434 Entry::new_at(self, idx)
435 }
436 }
437
438 #[verus_spec(nr =>
447 with Tracked(owner) : Tracked<&NodeOwner<C>>,
448 requires
449 owner.meta_own.nr_children.id() == owner.meta_value().nr_children.id(),
450 self.inner.inner@.invariants(*owner),
451 self.inner.inner@.external_meta_wf(owner.frame_permission.resource(), ()),
452 returns
453 owner.meta_own.nr_children.value(),
454 )]
455 pub fn nr_children(&self) -> u16 {
456 #[verus_spec(with
457 Tracked(Some(owner.tracked_borrow_metadata_perm())),
458 Tracked(&())
459 )]
460 let meta = self.meta();
461
462 *meta.nr_children.borrow(Tracked(&owner.meta_own.nr_children))
463 }
464
465 #[verus_spec(res =>
467 with
468 Tracked(metadata_perms): Tracked<&'a MetadataPerm>,
469 Tracked(repr_perm): Tracked<&'a ()>,
470 Ghost(stray_id): Ghost<vstd::cell::CellId>,
471 requires
472 old(self).inner.inner@.external_meta_wf(*metadata_perms, *repr_perm),
473 typed_meta_value::<PageTablePageMeta<C>>(
474 *metadata_perms,
475 *repr_perm,
476 ).stray.id()
477 == stray_id,
478 ensures
479 res.id() == stray_id,
480 *final(self) == *old(self),
481 )]
482 pub(super) fn stray_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<bool> {
483 #[verus_spec(with
485 Tracked(Some(metadata_perms)),
486 Tracked(repr_perm)
487 )]
488 let meta = self.meta();
489 &meta.stray
490 }
491
492 #[verus_spec(
502 with Tracked(owner): Tracked<&NodeOwner<C>>,
503 Tracked(regions): Tracked<&MetaRegionOwners>,
504 requires
505 self.inner.inner@.invariants(*owner),
506 regions.inv(),
507 regions.contains(owner.slot_index),
508 idx < NR_ENTRIES,
509 returns
510 owner.children_perm.value()[idx as int],
511 )]
512 pub unsafe fn read_pte(&self, idx: usize) -> C::E {
513 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
515 paddr_to_vaddr(self.start_paddr()),
516 );
517
518 unsafe {
522 #[verus_spec(with Tracked(&owner.children_perm))]
523 load_pte(ptr.add(idx), Ordering::Relaxed)
524 }
525 }
526
527 #[verus_spec(
540 with Tracked(owner): Tracked<&mut NodeOwner<C>>,
541 Tracked(regions): Tracked<&MetaRegionOwners>,
542 requires
543 old(self).inner.inner@.invariants(*old(owner)),
544 regions.inv(),
545 regions.contains(old(owner).slot_index),
546 idx < NR_ENTRIES,
547 ensures
548 final(owner).inv(),
549 final(owner).level() == old(owner).level(),
550 final(owner).meta_own == old(owner).meta_own,
551 final(owner).frame_permission == old(owner).frame_permission,
552 final(owner).slot_index == old(owner).slot_index,
553 final(owner).tree_level == old(owner).tree_level,
554 final(owner).children_perm.value() == old(owner).children_perm.value().update(
555 idx as int,
556 pte,
557 ),
558 *final(self) == *old(self),
559 )]
560 pub unsafe fn write_pte(&mut self, idx: usize, pte: C::E) {
561 #[verusfmt::skip]
563 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
564 paddr_to_vaddr(self.start_paddr())
565 );
566
567 unsafe {
571 #[verus_spec(with Tracked(&mut owner.children_perm))]
572 store_pte(ptr.add(idx), pte, Ordering::Release)
573 }
574 proof {
575 assert(owner.children_perm.wf());
576 }
577 }
578
579 #[verus_spec(res =>
581 with
582 Tracked(metadata_perms): Tracked<&'a MetadataPerm>,
583 Ghost(nr_children_id): Ghost<vstd::cell::CellId>,
584 requires
585 old(self).inner.inner@.external_meta_wf(*metadata_perms, ()),
586 typed_meta_value::<PageTablePageMeta<C>>(
587 *metadata_perms,
588 (),
589 ).nr_children.id()
590 == nr_children_id,
591 ensures
592 res.id() == nr_children_id,
593 *final(self) == *old(self),
594 )]
595 fn nr_children_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<u16> {
596 #[verus_spec(with
598 Tracked(Some(metadata_perms)),
599 Tracked(&())
600 )]
601 let meta = self.meta();
602 &meta.nr_children
603 }
604}
605
606impl<C: PageTableConfig> PageTablePageMeta<C> {
613 pub fn new(level: PagingLevel) -> Self {
614 Self {
615 nr_children: pcell_maybe_uninit::PCell::new(0).0,
616 stray: pcell_maybe_uninit::PCell::new(false).0,
617 level,
618 lock: PAtomicU8::new(0).0,
619 _phantom: PhantomData,
620 }
621 }
622
623 pub open spec fn walk_pte_at_view(view: crate::specs::mm::virt_mem::MemView, c: usize) -> C::E {
628 ostd_pod::decode_pod::<C::E>(view.read_bytes(c, core::mem::size_of::<C::E>()))
629 }
630
631 pub open spec fn walk_coverage_at(
636 self,
637 view: crate::specs::mm::virt_mem::MemView,
638 dom: vstd::set::Set<int>,
639 c: usize,
640 ) -> bool {
641 let pte = Self::walk_pte_at_view(view, c);
642 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(frame_to_index(pte.paddr()))
643 }
644
645 pub proof fn lemma_coverage_at(
647 self,
648 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
649 view: crate::specs::mm::virt_mem::MemView,
650 dom: vstd::set::Set<int>,
651 c: usize,
652 )
653 requires
654 self.walk_coverage_from_view(reader, view, dom),
655 reader.cursor.vaddr <= c,
656 c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
657 (c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
658 ensures
659 self.walk_coverage_at(view, dom, c),
660 {
661 }
662
663 pub proof fn lemma_uniqueness_at_pair(
665 self,
666 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
667 view: crate::specs::mm::virt_mem::MemView,
668 c1: usize,
669 c2: usize,
670 )
671 requires
672 self.walk_uniqueness_from_view(reader, view),
673 reader.cursor.vaddr <= c1,
674 c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
675 (c1 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
676 reader.cursor.vaddr <= c2,
677 c2 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
678 (c2 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
679 c1 != c2,
680 Self::walk_pte_at_view(view, c1).is_present(),
681 !Self::walk_pte_at_view(view, c1).is_last(self.level),
682 Self::walk_pte_at_view(view, c2).is_present(),
683 !Self::walk_pte_at_view(view, c2).is_last(self.level),
684 ensures
685 Self::walk_pte_at_view(view, c1).paddr() != Self::walk_pte_at_view(view, c2).paddr(),
686 {
687 }
688
689 pub open spec fn walk_coverage_from_view(
695 self,
696 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
697 view: crate::specs::mm::virt_mem::MemView,
698 dom: vstd::set::Set<int>,
699 ) -> bool {
700 forall|c: usize|
701 #![trigger Self::walk_pte_at_view(view, c)]
702 reader.cursor.vaddr <= c && c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
703 + reader.remain_spec() && (c - reader.cursor.vaddr) % core::mem::size_of::<
704 C::E,
705 >() as int == 0 ==> {
706 let pte = Self::walk_pte_at_view(view, c);
707 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(
708 frame_to_index(pte.paddr()),
709 )
710 }
711 }
712
713 pub open spec fn walk_uniqueness_from_view(
716 self,
717 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
718 view: crate::specs::mm::virt_mem::MemView,
719 ) -> bool {
720 forall|c1: usize, c2: usize|
721 #![trigger Self::walk_pte_at_view(view, c1), Self::walk_pte_at_view(view, c2)]
722 reader.cursor.vaddr <= c1 && c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
723 + reader.remain_spec() && (c1 - reader.cursor.vaddr) % core::mem::size_of::<
724 C::E,
725 >() as int == 0 && reader.cursor.vaddr <= c2 && c2 + core::mem::size_of::<C::E>()
726 <= reader.cursor.vaddr + reader.remain_spec() && (c2 - reader.cursor.vaddr)
727 % core::mem::size_of::<C::E>() as int == 0 && c1 != c2 ==> {
728 let pte1 = Self::walk_pte_at_view(view, c1);
729 let pte2 = Self::walk_pte_at_view(view, c2);
730 pte1.is_present() && !pte1.is_last(self.level) && pte2.is_present()
731 && !pte2.is_last(self.level) ==> pte1.paddr() != pte2.paddr()
732 }
733 }
734
735 pub open spec fn child_perms_embedding(
740 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
741 excluded: vstd::set::Set<int>,
742 ) -> bool {
743 forall|paddr: crate::mm::Paddr|
744 #![trigger regions.slot_owner(paddr)]
745 regions.slots.dom().contains(frame_to_index(paddr)) && !excluded.contains(
746 frame_to_index(paddr),
747 ) ==> {
748 let idx = frame_to_index(paddr);
749 let so = regions.slot_owners[idx];
750 &&& <Frame<Self>>::from_raw_requires(regions, paddr)
751 &&& 0 < so.ref_count() <= REF_COUNT_MAX
752 &&& so.storage_perm().is_init()
753 &&& so.ref_count() == 1 ==> {
754 &&& so.in_list_perm.value() == 0
755 &&& so.paths_in_pt.is_empty()
756 }
757 }
758 }
759}
760
761}