ostd/specs/mm/page_table/node/
owners.rs1use vstd::{
2 cell::{self, pcell_maybe_uninit},
3 prelude::*,
4 simple_pptr::*,
5};
6use vstd_extra::{array_ptr, ownership::*};
7
8use crate::specs::{
9 arch::*,
10 mm::{
11 frame::{mapping::*, meta_owners::*, meta_region_owners::MetaRegionOwners},
12 page_table::owners::INC_LEVELS,
13 },
14};
15
16use crate::arch::mm::PagingConsts;
17use crate::mm::{
18 Paddr, PagingConstsTrait, PagingLevel, Vaddr,
19 frame::meta::{META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, mapping::meta_to_frame},
20 kspace::{FRAME_METADATA_RANGE, LINEAR_MAPPING_BASE_VADDR, VMALLOC_BASE_VADDR},
21 paddr_to_vaddr,
22 page_table::{PageTableGuard, *},
23};
24
25verus! {
26
27pub open spec fn count_present_upto<E: PageTableEntryTrait>(s: Seq<E>, n: int) -> int
34 decreases n,
35{
36 if n <= 0 {
37 0
38 } else {
39 count_present_upto(s, n - 1) + if s[n - 1].is_present() {
40 1int
41 } else {
42 0int
43 }
44 }
45}
46
47pub open spec fn count_present<E: PageTableEntryTrait>(s: Seq<E>) -> int {
49 count_present_upto(s, s.len() as int)
50}
51
52pub proof fn lemma_count_present_upto_bound<E: PageTableEntryTrait>(s: Seq<E>, n: int)
54 requires
55 0 <= n,
56 ensures
57 0 <= count_present_upto(s, n) <= n,
58 decreases n,
59{
60 if n > 0 {
61 lemma_count_present_upto_bound(s, n - 1);
62 }
63}
64
65pub proof fn lemma_count_present_upto_absent<E: PageTableEntryTrait>(s: Seq<E>, n: int, idx: int)
67 requires
68 0 <= idx < n,
69 !s[idx].is_present(),
70 ensures
71 count_present_upto(s, n) < n,
72 decreases n,
73{
74 lemma_count_present_upto_bound(s, n - 1);
75 if idx < n - 1 {
76 lemma_count_present_upto_absent(s, n - 1, idx);
77 }
78}
79
80pub proof fn lemma_count_present_upto_present<E: PageTableEntryTrait>(s: Seq<E>, n: int, idx: int)
82 requires
83 0 <= idx < n,
84 s[idx].is_present(),
85 ensures
86 count_present_upto(s, n) >= 1,
87 decreases n,
88{
89 lemma_count_present_upto_bound(s, n - 1);
90 if idx < n - 1 {
91 lemma_count_present_upto_present(s, n - 1, idx);
92 }
93}
94
95pub proof fn lemma_count_present_upto_update<E: PageTableEntryTrait>(
98 s: Seq<E>,
99 n: int,
100 idx: int,
101 pte: E,
102)
103 requires
104 0 <= idx < n <= s.len(),
105 ensures
106 count_present_upto(s.update(idx, pte), n) == count_present_upto(s, n) - (
107 if s[idx].is_present() {
108 1int
109 } else {
110 0int
111 }) + (if pte.is_present() {
112 1int
113 } else {
114 0int
115 }),
116 decreases n,
117{
118 let s2 = s.update(idx, pte);
119 if n - 1 == idx {
120 assert(count_present_upto(s2, n - 1) == count_present_upto(s, n - 1)) by {
122 lemma_count_present_upto_unchanged(s, s2, n - 1);
123 }
124 } else {
125 lemma_count_present_upto_update(s, n - 1, idx, pte);
126 }
127}
128
129pub proof fn lemma_count_present_upto_zero_all_absent<E: PageTableEntryTrait>(s: Seq<E>, n: int)
131 requires
132 count_present_upto(s, n) == 0,
133 0 <= n,
134 ensures
135 forall|k: int| 0 <= k < n ==> !#[trigger] s[k].is_present(),
136 decreases n,
137{
138 if n > 0 {
139 lemma_count_present_upto_bound(s, n - 1);
140 lemma_count_present_upto_zero_all_absent(s, n - 1);
141 }
142}
143
144pub proof fn lemma_count_present_upto_unchanged<E: PageTableEntryTrait>(
146 s: Seq<E>,
147 s2: Seq<E>,
148 n: int,
149)
150 requires
151 0 <= n,
152 forall|k: int| 0 <= k < n ==> s[k] == s2[k],
153 ensures
154 count_present_upto(s2, n) == count_present_upto(s, n),
155 decreases n,
156{
157 if n > 0 {
158 lemma_count_present_upto_unchanged(s, s2, n - 1);
159 }
160}
161
162pub tracked struct PageMetaOwner {
163 pub nr_children: pcell_maybe_uninit::PointsTo<u16>,
164 pub stray: pcell_maybe_uninit::PointsTo<bool>,
165}
166
167impl Inv for PageMetaOwner {
168 open spec fn inv(self) -> bool {
169 &&& self.nr_children.is_init()
170 &&& 0 <= self.nr_children.value() <= NR_ENTRIES
171 &&& self.stray.is_init()
172 }
173}
174
175impl<C: PageTableConfig> OwnerOf for PageTablePageMeta<C> {
176 type Owner = PageMetaOwner;
177
178 open spec fn wf(self, owner: Self::Owner) -> bool {
179 &&& self.nr_children.id() == owner.nr_children.id()
180 &&& self.stray.id() == owner.stray.id()
181 &&& 0 <= owner.nr_children.value() <= NR_ENTRIES
182 }
183}
184
185pub tracked struct NodeOwner<C: PageTableConfig> {
197 pub meta_own: PageMetaOwner,
198 pub frame_permission: FracMetadataPerm,
199 pub children_perm: array_ptr::PointsTo<C::E, NR_ENTRIES>,
200 pub ghost tree_level: int,
201 pub ghost slot_index: int,
202}
203
204impl<C: PageTableConfig> Inv for NodeOwner<C> {
205 open spec fn inv(self) -> bool {
206 &&& self.meta_own.inv()
207 &&& self.frame_permission.frac() == 1
208 &&& 1 <= self.level() <= NR_LEVELS
209 &&& self.children_perm.wf()
210 &&& self.children_perm.is_init_all()
211 &&& self.children_perm.addr() == paddr_to_vaddr(
212 meta_to_frame(index_to_meta(self.slot_index)),
213 )
214 &&& self.tree_level == INC_LEVELS - self.level() - 1
215 &&& 0 <= self.slot_index < max_meta_slots()
216 &&& FRAME_METADATA_RANGE.start <= index_to_meta(self.slot_index) < FRAME_METADATA_RANGE.end
217 &&& index_to_meta(self.slot_index) % META_SLOT_SIZE == 0
218 &&& meta_to_frame(index_to_meta(self.slot_index)) < VMALLOC_BASE_VADDR
219 - LINEAR_MAPPING_BASE_VADDR
220 &&& meta_to_frame(index_to_meta(self.slot_index)) < MAX_PADDR
221 }
222}
223
224impl<C: PageTableConfig> NodeOwner<C> {
225 pub proof fn tracked_borrow_frame_metadata_perm(
226 tracked permission: &FracMetadataPerm,
227 ) -> (tracked res: &MetadataPerm)
228 ensures
229 *res == permission.resource(),
230 {
231 permission.tracked_borrow()
232 }
233
234 pub proof fn tracked_borrow_metadata_perm(tracked &self) -> tracked &MetadataPerm
235 returns
236 self.frame_permission.resource(),
237 {
238 self.frame_permission.tracked_borrow()
239 }
240
241 pub open spec fn slot_vaddr(self) -> Vaddr {
243 index_to_meta(self.slot_index)
244 }
245
246 pub open spec fn meta_wf(self, regions: MetaRegionOwners) -> bool {
247 typed_meta_wf::<PageTablePageMeta<C>>(
248 *regions.slots[self.slot_index],
249 self.frame_permission.resource(),
250 (),
251 )
252 }
253
254 pub open spec fn meta_value(self) -> PageTablePageMeta<C> {
255 typed_meta_value::<PageTablePageMeta<C>>(self.frame_permission.resource(), ())
256 }
257
258 pub open spec fn level(self) -> PagingLevel {
259 self.meta_value().level
260 }
261
262 pub open spec fn metaregion_sound_node(self, regions: MetaRegionOwners) -> bool {
266 let idx = self.slot_index;
267 &&& regions.contains(idx)
268 &&& 0 < regions.ref_count(idx) <= REF_COUNT_MAX
269 &&& self.frame_permission.id() == regions.slot_owners[idx].metadata_perm.id()
270 &&& self.meta_wf(regions)
271 &&& self.meta_value().wf(
272 self.meta_own,
273 )
274 &&& regions.slot_owners[self.slot_index].usage is PageTable
281 &&& self.count_consistent()
286 }
287
288 pub open spec fn count_consistent(self) -> bool {
291 self.meta_own.nr_children.value() == count_present(self.children_perm.value())
292 }
293}
294
295impl<C: PageTableConfig> NodeOwner<C> {
296 pub proof fn lemma_nr_children_absent_slot_bound(self, idx: usize)
301 requires
302 self.inv(),
303 self.count_consistent(),
304 self.children_perm.value().len() == NR_ENTRIES,
305 idx < NR_ENTRIES,
306 !self.children_perm.value()[idx as int].is_present(),
307 ensures
308 self.meta_own.nr_children.value() < NR_ENTRIES,
309 {
310 lemma_count_present_upto_absent(self.children_perm.value(), NR_ENTRIES as int, idx as int);
311 }
312
313 pub proof fn nr_children_present_slot_bound(self, idx: usize)
317 requires
318 self.inv(),
319 self.count_consistent(),
320 self.children_perm.value().len() == NR_ENTRIES,
321 idx < NR_ENTRIES,
322 self.children_perm.value()[idx as int].is_present(),
323 ensures
324 self.meta_own.nr_children.value() > 0,
325 {
326 lemma_count_present_upto_present(self.children_perm.value(), NR_ENTRIES as int, idx as int);
327 }
328}
329
330impl<'rcu, C: PageTableConfig> NodeOwner<C> {
331 pub open spec fn relate_guard(self, guard: PageTableGuard<'rcu, C>) -> bool {
332 &&& guard.inner.inner@.wf(self)
333 &&& guard.inner.inner@.external_meta_wf(self.frame_permission.resource(), ())
334 }
335}
336
337impl<C: PageTableConfig> OwnerOf for PageTableNode<C> {
338 type Owner = NodeOwner<C>;
339
340 open spec fn wf(self, owner: Self::Owner) -> bool {
341 &&& self.slot_vaddr() == owner.slot_vaddr()
342 &&& self.ptr_inv()
343 }
344}
345
346impl<C: PageTableConfig> PageTableNode<C> {
347 pub open spec fn invariants(self, owner: NodeOwner<C>) -> bool {
348 &&& owner.inv()
349 &&& self.wf(owner)
350 }
351}
352
353}