Skip to main content

ostd/specs/mm/page_table/node/
owners.rs

1use vstd::cell::pcell_maybe_uninit;
2use vstd::prelude::*;
3
4use vstd::cell;
5use vstd::simple_pptr::*;
6
7use crate::mm::frame::meta::MetaSlot;
8use crate::mm::kspace::{LINEAR_MAPPING_BASE_VADDR, VMALLOC_BASE_VADDR};
9use crate::mm::paddr_to_vaddr;
10use crate::mm::page_table::*;
11use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
12use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
13use crate::specs::arch::mm::{MAX_NR_PAGES, MAX_PADDR, NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
14use crate::specs::arch::paging_consts::PagingConsts;
15use crate::specs::mm::frame::mapping::{frame_to_index, meta_to_frame, META_SLOT_SIZE};
16use crate::specs::mm::frame::meta_owners::*;
17use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
18use crate::specs::mm::page_table::owners::INC_LEVELS;
19use crate::specs::mm::page_table::GuardPerm;
20
21use vstd_extra::array_ptr;
22use vstd_extra::cast_ptr::Repr;
23use vstd_extra::ghost_tree::TreePath;
24use vstd_extra::ownership::*;
25
26verus! {
27
28pub tracked struct PageMetaOwner {
29    pub nr_children: pcell_maybe_uninit::PointsTo<u16>,
30    pub stray: pcell_maybe_uninit::PointsTo<bool>,
31}
32
33impl Inv for PageMetaOwner {
34    open spec fn inv(self) -> bool {
35        &&& self.nr_children.is_init()
36        &&& 0 <= self.nr_children.value() <= NR_ENTRIES
37        &&& self.stray.is_init()
38    }
39}
40
41pub ghost struct PageMetaModel {
42    pub nr_children: u16,
43    pub stray: bool,
44}
45
46impl Inv for PageMetaModel {
47    open spec fn inv(self) -> bool {
48        true
49    }
50}
51
52impl View for PageMetaOwner {
53    type V = PageMetaModel;
54
55    open spec fn view(&self) -> <Self as View>::V {
56        PageMetaModel { nr_children: self.nr_children.value(), stray: self.stray.value() }
57    }
58}
59
60impl InvView for PageMetaOwner {
61    proof fn view_preserves_inv(self) {
62    }
63}
64
65impl<C: PageTableConfig> OwnerOf for PageTablePageMeta<C> {
66    type Owner = PageMetaOwner;
67
68    open spec fn wf(self, owner: Self::Owner) -> bool {
69        &&& self.nr_children.id() == owner.nr_children.id()
70        &&& self.stray.id() == owner.stray.id()
71        &&& 0 <= owner.nr_children.value() <= NR_ENTRIES
72    }
73}
74
75pub tracked struct NodeOwner<C: PageTableConfig> {
76    pub meta_own: PageMetaOwner,
77    pub meta_perm: MetaPerm<PageTablePageMeta<C>>,
78    pub children_perm: array_ptr::PointsTo<C::E, NR_ENTRIES>,
79    pub level: PagingLevel,
80    pub tree_level: int,
81}
82
83impl<C: PageTableConfig> Inv for NodeOwner<C> {
84    open spec fn inv(self) -> bool {
85        &&& self.meta_perm.points_to.is_init()
86        &&& self.meta_perm.addr() == self.meta_perm.points_to.addr()
87        &&& self.meta_own.inv()
88        &&& self.meta_perm.value().metadata.wf(self.meta_own)
89        &&& self.meta_perm.is_init()
90        &&& self.meta_perm.wf(&self.meta_perm.inner_perms)
91        &&& FRAME_METADATA_RANGE.start <= self.meta_perm.addr() < FRAME_METADATA_RANGE.end
92        &&& self.meta_perm.addr() % META_SLOT_SIZE == 0
93        &&& meta_to_frame(self.meta_perm.addr()) < VMALLOC_BASE_VADDR - LINEAR_MAPPING_BASE_VADDR
94        &&& meta_to_frame(self.meta_perm.addr()) < MAX_PADDR
95        &&& meta_to_frame(self.meta_perm.addr()) == self.children_perm.addr()
96        &&& self.meta_own.nr_children.id() == self.meta_perm.value().metadata.nr_children.id()
97        &&& 0 <= self.meta_own.nr_children.value() <= NR_ENTRIES
98        &&& 1 <= self.level <= NR_LEVELS
99        &&& self.children_perm.is_init_all()
100        &&& self.children_perm.addr() == paddr_to_vaddr(meta_to_frame(self.meta_perm.addr()))
101        &&& self.level == self.meta_perm.value().metadata.level
102        &&& self.tree_level == INC_LEVELS - self.level - 1
103    }
104}
105
106impl<C: PageTableConfig> NodeOwner<C> {
107    // TODO: this is a bizzare structure; `set_children_perm` needs to actually be
108    // defined to satisfy the axiom, which can then be deleted.
109    pub uninterp spec fn set_children_perm(self, idx: usize, pte: C::E) -> Self;
110
111    #[verifier::external_body]
112    pub axiom fn set_children_perm_axiom(self, idx: usize, pte: C::E)
113        requires
114            self.inv(),
115            idx < NR_ENTRIES,
116        ensures
117            self.set_children_perm(idx, pte).inv(),
118            self.set_children_perm(idx, pte).meta_perm == self.meta_perm,
119            self.set_children_perm(idx, pte).meta_own == self.meta_own,
120            self.set_children_perm(idx, pte).level == self.level,
121            self.set_children_perm(idx, pte).tree_level == self.tree_level,
122            self.set_children_perm(idx, pte).children_perm.addr() == self.children_perm.addr(),
123            self.set_children_perm(idx, pte).children_perm.value()
124                == self.children_perm.value().update(idx as int, pte);
125
126    /// If any slot in `children_perm` holds a non-present PTE, then
127    /// `nr_children < NR_ENTRIES`.
128    ///
129    /// Axiomatizes the intended meaning of `nr_children`: it counts the
130    /// number of *present* PTEs in the node. When at least one slot is
131    /// absent, the count must be strictly less than the maximum. This
132    /// sidesteps a full `nr_children == count(present PTEs)` invariant
133    /// (which would thread through every PTE mutation); the axiom instead
134    /// exposes the single boundary fact that `Entry::replace` needs when
135    /// incrementing the counter.
136    pub axiom fn nr_children_absent_slot_bound(self, idx: usize)
137        requires
138            self.inv(),
139            idx < NR_ENTRIES,
140            !self.children_perm.value()[idx as int].is_present(),
141        ensures
142            self.meta_own.nr_children.value() < NR_ENTRIES;
143
144    /// If any slot in `children_perm` holds a present PTE, then
145    /// `nr_children > 0`. Dual of [`Self::nr_children_absent_slot_bound`];
146    /// used by `Entry::replace` when decrementing the counter.
147    pub axiom fn nr_children_present_slot_bound(self, idx: usize)
148        requires
149            self.inv(),
150            idx < NR_ENTRIES,
151            self.children_perm.value()[idx as int].is_present(),
152        ensures
153            self.meta_own.nr_children.value() > 0;
154}
155
156impl<'rcu, C: PageTableConfig> NodeOwner<C> {
157
158    pub open spec fn relate_guard_perm(self, guard_perm: GuardPerm<'rcu, C>) -> bool {
159        &&& guard_perm.is_init()
160        &&& guard_perm.value().inner.inner@.ptr.addr() == self.meta_perm.addr()
161        &&& guard_perm.value().inner.inner@.ptr.addr() == self.meta_perm.points_to.addr()
162        &&& guard_perm.value().inner.inner@.wf(self)
163        &&& self.meta_perm.is_init()
164        &&& self.meta_perm.wf(&self.meta_perm.inner_perms)
165    }
166}
167
168pub ghost struct NodeModel<C: PageTableConfig> {
169    pub meta: PageTablePageMeta<C>,
170}
171
172impl<C: PageTableConfig> Inv for NodeModel<C> {
173    open spec fn inv(self) -> bool {
174        true
175    }
176}
177
178impl<C: PageTableConfig> View for NodeOwner<C> {
179    type V = NodeModel<C>;
180
181    open spec fn view(&self) -> <Self as View>::V {
182        NodeModel { meta: self.meta_perm.value().metadata }
183    }
184}
185
186impl<C: PageTableConfig> InvView for NodeOwner<C> {
187    proof fn view_preserves_inv(self) {
188    }
189}
190
191impl<C: PageTableConfig> OwnerOf for PageTableNode<C> {
192    type Owner = NodeOwner<C>;
193
194    open spec fn wf(self, owner: Self::Owner) -> bool {
195        &&& self.ptr.addr() == owner.meta_perm.addr()
196    }
197}
198
199impl<C: PageTableConfig> PageTableNode<C> {
200    pub open spec fn invariants(self, owner: NodeOwner<C>) -> bool {
201        &&& owner.inv()
202        &&& self.wf(owner)
203//        &&& owner.meta_perm.wf(&owner.meta_perm.inner_perms)
204//        &&& owner.meta_perm.addr() == self.ptr.addr()
205//        &&& owner.meta_perm.addr() == self.ptr.addr()
206    }
207}
208
209} // verus!