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
34pub use crate::specs::mm::page_table::node::{entry_owners::*, owners::*};
35pub use child::*;
36pub use entry::*;
37
38use vstd::cell::pcell_maybe_uninit;
39use vstd::prelude::*;
40
41use vstd::atomic::PAtomicU8;
42use vstd_extra::array_ptr;
43use vstd_extra::cast_ptr::*;
44use vstd_extra::drop_tracking::{Drop as VerifiedDrop, TrackDrop};
45use vstd_extra::ghost_tree::*;
46use vstd_extra::ownership::*;
47
48use crate::mm::frame::{
49 allocator::FrameAllocOptions,
50 meta::{
51 META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, REF_COUNT_UNUSED,
52 mapping::{frame_to_meta, meta_to_frame},
53 },
54};
55
56use crate::mm::page_table::*;
57use crate::mm::{Paddr, Vaddr};
58use crate::specs::mm::{
59 frame::{
60 mapping::{frame_to_index, lemma_frame_to_index_injective},
61 meta_owners::{MetaSlotOwner, MetaSlotStorage, Metadata},
62 meta_region_owners::MetaRegionOwners,
63 },
64 page_table::node::owners::*,
65};
66
67use core::{marker::PhantomData, ops::Deref, sync::atomic::Ordering};
68
69use super::{PageTableConfig, PageTableEntryTrait, nr_subpage_per_huge};
70
71use crate::{
72 mm::{
73 PagingConstsTrait,
74 PagingLevel,
75 frame::{Frame, FrameRef, meta::AnyFrameMeta},
78 paddr_to_vaddr,
79 page_table::{load_pte, store_pte},
80 },
81 specs::task::InAtomicMode,
82};
83
84verus! {
85
86pub struct PageTablePageMeta<C: PageTableConfig> {
89 pub nr_children: pcell_maybe_uninit::PCell<u16>,
91 pub stray: pcell_maybe_uninit::PCell<bool>,
97 pub level: PagingLevel,
100 pub lock: PAtomicU8,
102 pub _phantom: core::marker::PhantomData<C>,
103}
104
105pub type PageTableNode<C> = Frame<PageTablePageMeta<C>>;
115
116unsafe impl<C: PageTableConfig> AnyFrameMeta for PageTablePageMeta<C> {
117 open spec fn on_drop_pre(
137 &self,
138 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
139 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
140 vm_io_owner: crate::specs::mm::io::VmIoOwner,
141 ) -> bool {
142 &&& reader.inv()
143 &&& reader.wf(vm_io_owner)
144 &&& reader.remain_spec() >= crate::specs::arch::PAGE_SIZE
145 &&& reader.cursor.vaddr % core::mem::align_of::<C::E>() == 0
146 &&& vm_io_owner.inv()
147 &&& vm_io_owner.read_view_initialized()
148 &&& regions.inv()
149 &&& Self::child_perms_embedding(regions, vstd::set::Set::empty())
150 &&& self.walk_coverage_from_view(reader, vm_io_owner.read_view_of(), regions.slots.dom())
151 &&& self.walk_items_well_formed_from_view(reader, vm_io_owner.read_view_of())
152 &&& self.walk_uniqueness_from_view(reader, vm_io_owner.read_view_of())
153 }
154
155 #[verifier::spinoff_prover]
158 fn on_drop(
159 &mut self,
160 reader: &mut crate::mm::VmReader<'_, crate::mm::Infallible>,
161 Tracked(regions): Tracked<
162 &mut crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
163 >,
164 Tracked(vm_io_owner): Tracked<&mut crate::specs::mm::io::VmIoOwner>,
165 ) {
166 let level = self.level;
167 let range = if level == C::NR_LEVELS() {
168 C::TOP_LEVEL_INDEX_RANGE()
169 } else {
170 0..nr_subpage_per_huge::<C>()
171 };
172
173 proof {
174 C::lemma_paging_consts_properties();
175 C::lemma_page_table_config_constant_properties();
176 vstd::arithmetic::mul::lemma_mul_inequality(
177 range.start as int,
178 NR_ENTRIES as int,
179 core::mem::size_of::<C::E>() as int,
180 );
181 }
182
183 let ghost size_of_e: int = core::mem::size_of::<C::E>() as int;
184 let ghost align_of_e: int = core::mem::align_of::<C::E>() as int;
185 let ghost pre_skip_cursor: int = reader.cursor.vaddr as int;
186
187 let ghost initial_view: crate::specs::mm::virt_mem::MemView = vm_io_owner.read_view_of();
188 let ghost initial_dom: vstd::set::Set<int> = regions.slots.dom();
189 let ghost initial_reader: crate::mm::VmReader<'_, crate::mm::Infallible> = *reader;
190
191 #[verus_spec(with Tracked(vm_io_owner))]
192 reader.skip_in_place(range.start * core::mem::size_of::<C::E>());
193
194 proof {
195 C::E::lemma_page_table_entry_properties();
196 let k = size_of_e / align_of_e;
197 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(size_of_e, align_of_e);
198 vstd::arithmetic::mul::lemma_mul_is_commutative(align_of_e, k);
199 vstd::arithmetic::mul::lemma_mul_is_associative(range.start as int, k, align_of_e);
200 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(range.start * k, align_of_e);
201 vstd::arithmetic::div_mod::lemma_mod_adds(
202 pre_skip_cursor,
203 range.start * size_of_e,
204 align_of_e,
205 );
206 }
207
208 let ghost post_skip_remain: int = reader.remain_spec() as int;
209 let ghost range_start: int = range.start as int;
210 let ghost range_end: int = range.end as int;
211 let n_iters: usize = range.end - range.start;
212 let mut iter_count: usize = 0;
213 let ghost mut removed_indices: vstd::set::Set<int> = vstd::set::Set::empty();
214
215 proof {
216 C::lemma_page_table_config_constant_properties();
217 C::lemma_paging_consts_properties();
218 vstd::arithmetic::mul::lemma_mul_is_distributive_sub_other_way(
219 size_of_e,
220 NR_ENTRIES as int,
221 range_start,
222 );
223 vstd::arithmetic::mul::lemma_mul_inequality(
224 range_end - range_start,
225 NR_ENTRIES - range_start,
226 size_of_e,
227 );
228 }
229
230 while iter_count < n_iters
231 invariant
232 reader.inv(),
233 reader.wf(*vm_io_owner),
234 vm_io_owner.inv(),
235 vm_io_owner.read_view_initialized(),
236 regions.inv(),
237 reader.cursor.vaddr as int % align_of_e == 0,
238 size_of_e == core::mem::size_of::<C::E>(),
239 align_of_e == core::mem::align_of::<C::E>(),
240 size_of_e % align_of_e == 0,
241 align_of_e > 0,
242 size_of_e > 0,
243 iter_count <= n_iters,
244 n_iters == range_end - range_start,
245 0 <= range_start,
249 range_start <= range_end,
250 range_end <= NR_ENTRIES,
251 reader.remain_spec() == post_skip_remain - iter_count * size_of_e,
252 post_skip_remain >= (range_end - range_start) * size_of_e,
253 regions.slots.dom() == initial_dom,
254 Self::child_perms_embedding(*regions, removed_indices),
255 self.walk_coverage_from_view(initial_reader, initial_view, initial_dom),
256 self.walk_items_well_formed_from_view(initial_reader, initial_view),
257 self.walk_uniqueness_from_view(initial_reader, initial_view),
258 self.level == level,
262 reader.end == initial_reader.end,
263 reader.cursor.vaddr == initial_reader.cursor.vaddr + range_start * size_of_e
264 + iter_count * size_of_e,
265 forall|i: usize|
266 #![trigger initial_view.addr_transl(i)]
267 initial_reader.cursor.vaddr <= i < initial_reader.end.vaddr ==> {
268 &&& initial_view.addr_transl(i) is Some
269 &&& initial_view.memory.contains_key(initial_view.addr_transl(i).unwrap().0)
270 },
271 forall|va: usize|
272 #![trigger vm_io_owner.read_view_of().read(va)]
273 reader.cursor.vaddr <= va < initial_reader.end.vaddr ==> {
274 &&& initial_view.addr_transl(va) == vm_io_owner.read_view_of().addr_transl(
275 va,
276 )
277 &&& initial_view.read(va) == vm_io_owner.read_view_of().read(va)
278 },
279 removed_indices.subset_of(initial_dom),
280 forall|idx: int| #[trigger]
284 removed_indices.contains(idx) ==> exists|j: int|
285 #![trigger Self::walk_pte_at_view(
286 initial_view,
287 (initial_reader.cursor.vaddr
288 + range_start * size_of_e
289 + j * size_of_e) as usize,
290 )]
291 0 <= j < iter_count && {
292 let cj = (initial_reader.cursor.vaddr + range_start * size_of_e + j
293 * size_of_e) as usize;
294 let pte_j = Self::walk_pte_at_view(initial_view, cj);
295 &&& pte_j.is_present()
296 &&& !pte_j.is_last(self.level)
297 &&& idx == frame_to_index(pte_j.paddr())
298 },
299 decreases n_iters - iter_count,
300 {
301 proof {
302 vstd::arithmetic::mul::lemma_mul_is_distributive_sub(
303 size_of_e,
304 range_end - range_start,
305 iter_count as int,
306 );
307 vstd::arithmetic::mul::lemma_mul_inequality(
308 1,
309 range_end - range_start - iter_count,
310 size_of_e,
311 );
312 }
313 let ghost cursor_pre_read: usize = reader.cursor.vaddr;
314 let ghost pre_view: crate::specs::mm::virt_mem::MemView = vm_io_owner.read_view_of();
315 proof {
316 crate::specs::mm::virt_mem::MemView::lemma_read_bytes_eq_pointwise(
317 pre_view,
318 initial_view,
319 cursor_pre_read,
320 core::mem::size_of::<C::E>(),
321 );
322 }
323 let pte = #[verus_spec(with Tracked(vm_io_owner))]
324 reader.read_once::<C::E>();
325 let pte = pte.unwrap();
326 proof {
327 ostd_pod::lemma_decode_pod_inverse::<C::E>(pte);
328 vstd::arithmetic::mul::lemma_mul_nonnegative(range_start, size_of_e);
329 vstd::arithmetic::mul::lemma_mul_nonnegative(iter_count as int, size_of_e);
330 }
331 if pte.is_present() {
332 let paddr = pte.paddr();
333 if !pte.is_last(level) {
334 proof {
335 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
336 size_of_e,
337 range_start,
338 iter_count as int,
339 );
340 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(
341 range_start + iter_count,
342 size_of_e,
343 );
344 Self::lemma_coverage_at(
345 *self,
346 initial_reader,
347 initial_view,
348 initial_dom,
349 cursor_pre_read,
350 );
351 broadcast use lemma_frame_to_index_injective;
352
353 assert forall|idx: int| #[trigger] removed_indices.contains(idx) implies idx
354 != frame_to_index(pte.paddr()) by {
355 let j = choose|j: int|
356 #![trigger Self::walk_pte_at_view(
357 initial_view,
358 (initial_reader.cursor.vaddr
359 + range_start * size_of_e
360 + j * size_of_e) as usize,
361 )]
362 0 <= j < iter_count && {
363 let cj = (initial_reader.cursor.vaddr + range_start * size_of_e
364 + j * size_of_e) as usize;
365 let pte_j = Self::walk_pte_at_view(initial_view, cj);
366 &&& pte_j.is_present()
367 &&& !pte_j.is_last(self.level)
368 &&& idx == frame_to_index(pte_j.paddr())
369 };
370 let cj: usize = (initial_reader.cursor.vaddr + range_start * size_of_e
371 + j * size_of_e) as usize;
372 let pte_j = Self::walk_pte_at_view(initial_view, cj);
373 vstd::arithmetic::mul::lemma_mul_nonnegative(range_start, size_of_e);
374 vstd::arithmetic::mul::lemma_mul_nonnegative(j, size_of_e);
375 vstd::arithmetic::mul::lemma_mul_strict_inequality(
376 j,
377 iter_count as int,
378 size_of_e,
379 );
380 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
381 size_of_e,
382 range_start,
383 j,
384 );
385 vstd::arithmetic::mul::lemma_mul_inequality(
386 range_start + j + 1,
387 range_end,
388 size_of_e,
389 );
390 vstd::arithmetic::mul::lemma_mul_is_distributive_sub_other_way(
391 size_of_e,
392 range_end,
393 range_start,
394 );
395 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(
396 range_start + j,
397 size_of_e,
398 );
399 Self::lemma_uniqueness_at_pair(
400 *self,
401 initial_reader,
402 initial_view,
403 cursor_pre_read,
404 cj,
405 );
406 pte.lemma_paddr_is_page_aligned();
407 pte_j.lemma_paddr_is_page_aligned();
408 };
409 }
413 proof {
414 removed_indices = removed_indices.insert(frame_to_index(paddr));
415 assert({
416 let cj = (initial_reader.cursor.vaddr + range_start * size_of_e
417 + iter_count * size_of_e) as usize;
418 let pte_j = Self::walk_pte_at_view(initial_view, cj);
419 &&& cj == cursor_pre_read
420 &&& pte_j == pte
421 &&& pte_j.is_present()
422 &&& !pte_j.is_last(self.level)
423 &&& frame_to_index(paddr) == frame_to_index(pte_j.paddr())
424 });
425 }
426 proof_decl! {
427 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<int>;
428 }
429 let frame = unsafe {
430 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
431 Frame::<Self>::from_raw(paddr)
432 };
433 VerifiedDrop::drop(frame, Tracked(regions), Tracked(from_raw_obl));
436 } else {
437 proof {
440 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
441 size_of_e,
442 range_start,
443 iter_count as int,
444 );
445 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(
446 range_start + iter_count,
447 size_of_e,
448 );
449 Self::lemma_item_well_formed_at(
450 *self,
451 initial_reader,
452 initial_view,
453 cursor_pre_read,
454 );
455 assert(C::raw_item_well_formed(paddr, level, pte.prop()));
456 }
457 let _item = unsafe { C::item_from_raw(paddr, level, pte.prop()) };
458 }
459 }
460 proof {
461 vstd::arithmetic::div_mod::lemma_mod_adds(
462 reader.cursor.vaddr - size_of_e,
463 size_of_e,
464 align_of_e,
465 );
466 }
467 let ghost iter_count_old: int = iter_count as int;
468 iter_count = iter_count + 1;
469 proof {
470 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
471 size_of_e,
472 iter_count_old,
473 1,
474 );
475 }
476 }
477 }
478
479 fn is_untyped(&self) -> bool {
480 false
481 }
482
483 uninterp spec fn vtable_ptr(&self) -> usize;
484}
485
486#[verus_verify]
487impl<C: PageTableConfig> PageTableNode<C> {
488 #[verus_spec(
497 with Tracked(perm) : Tracked<&PointsTo<MetaSlot, Metadata<PageTablePageMeta<C>>>>
498 )]
499 pub(super) fn level(&self) -> PagingLevel
500 requires
501 self.ptr.addr() == perm.addr(),
502 self.ptr.addr() == perm.points_to.addr(),
503 perm.is_init(),
504 perm.wf(&perm.inner_perms),
505 returns
506 perm.value().metadata.level,
507 {
508 #[verus_spec(with Tracked(perm))]
509 let meta = self.meta();
510 meta.level
511 }
512
513 #[verus_spec(res =>
515 with Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
516 Tracked(regions): Tracked<&mut MetaRegionOwners>,
517 Tracked(guards): Tracked<&Guards<'rcu>>,
518 Ghost(idx): Ghost<usize>,
519 -> owner: Tracked<OwnerSubtree<C>>,
520 requires
521 1 <= level < NR_LEVELS,
522 idx < NR_ENTRIES,
523 old(regions).inv(),
524 old(parent_owner).inv(),
525 ensures
526 final(regions).inv(),
527 final(parent_owner).inv(),
528 allocated_empty_node_owner(owner@, level),
529 allocated_empty_node_grandchildren_none(owner@),
530 res.ptr.addr() == owner@.value().node().meta_vaddr(),
531 guards.unlocked(owner@.value().node().meta_vaddr()),
532 MetaSlot::get_node_from_unused_spec(meta_to_frame(owner@.value().node().meta_vaddr()), *old(regions), *final(regions)),
533 MetaSlot::slot_perm_reparked_spec(meta_to_frame(owner@.value().node().meta_vaddr()), *old(regions), *final(regions)),
534
535 final(regions).frame_obligations == old(regions).frame_obligations.insert(
536 frame_to_index(meta_to_frame(owner@.value().node().meta_vaddr()))),
537 old(regions).slots.contains_key(frame_to_index(meta_to_frame(owner@.value().node().meta_vaddr()))),
538
539 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
540 meta_to_frame(owner@.value().node().meta_vaddr())),
541 owner@.value().metaregion_sound(*final(regions)),
542 forall|i: int|
543 #[trigger] old(regions).slot_owners[i].inner_perms.ref_count.value() != REF_COUNT_UNUSED
544 ==> i != frame_to_index(meta_to_frame(owner@.value().node().meta_vaddr())),
545 owner@.value().match_pte(C::E::new_pt_spec(meta_to_frame(owner@.value().node().meta_vaddr())), level as PagingLevel),
546 final(parent_owner).meta_own == old(parent_owner).meta_own,
547 final(parent_owner).slot_index == old(parent_owner).slot_index,
548 final(parent_owner).level == old(parent_owner).level,
549 final(parent_owner).tree_level == old(parent_owner).tree_level,
550 final(parent_owner).children_perm.addr() == old(parent_owner).children_perm.addr(),
551 final(parent_owner).children_perm.value() == old(parent_owner).children_perm.value().update(
552 idx as int,
553 C::E::new_pt_spec(meta_to_frame(owner@.value().node().meta_vaddr())),
554 ),
555 final(regions).slots.contains_key(owner@.value().node().slot_index),
556 owner@.value().node().metaregion_sound_node(*final(regions)),
557 )]
558 #[verifier::external_body]
559 pub fn alloc<'rcu>(level: PagingLevel) -> Self {
560 let tracked entry_owner = EntryOwner::tracked_new_absent(
561 TreePath::new(Seq::empty()),
562 level,
563 );
564
565 let tracked mut owner = OwnerSubtree::<C>::tracked_new_val(entry_owner, level as nat);
566 let meta = PageTablePageMeta::new(level);
567 let mut frame = FrameAllocOptions::new();
568 frame.zeroed(true);
569 let allocated_frame = frame.alloc_frame_with(meta).expect(
570 "Failed to allocate a page table node",
571 );
572 proof_with!(|= Tracked(owner));
576
577 allocated_frame
578 }}
629
630#[verus_verify]
631impl<'a, C: PageTableConfig> PageTableNodeRef<'a, C> {
632 pub open spec fn locks_preserved_except<'rcu>(
633 addr: usize,
634 guards0: Guards<'rcu>,
635 guards1: Guards<'rcu>,
636 ) -> bool {
637 &&& OwnerSubtree::implies(
638 CursorOwner::<'rcu, C>::node_unlocked(guards0),
639 CursorOwner::<'rcu, C>::node_unlocked_except(guards1, addr),
640 )
641 &&& forall|i: usize| guards0.lock_held(i) ==> guards1.lock_held(i)
642 &&& forall|i: usize| guards0.unlocked(i) && i != addr ==> guards1.unlocked(i)
643 }
644
645 #[verifier::external_body]
654 #[verus_spec(res =>
655 with Tracked(owner): Tracked<&NodeOwner<C>>,
656 Tracked(guards): Tracked<&mut Guards<'rcu>>
657 requires
658 self.inner@.invariants(*owner),
659 old(guards).unlocked(owner.meta_vaddr()),
660 ensures
661 final(guards).lock_held(owner.meta_vaddr()),
662 Self::locks_preserved_except(owner.meta_vaddr(), *old(guards), *final(guards)),
663 owner.relate_guard(res),
664 )]
665 pub fn lock<'rcu, A: InAtomicMode>(self, _guard: &'rcu A) -> PageTableGuard<'rcu, C> where
666 'a: 'rcu,
667 {
668 unimplemented!()
669 }
670
671 #[verus_spec(res =>
680 with Tracked(owner): Tracked<&NodeOwner<C>>,
681 Tracked(guards): Tracked<&mut Guards<'rcu>>,
682 requires
683 self.inner@.invariants(*owner),
684 old(guards).unlocked(owner.meta_vaddr()),
685 ensures
686 final(guards).lock_held(owner.meta_vaddr()),
687 Self::locks_preserved_except(owner.meta_vaddr(), *old(guards), *final(guards)),
688 owner.relate_guard(res),
689 )]
690 pub unsafe fn make_guard_unchecked<'rcu, A: InAtomicMode>(
691 self,
692 _guard: &'rcu A,
693 ) -> PageTableGuard<'rcu, C> where 'a: 'rcu {
694 let guard = PageTableGuard { inner: self };
695
696 proof {
697 let ghost guards0 = *guards;
698 guards.guards = guards.guards.insert(owner.meta_vaddr());
699
700 }
701
702 guard
703 }
704}
705
706impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
707 #[verus_spec(res =>
714 with Tracked(owner): Tracked<&NodeOwner<C>>,
715 Tracked(child_owner): Tracked<&EntryOwner<C>>,
716 Tracked(regions): Tracked<&MetaRegionOwners>,
717 requires
718 owner.inv(),
719 child_owner.inv(),
720 owner.relate_guard(*old(self)),
721 child_owner.match_pte(
722 owner.children_perm.value()[idx as int],
723 child_owner.parent_level,
724 ),
725 regions.inv(),
726 regions.slots.contains_key(owner.slot_index),
727 idx < NR_ENTRIES,
729 ensures
730 res.wf(*child_owner),
731 res.idx == idx,
732 *res.node == *old(self),
733 *final(self) == *final(res.node),
734 owner.relate_guard(*res.node),
735 )]
736 pub fn entry<'a>(&'a mut self, idx: usize) -> Entry<'a, 'rcu, C> {
737 #[cfg(feature = "allow_panic")]
738 assert!(idx < nr_subpage_per_huge::<C>());
739 unsafe {
742 #[verus_spec(with Tracked(child_owner), Tracked(owner), Tracked(regions))]
743 Entry::new_at(self, idx)
744 }
745 }
746
747 #[verus_spec(nr =>
756 with Tracked(owner) : Tracked<&NodeOwner<C>>,
757 Tracked(regions): Tracked<&MetaRegionOwners>,
758 requires
759 self.inner.inner@.invariants(*owner),
760 regions.inv(),
761 owner.metaregion_sound_node(*regions),
762 returns
763 owner.meta_own.nr_children.value(),
764 )]
765 pub fn nr_children(&self) -> u16 {
766 let tracked owner_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
767 owner.slot_index,
768 );
769 #[verus_spec(with Tracked(owner_meta_perm))]
770 let meta = self.meta();
771
772 *meta.nr_children.borrow(Tracked(&owner.meta_own.nr_children))
773 }
774
775 #[verus_spec(res =>
777 with
778 Tracked(meta_perm): Tracked<&'a PointsTo<MetaSlot, Metadata<PageTablePageMeta<C>>>>,
779 requires
780 old(self).inner.inner@.ptr.addr() == meta_perm.addr(),
781 old(self).inner.inner@.ptr.addr() == meta_perm.points_to.addr(),
782 meta_perm.is_init(),
783 meta_perm.wf(&meta_perm.inner_perms),
784 ensures
785 res.id() == meta_perm.value().metadata.stray.id(),
786 *final(self) == *old(self),
787 )]
788 pub(super) fn stray_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<bool> {
789 #[verus_spec(with Tracked(meta_perm))]
791 let meta = self.meta();
792 &meta.stray
793 }
794
795 #[verus_spec(pte =>
805 with Tracked(owner): Tracked<&NodeOwner<C>>,
806 Tracked(regions): Tracked<&MetaRegionOwners>,
807 requires
808 self.inner.inner@.invariants(*owner),
809 regions.inv(),
810 regions.slots.contains_key(owner.slot_index),
811 idx < NR_ENTRIES,
812 ensures
813 pte == owner.children_perm.value()[idx as int],
814 )]
815 pub unsafe fn read_pte(&self, idx: usize) -> C::E {
816 let tracked owner_slot_perm = regions.slots.tracked_borrow(owner.slot_index);
818 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
819 paddr_to_vaddr(
820 #[verus_spec(with Tracked(owner_slot_perm))]
821 self.start_paddr(),
822 ),
823 );
824
825 unsafe {
829 #[verus_spec(with Tracked(&owner.children_perm))]
830 load_pte(ptr.add(idx), Ordering::Relaxed)
831 }
832 }
833
834 #[verus_spec(
847 with Tracked(owner): Tracked<&mut NodeOwner<C>>,
848 Tracked(regions): Tracked<&MetaRegionOwners>,
849 requires
850 old(self).inner.inner@.invariants(*old(owner)),
851 regions.inv(),
852 regions.slots.contains_key(old(owner).slot_index),
853 idx < NR_ENTRIES,
854 ensures
855 final(owner).inv(),
856 final(owner).level == old(owner).level,
857 final(owner).meta_own == old(owner).meta_own,
858 final(owner).slot_index == old(owner).slot_index,
859 final(owner).children_perm.value() == old(owner).children_perm.value().update(
860 idx as int,
861 pte,
862 ),
863 *final(self) == *old(self),
864 )]
865 pub unsafe fn write_pte(&mut self, idx: usize, pte: C::E) {
866 let tracked owner_slot_perm = regions.slots.tracked_borrow(owner.slot_index);
868 #[verusfmt::skip]
869 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
870 paddr_to_vaddr(
871 #[verus_spec(with Tracked(owner_slot_perm))]
872 self.start_paddr()
873 ),
874 );
875
876 unsafe {
880 #[verus_spec(with Tracked(&mut owner.children_perm))]
881 store_pte(ptr.add(idx), pte, Ordering::Release)
882 }
883 }
884
885 #[verus_spec(res =>
887 with
888 Tracked(meta_perm): Tracked<&'a PointsTo<MetaSlot, Metadata<PageTablePageMeta<C>>>>,
889 requires
890 old(self).inner.inner@.ptr.addr() == meta_perm.addr(),
891 old(self).inner.inner@.ptr.addr() == meta_perm.points_to.addr(),
892 meta_perm.is_init(),
893 meta_perm.wf(&meta_perm.inner_perms),
894 ensures
895 res.id() == meta_perm.value().metadata.nr_children.id(),
896 *final(self) == *old(self),
897 )]
898 fn nr_children_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<u16> {
899 #[verus_spec(with Tracked(meta_perm))]
901 let meta = self.meta();
902 &meta.nr_children
903 }
904}
905
906impl<C: PageTableConfig> PageTablePageMeta<C> {
913 pub fn new(level: PagingLevel) -> Self {
914 Self {
915 nr_children: pcell_maybe_uninit::PCell::new(0).0,
916 stray: pcell_maybe_uninit::PCell::new(false).0,
917 level,
918 lock: PAtomicU8::new(0).0,
919 _phantom: PhantomData,
920 }
921 }
922
923 pub open spec fn walk_pte_at_view(view: crate::specs::mm::virt_mem::MemView, c: usize) -> C::E {
928 ostd_pod::decode_pod::<C::E>(view.read_bytes(c, core::mem::size_of::<C::E>()))
929 }
930
931 pub open spec fn walk_coverage_at(
936 self,
937 view: crate::specs::mm::virt_mem::MemView,
938 dom: vstd::set::Set<int>,
939 c: usize,
940 ) -> bool {
941 let pte = Self::walk_pte_at_view(view, c);
942 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(frame_to_index(pte.paddr()))
943 }
944
945 pub proof fn lemma_coverage_at(
947 self,
948 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
949 view: crate::specs::mm::virt_mem::MemView,
950 dom: vstd::set::Set<int>,
951 c: usize,
952 )
953 requires
954 self.walk_coverage_from_view(reader, view, dom),
955 reader.cursor.vaddr <= c,
956 c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
957 (c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
958 ensures
959 self.walk_coverage_at(view, dom, c),
960 {
961 }
962
963 pub proof fn lemma_item_well_formed_at(
965 self,
966 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
967 view: crate::specs::mm::virt_mem::MemView,
968 c: usize,
969 )
970 requires
971 self.walk_items_well_formed_from_view(reader, view),
972 reader.cursor.vaddr <= c,
973 c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
974 (c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
975 ensures
976 ({
977 let pte = Self::walk_pte_at_view(view, c);
978 pte.is_present() && pte.is_last(self.level) ==> C::raw_item_well_formed(
979 pte.paddr(),
980 self.level,
981 pte.prop(),
982 )
983 }),
984 {
985 }
986
987 pub proof fn lemma_uniqueness_at_pair(
989 self,
990 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
991 view: crate::specs::mm::virt_mem::MemView,
992 c1: usize,
993 c2: usize,
994 )
995 requires
996 self.walk_uniqueness_from_view(reader, view),
997 reader.cursor.vaddr <= c1,
998 c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
999 (c1 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
1000 reader.cursor.vaddr <= c2,
1001 c2 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
1002 (c2 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
1003 c1 != c2,
1004 Self::walk_pte_at_view(view, c1).is_present(),
1005 !Self::walk_pte_at_view(view, c1).is_last(self.level),
1006 Self::walk_pte_at_view(view, c2).is_present(),
1007 !Self::walk_pte_at_view(view, c2).is_last(self.level),
1008 ensures
1009 Self::walk_pte_at_view(view, c1).paddr() != Self::walk_pte_at_view(view, c2).paddr(),
1010 {
1011 }
1012
1013 pub open spec fn walk_coverage_from_view(
1019 self,
1020 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
1021 view: crate::specs::mm::virt_mem::MemView,
1022 dom: vstd::set::Set<int>,
1023 ) -> bool {
1024 forall|c: usize|
1025 #![trigger Self::walk_pte_at_view(view, c)]
1026 reader.cursor.vaddr <= c && c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
1027 + reader.remain_spec() && (c - reader.cursor.vaddr) % core::mem::size_of::<
1028 C::E,
1029 >() as int == 0 ==> {
1030 let pte = Self::walk_pte_at_view(view, c);
1031 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(
1032 frame_to_index(pte.paddr()),
1033 )
1034 }
1035 }
1036
1037 pub open spec fn walk_items_well_formed_from_view(
1040 self,
1041 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
1042 view: crate::specs::mm::virt_mem::MemView,
1043 ) -> bool {
1044 forall|c: usize|
1045 #![trigger Self::walk_pte_at_view(view, c)]
1046 reader.cursor.vaddr <= c && c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
1047 + reader.remain_spec() && (c - reader.cursor.vaddr) % core::mem::size_of::<
1048 C::E,
1049 >() as int == 0 ==> {
1050 let pte = Self::walk_pte_at_view(view, c);
1051 pte.is_present() && pte.is_last(self.level) ==> C::raw_item_well_formed(
1052 pte.paddr(),
1053 self.level,
1054 pte.prop(),
1055 )
1056 }
1057 }
1058
1059 pub open spec fn walk_uniqueness_from_view(
1062 self,
1063 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
1064 view: crate::specs::mm::virt_mem::MemView,
1065 ) -> bool {
1066 forall|c1: usize, c2: usize|
1067 #![trigger Self::walk_pte_at_view(view, c1), Self::walk_pte_at_view(view, c2)]
1068 reader.cursor.vaddr <= c1 && c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
1069 + reader.remain_spec() && (c1 - reader.cursor.vaddr) % core::mem::size_of::<
1070 C::E,
1071 >() as int == 0 && reader.cursor.vaddr <= c2 && c2 + core::mem::size_of::<C::E>()
1072 <= reader.cursor.vaddr + reader.remain_spec() && (c2 - reader.cursor.vaddr)
1073 % core::mem::size_of::<C::E>() as int == 0 && c1 != c2 ==> {
1074 let pte1 = Self::walk_pte_at_view(view, c1);
1075 let pte2 = Self::walk_pte_at_view(view, c2);
1076 pte1.is_present() && !pte1.is_last(self.level) && pte2.is_present()
1077 && !pte2.is_last(self.level) ==> pte1.paddr() != pte2.paddr()
1078 }
1079 }
1080
1081 pub open spec fn child_perms_embedding(
1086 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
1087 excluded: vstd::set::Set<int>,
1088 ) -> bool {
1089 forall|paddr: crate::mm::Paddr|
1090 #![trigger regions.slot_owners[frame_to_index(paddr)]]
1091 regions.slots.dom().contains(frame_to_index(paddr)) && !excluded.contains(
1092 frame_to_index(paddr),
1093 ) ==> {
1094 let idx = frame_to_index(paddr);
1095 let so = regions.slot_owners[idx];
1096 &&& <Frame<Self>>::from_raw_requires_safety(
1097 regions,
1098 paddr,
1099 )
1100 &&& so.inner_perms.ref_count.value() > 0
1102 &&& so.inner_perms.ref_count.value() != REF_COUNT_UNUSED
1103 &&& so.inner_perms.ref_count.value() <= REF_COUNT_MAX
1104 &&& so.inner_perms.ref_count.value() == 1 ==> {
1105 &&& so.inner_perms.storage.is_init()
1106 &&& so.inner_perms.in_list.value() == 0
1107 &&& so.paths_in_pt.is_empty()
1108 }
1109 }
1114 }
1115}
1116
1117}