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, meta_to_index},
61 meta_owners::{
62 MetaSlotOwner, MetaSlotStorage, MetadataPerms, typed_meta_value, typed_meta_wf,
63 },
64 meta_region_owners::MetaRegionOwners,
65 },
66 page_table::node::owners::*,
67};
68
69use core::{marker::PhantomData, ops::Deref, sync::atomic::Ordering};
70
71use super::{PageTableConfig, PageTableEntryTrait, nr_subpage_per_huge};
72
73use crate::{
74 mm::{
75 PagingConstsTrait,
76 PagingLevel,
77 frame::{Frame, FrameRef, meta::AnyFrameMeta},
80 paddr_to_vaddr,
81 page_table::{load_pte, store_pte},
82 },
83 specs::task::InAtomicMode,
84};
85
86verus! {
87
88pub struct PageTablePageMeta<C: PageTableConfig> {
91 pub nr_children: pcell_maybe_uninit::PCell<u16>,
93 pub stray: pcell_maybe_uninit::PCell<bool>,
99 pub level: PagingLevel,
102 pub lock: PAtomicU8,
104 pub _phantom: core::marker::PhantomData<C>,
105}
106
107pub type PageTableNode<C> = Frame<PageTablePageMeta<C>>;
117
118unsafe impl<C: PageTableConfig> AnyFrameMeta for PageTablePageMeta<C> {
119 open spec fn on_drop_pre(
139 &self,
140 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
141 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
142 vm_io_owner: crate::specs::mm::io::VmIoOwner,
143 ) -> bool {
144 &&& reader.inv()
145 &&& reader.wf(vm_io_owner)
146 &&& reader.remain_spec() >= crate::specs::arch::PAGE_SIZE
147 &&& reader.cursor.vaddr % core::mem::align_of::<C::E>() == 0
148 &&& vm_io_owner.inv()
149 &&& vm_io_owner.read_view_initialized()
150 &&& regions.inv()
151 &&& Self::child_perms_embedding(regions, vstd::set::Set::empty())
152 &&& self.walk_coverage_from_view(reader, vm_io_owner.read_view_of(), regions.slots.dom())
153 &&& self.walk_items_well_formed_from_view(reader, vm_io_owner.read_view_of())
154 &&& self.walk_uniqueness_from_view(reader, vm_io_owner.read_view_of())
155 }
156
157 #[verifier::spinoff_prover]
160 fn on_drop(
161 &mut self,
162 reader: &mut crate::mm::VmReader<'_, crate::mm::Infallible>,
163 Tracked(regions): Tracked<
164 &mut crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
165 >,
166 Tracked(vm_io_owner): Tracked<&mut crate::specs::mm::io::VmIoOwner>,
167 ) {
168 let level = self.level;
169 let range = if level == C::NR_LEVELS() {
170 C::TOP_LEVEL_INDEX_RANGE()
171 } else {
172 0..nr_subpage_per_huge::<C>()
173 };
174
175 proof {
176 C::lemma_paging_consts_properties();
177 C::lemma_page_table_config_constant_properties();
178 vstd::arithmetic::mul::lemma_mul_inequality(
179 range.start as int,
180 NR_ENTRIES as int,
181 core::mem::size_of::<C::E>() as int,
182 );
183 }
184
185 let ghost size_of_e: int = core::mem::size_of::<C::E>() as int;
186 let ghost align_of_e: int = core::mem::align_of::<C::E>() as int;
187 let ghost pre_skip_cursor: int = reader.cursor.vaddr as int;
188
189 let ghost initial_view: crate::specs::mm::virt_mem::MemView = vm_io_owner.read_view_of();
190 let ghost initial_dom: vstd::set::Set<int> = regions.slots.dom();
191 let ghost initial_reader: crate::mm::VmReader<'_, crate::mm::Infallible> = *reader;
192
193 #[verus_spec(with Tracked(vm_io_owner))]
194 reader.skip_in_place(range.start * core::mem::size_of::<C::E>());
195
196 proof {
197 C::E::lemma_page_table_entry_properties();
198 let k = size_of_e / align_of_e;
199 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(size_of_e, align_of_e);
200 vstd::arithmetic::mul::lemma_mul_is_commutative(align_of_e, k);
201 vstd::arithmetic::mul::lemma_mul_is_associative(range.start as int, k, align_of_e);
202 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(range.start * k, align_of_e);
203 vstd::arithmetic::div_mod::lemma_mod_adds(
204 pre_skip_cursor,
205 range.start * size_of_e,
206 align_of_e,
207 );
208 }
209
210 let ghost post_skip_remain: int = reader.remain_spec() as int;
211 let ghost range_start: int = range.start as int;
212 let ghost range_end: int = range.end as int;
213 let n_iters: usize = range.end - range.start;
214 let mut iter_count: usize = 0;
215 let ghost mut removed_indices: vstd::set::Set<int> = vstd::set::Set::empty();
216
217 proof {
218 C::lemma_page_table_config_constant_properties();
219 C::lemma_paging_consts_properties();
220 vstd::arithmetic::mul::lemma_mul_is_distributive_sub_other_way(
221 size_of_e,
222 NR_ENTRIES as int,
223 range_start,
224 );
225 vstd::arithmetic::mul::lemma_mul_inequality(
226 range_end - range_start,
227 NR_ENTRIES - range_start,
228 size_of_e,
229 );
230 }
231
232 while iter_count < n_iters
233 invariant
234 reader.inv(),
235 reader.wf(*vm_io_owner),
236 vm_io_owner.inv(),
237 vm_io_owner.read_view_initialized(),
238 regions.inv(),
239 reader.cursor.vaddr as int % align_of_e == 0,
240 size_of_e == core::mem::size_of::<C::E>(),
241 align_of_e == core::mem::align_of::<C::E>(),
242 size_of_e % align_of_e == 0,
243 align_of_e > 0,
244 size_of_e > 0,
245 iter_count <= n_iters,
246 n_iters == range_end - range_start,
247 0 <= range_start,
251 range_start <= range_end,
252 range_end <= NR_ENTRIES,
253 reader.remain_spec() == post_skip_remain - iter_count * size_of_e,
254 post_skip_remain >= (range_end - range_start) * size_of_e,
255 regions.slots.dom() == initial_dom,
256 Self::child_perms_embedding(*regions, removed_indices),
257 self.walk_coverage_from_view(initial_reader, initial_view, initial_dom),
258 self.walk_items_well_formed_from_view(initial_reader, initial_view),
259 self.walk_uniqueness_from_view(initial_reader, initial_view),
260 self.level == level,
264 reader.end == initial_reader.end,
265 reader.cursor.vaddr == initial_reader.cursor.vaddr + range_start * size_of_e
266 + iter_count * size_of_e,
267 forall|i: usize|
268 #![trigger initial_view.addr_transl(i)]
269 initial_reader.cursor.vaddr <= i < initial_reader.end.vaddr ==> {
270 &&& initial_view.addr_transl(i) is Some
271 &&& initial_view.memory.contains_key(initial_view.addr_transl(i).unwrap().0)
272 },
273 forall|va: usize|
274 #![trigger vm_io_owner.read_view_of().read(va)]
275 reader.cursor.vaddr <= va < initial_reader.end.vaddr ==> {
276 &&& initial_view.addr_transl(va) == vm_io_owner.read_view_of().addr_transl(
277 va,
278 )
279 &&& initial_view.read(va) == vm_io_owner.read_view_of().read(va)
280 },
281 removed_indices.subset_of(initial_dom),
282 forall|idx: int| #[trigger]
286 removed_indices.contains(idx) ==> exists|j: int|
287 #![trigger Self::walk_pte_at_view(
288 initial_view,
289 (initial_reader.cursor.vaddr
290 + range_start * size_of_e
291 + j * size_of_e) as usize,
292 )]
293 0 <= j < iter_count && {
294 let cj = (initial_reader.cursor.vaddr + range_start * size_of_e + j
295 * size_of_e) as usize;
296 let pte_j = Self::walk_pte_at_view(initial_view, cj);
297 &&& pte_j.is_present()
298 &&& !pte_j.is_last(self.level)
299 &&& idx == frame_to_index(pte_j.paddr())
300 },
301 decreases n_iters - iter_count,
302 {
303 proof {
304 vstd::arithmetic::mul::lemma_mul_is_distributive_sub(
305 size_of_e,
306 range_end - range_start,
307 iter_count as int,
308 );
309 vstd::arithmetic::mul::lemma_mul_inequality(
310 1,
311 range_end - range_start - iter_count,
312 size_of_e,
313 );
314 }
315 let ghost cursor_pre_read: usize = reader.cursor.vaddr;
316 let ghost pre_view: crate::specs::mm::virt_mem::MemView = vm_io_owner.read_view_of();
317 proof {
318 crate::specs::mm::virt_mem::MemView::lemma_read_bytes_eq_pointwise(
319 pre_view,
320 initial_view,
321 cursor_pre_read,
322 core::mem::size_of::<C::E>(),
323 );
324 }
325 let pte = #[verus_spec(with Tracked(vm_io_owner))]
326 reader.read_once::<C::E>();
327 let pte = pte.unwrap();
328 proof {
329 ostd_pod::lemma_decode_pod_inverse::<C::E>(pte);
330 vstd::arithmetic::mul::lemma_mul_nonnegative(range_start, size_of_e);
331 vstd::arithmetic::mul::lemma_mul_nonnegative(iter_count as int, size_of_e);
332 }
333 if pte.is_present() {
334 let paddr = pte.paddr();
335 if !pte.is_last(level) {
336 proof {
337 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
338 size_of_e,
339 range_start,
340 iter_count as int,
341 );
342 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(
343 range_start + iter_count,
344 size_of_e,
345 );
346 Self::lemma_coverage_at(
347 *self,
348 initial_reader,
349 initial_view,
350 initial_dom,
351 cursor_pre_read,
352 );
353 broadcast use lemma_frame_to_index_injective;
354
355 assert forall|idx: int| #[trigger] removed_indices.contains(idx) implies idx
356 != frame_to_index(pte.paddr()) by {
357 let j = choose|j: int|
358 #![trigger Self::walk_pte_at_view(
359 initial_view,
360 (initial_reader.cursor.vaddr
361 + range_start * size_of_e
362 + j * size_of_e) as usize,
363 )]
364 0 <= j < iter_count && {
365 let cj = (initial_reader.cursor.vaddr + range_start * size_of_e
366 + j * size_of_e) as usize;
367 let pte_j = Self::walk_pte_at_view(initial_view, cj);
368 &&& pte_j.is_present()
369 &&& !pte_j.is_last(self.level)
370 &&& idx == frame_to_index(pte_j.paddr())
371 };
372 let cj: usize = (initial_reader.cursor.vaddr + range_start * size_of_e
373 + j * size_of_e) as usize;
374 let pte_j = Self::walk_pte_at_view(initial_view, cj);
375 vstd::arithmetic::mul::lemma_mul_nonnegative(range_start, size_of_e);
376 vstd::arithmetic::mul::lemma_mul_nonnegative(j, size_of_e);
377 vstd::arithmetic::mul::lemma_mul_strict_inequality(
378 j,
379 iter_count as int,
380 size_of_e,
381 );
382 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
383 size_of_e,
384 range_start,
385 j,
386 );
387 vstd::arithmetic::mul::lemma_mul_inequality(
388 range_start + j + 1,
389 range_end,
390 size_of_e,
391 );
392 vstd::arithmetic::mul::lemma_mul_is_distributive_sub_other_way(
393 size_of_e,
394 range_end,
395 range_start,
396 );
397 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(
398 range_start + j,
399 size_of_e,
400 );
401 Self::lemma_uniqueness_at_pair(
402 *self,
403 initial_reader,
404 initial_view,
405 cursor_pre_read,
406 cj,
407 );
408 pte.lemma_paddr_is_page_aligned();
409 pte_j.lemma_paddr_is_page_aligned();
410 };
411 }
412 proof {
413 removed_indices = removed_indices.insert(frame_to_index(paddr));
414 assert({
415 let cj = (initial_reader.cursor.vaddr + range_start * size_of_e
416 + iter_count * size_of_e) as usize;
417 let pte_j = Self::walk_pte_at_view(initial_view, cj);
418 &&& cj == cursor_pre_read
419 &&& pte_j == pte
420 &&& pte_j.is_present()
421 &&& !pte_j.is_last(self.level)
422 &&& frame_to_index(paddr) == frame_to_index(pte_j.paddr())
423 });
424 }
425 proof_decl! {
426 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<int>;
427 }
428 let frame = unsafe {
429 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
430 Frame::<Self>::from_raw(paddr)
431 };
432 VerifiedDrop::drop(frame, Tracked(regions), Tracked(from_raw_obl));
435 } else {
436 proof {
439 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
440 size_of_e,
441 range_start,
442 iter_count as int,
443 );
444 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(
445 range_start + iter_count,
446 size_of_e,
447 );
448 Self::lemma_item_well_formed_at(
449 *self,
450 initial_reader,
451 initial_view,
452 cursor_pre_read,
453 );
454 assert(C::raw_item_well_formed(paddr, level, pte.prop()));
455 }
456 let _item = unsafe { C::item_from_raw(paddr, level, pte.prop()) };
457 }
458 }
459 proof {
460 vstd::arithmetic::div_mod::lemma_mod_adds(
461 reader.cursor.vaddr - size_of_e,
462 size_of_e,
463 align_of_e,
464 );
465 }
466 let ghost iter_count_old: int = iter_count as int;
467 iter_count = iter_count + 1;
468 proof {
469 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
470 size_of_e,
471 iter_count_old,
472 1,
473 );
474 }
475 }
476 }
477
478 fn is_untyped(&self) -> bool {
479 false
480 }
481
482 uninterp spec fn vtable_ptr(&self) -> usize;
483}
484
485#[verus_verify]
486impl<C: PageTableConfig> PageTableNode<C> {
487 #[verus_spec(
496 with
497 Tracked(owner): Tracked<&NodeOwner<C>>,
498 Tracked(regions): Tracked<&MetaRegionOwners>
499 )]
500 pub(super) fn level(&self) -> PagingLevel
501 requires
502 self.ptr.addr() == regions.slots[owner.slot_index].addr(),
503 owner.metaregion_sound_node(*regions),
504 returns
505 owner.level,
506 {
507 let tracked points_to = regions.slots.tracked_borrow(owner.slot_index);
508 let tracked slot_owner = regions.slot_owners.tracked_borrow(owner.slot_index);
509 #[verus_spec(with
510 Tracked(points_to),
511 Tracked(&slot_owner.metadata_perm),
512 Tracked(&())
513 )]
514 let meta = self.meta();
515 meta.level
516 }
517
518 #[verus_spec(res =>
520 with Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
521 Tracked(regions): Tracked<&mut MetaRegionOwners>,
522 Tracked(guards): Tracked<&Guards<'rcu>>,
523 Ghost(idx): Ghost<usize>,
524 -> owner: Tracked<OwnerSubtree<C>>,
525 requires
526 1 <= level < NR_LEVELS,
527 idx < NR_ENTRIES,
528 old(regions).inv(),
529 old(parent_owner).inv(),
530 ensures
531 final(regions).inv(),
532 final(parent_owner).inv(),
533 allocated_empty_node_owner(owner@, level),
534 allocated_empty_node_grandchildren_none(owner@),
535 res.ptr.addr() == owner@.value().node().meta_vaddr(),
536 guards.unlocked(owner@.value().node().meta_vaddr()),
537 MetaSlot::get_node_from_unused_spec(meta_to_frame(owner@.value().node().meta_vaddr()), *old(regions), *final(regions)),
538 MetaSlot::slot_perm_reparked_spec(meta_to_frame(owner@.value().node().meta_vaddr()), *old(regions), *final(regions)),
539
540 final(regions).frame_obligations == old(regions).frame_obligations.insert(
541 meta_to_index(owner@.value().node().meta_vaddr())),
542 old(regions).contains(meta_to_index(owner@.value().node().meta_vaddr())),
543
544 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
545 meta_to_frame(owner@.value().node().meta_vaddr())),
546 owner@.value().metaregion_sound(*final(regions)),
547 forall|i: int|
548 #[trigger] old(regions).slot_owners[i].ref_count() != REF_COUNT_UNUSED
549 ==> i != meta_to_index(owner@.value().node().meta_vaddr()),
550 owner@.value().match_pte(C::E::new_pt_spec(meta_to_frame(owner@.value().node().meta_vaddr())), level as PagingLevel),
551 final(parent_owner).meta_own == old(parent_owner).meta_own,
552 final(parent_owner).slot_index == old(parent_owner).slot_index,
553 final(parent_owner).level == old(parent_owner).level,
554 final(parent_owner).tree_level == old(parent_owner).tree_level,
555 final(parent_owner).children_perm.addr() == old(parent_owner).children_perm.addr(),
556 final(parent_owner).children_perm.value() == old(parent_owner).children_perm.value().update(
557 idx as int,
558 C::E::new_pt_spec(meta_to_frame(owner@.value().node().meta_vaddr())),
559 ),
560 final(regions).contains(owner@.value().node().slot_index),
561 owner@.value().node().metaregion_sound_node(*final(regions)),
562 )]
563 #[verifier::external_body]
564 pub fn alloc<'rcu>(level: PagingLevel) -> Self {
565 let tracked entry_owner = EntryOwner::tracked_new_absent(
566 TreePath::new(Seq::empty()),
567 level,
568 );
569
570 let tracked mut owner = OwnerSubtree::<C>::tracked_new_val(entry_owner, level as nat);
571 let meta = PageTablePageMeta::new(level);
572 let mut frame = FrameAllocOptions::new();
573 frame.zeroed(true);
574 let allocated_frame = frame.alloc_frame_with(meta).expect(
575 "Failed to allocate a page table node",
576 );
577 proof_with!(|= Tracked(owner));
581
582 allocated_frame
583 }}
634
635#[verus_verify]
636impl<'a, C: PageTableConfig> PageTableNodeRef<'a, C> {
637 pub open spec fn locks_preserved_except<'rcu>(
638 addr: usize,
639 guards0: Guards<'rcu>,
640 guards1: Guards<'rcu>,
641 ) -> bool {
642 &&& OwnerSubtree::implies(
643 CursorOwner::<'rcu, C>::node_unlocked(guards0),
644 CursorOwner::<'rcu, C>::node_unlocked_except(guards1, addr),
645 )
646 &&& forall|i: usize| guards0.lock_held(i) ==> guards1.lock_held(i)
647 &&& forall|i: usize| guards0.unlocked(i) && i != addr ==> guards1.unlocked(i)
648 }
649
650 #[verifier::external_body]
659 #[verus_spec(res =>
660 with Tracked(owner): Tracked<&NodeOwner<C>>,
661 Tracked(guards): Tracked<&mut Guards<'rcu>>
662 requires
663 self.inner@.invariants(*owner),
664 old(guards).unlocked(owner.meta_vaddr()),
665 ensures
666 final(guards).lock_held(owner.meta_vaddr()),
667 Self::locks_preserved_except(owner.meta_vaddr(), *old(guards), *final(guards)),
668 owner.relate_guard(res),
669 )]
670 pub fn lock<'rcu, A: InAtomicMode>(self, _guard: &'rcu A) -> PageTableGuard<'rcu, C> where
671 'a: 'rcu,
672 {
673 unimplemented!()
674 }
675
676 #[verus_spec(res =>
685 with Tracked(owner): Tracked<&NodeOwner<C>>,
686 Tracked(guards): Tracked<&mut Guards<'rcu>>,
687 requires
688 self.inner@.invariants(*owner),
689 old(guards).unlocked(owner.meta_vaddr()),
690 ensures
691 final(guards).lock_held(owner.meta_vaddr()),
692 Self::locks_preserved_except(owner.meta_vaddr(), *old(guards), *final(guards)),
693 owner.relate_guard(res),
694 )]
695 pub unsafe fn make_guard_unchecked<'rcu, A: InAtomicMode>(
696 self,
697 _guard: &'rcu A,
698 ) -> PageTableGuard<'rcu, C> where 'a: 'rcu {
699 let guard = PageTableGuard { inner: self };
700
701 proof {
702 let ghost guards0 = *guards;
703 guards.guards = guards.guards.insert(owner.meta_vaddr());
704
705 }
706
707 guard
708 }
709}
710
711impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
712 #[verus_spec(res =>
719 with Tracked(owner): Tracked<&NodeOwner<C>>,
720 Tracked(child_owner): Tracked<&EntryOwner<C>>,
721 Tracked(regions): Tracked<&MetaRegionOwners>,
722 requires
723 owner.inv(),
724 child_owner.inv(),
725 owner.relate_guard(*old(self)),
726 child_owner.match_pte(
727 owner.children_perm.value()[idx as int],
728 child_owner.parent_level,
729 ),
730 regions.inv(),
731 regions.contains(owner.slot_index),
732 idx < NR_ENTRIES,
734 ensures
735 res.wf(*child_owner),
736 res.idx == idx,
737 *res.node == *old(self),
738 *final(self) == *final(res.node),
739 owner.relate_guard(*res.node),
740 )]
741 pub fn entry<'a>(&'a mut self, idx: usize) -> Entry<'a, 'rcu, C> {
742 #[cfg(feature = "allow_panic")]
743 assert!(idx < nr_subpage_per_huge::<C>());
744 unsafe {
747 #[verus_spec(with Tracked(child_owner), Tracked(owner), Tracked(regions))]
748 Entry::new_at(self, idx)
749 }
750 }
751
752 #[verus_spec(nr =>
761 with Tracked(owner) : Tracked<&NodeOwner<C>>,
762 Tracked(regions): Tracked<&MetaRegionOwners>,
763 requires
764 self.inner.inner@.invariants(*owner),
765 regions.inv(),
766 owner.metaregion_sound_node(*regions),
767 returns
768 owner.meta_own.nr_children.value(),
769 )]
770 pub fn nr_children(&self) -> u16 {
771 let tracked points_to = regions.slots.tracked_borrow(owner.slot_index);
772 let tracked slot_owner = regions.slot_owners.tracked_borrow(owner.slot_index);
773 #[verus_spec(with
774 Tracked(points_to),
775 Tracked(&slot_owner.metadata_perm),
776 Tracked(&())
777 )]
778 let meta = self.meta();
779
780 *meta.nr_children.borrow(Tracked(&owner.meta_own.nr_children))
781 }
782
783 #[verus_spec(res =>
785 with
786 Tracked(points_to): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>,
787 Tracked(metadata_perms): Tracked<&'a MetadataPerms>,
788 Tracked(repr_perm): Tracked<&'a ()>,
789 Ghost(stray_id): Ghost<vstd::cell::CellId>,
790 requires
791 old(self).inner.inner@.ptr.addr() == points_to.addr(),
792 typed_meta_wf::<PageTablePageMeta<C>>(*points_to, *metadata_perms, *repr_perm),
793 typed_meta_value::<PageTablePageMeta<C>>(*metadata_perms, *repr_perm).stray.id()
794 == stray_id,
795 ensures
796 res.id() == stray_id,
797 *final(self) == *old(self),
798 )]
799 pub(super) fn stray_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<bool> {
800 #[verus_spec(with
802 Tracked(points_to),
803 Tracked(metadata_perms),
804 Tracked(repr_perm)
805 )]
806 let meta = self.meta();
807 &meta.stray
808 }
809
810 #[verus_spec(pte =>
820 with Tracked(owner): Tracked<&NodeOwner<C>>,
821 Tracked(regions): Tracked<&MetaRegionOwners>,
822 requires
823 self.inner.inner@.invariants(*owner),
824 regions.inv(),
825 regions.contains(owner.slot_index),
826 idx < NR_ENTRIES,
827 ensures
828 pte == owner.children_perm.value()[idx as int],
829 )]
830 pub unsafe fn read_pte(&self, idx: usize) -> C::E {
831 let tracked owner_slot_perm = regions.slots.tracked_borrow(owner.slot_index);
833 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
834 paddr_to_vaddr(
835 #[verus_spec(with Tracked(owner_slot_perm))]
836 self.start_paddr(),
837 ),
838 );
839
840 unsafe {
844 #[verus_spec(with Tracked(&owner.children_perm))]
845 load_pte(ptr.add(idx), Ordering::Relaxed)
846 }
847 }
848
849 #[verus_spec(
862 with Tracked(owner): Tracked<&mut NodeOwner<C>>,
863 Tracked(regions): Tracked<&MetaRegionOwners>,
864 requires
865 old(self).inner.inner@.invariants(*old(owner)),
866 regions.inv(),
867 regions.contains(old(owner).slot_index),
868 idx < NR_ENTRIES,
869 ensures
870 final(owner).inv(),
871 final(owner).level == old(owner).level,
872 final(owner).meta_own == old(owner).meta_own,
873 final(owner).slot_index == old(owner).slot_index,
874 final(owner).children_perm.value() == old(owner).children_perm.value().update(
875 idx as int,
876 pte,
877 ),
878 *final(self) == *old(self),
879 )]
880 pub unsafe fn write_pte(&mut self, idx: usize, pte: C::E) {
881 let tracked owner_slot_perm = regions.slots.tracked_borrow(owner.slot_index);
883 #[verusfmt::skip]
884 let ptr = vstd_extra::array_ptr::ArrayPtr::<C::E, NR_ENTRIES>::from_addr(
885 paddr_to_vaddr(
886 #[verus_spec(with Tracked(owner_slot_perm))]
887 self.start_paddr()
888 ),
889 );
890
891 unsafe {
895 #[verus_spec(with Tracked(&mut owner.children_perm))]
896 store_pte(ptr.add(idx), pte, Ordering::Release)
897 }
898 proof {
899 assert(owner.children_perm.wf());
900 }
901 }
902
903 #[verus_spec(res =>
905 with
906 Tracked(points_to): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>,
907 Tracked(metadata_perms): Tracked<&'a MetadataPerms>,
908 Ghost(nr_children_id): Ghost<vstd::cell::CellId>,
909 requires
910 old(self).inner.inner@.ptr.addr() == points_to.addr(),
911 typed_meta_wf::<PageTablePageMeta<C>>(*points_to, *metadata_perms, ()),
912 typed_meta_value::<PageTablePageMeta<C>>(*metadata_perms, ()).nr_children.id()
913 == nr_children_id,
914 ensures
915 res.id() == nr_children_id,
916 *final(self) == *old(self),
917 )]
918 fn nr_children_mut<'a>(&'a mut self) -> &'a pcell_maybe_uninit::PCell<u16> {
919 #[verus_spec(with
921 Tracked(points_to),
922 Tracked(metadata_perms),
923 Tracked(&())
924 )]
925 let meta = self.meta();
926 &meta.nr_children
927 }
928}
929
930impl<C: PageTableConfig> PageTablePageMeta<C> {
937 pub fn new(level: PagingLevel) -> Self {
938 Self {
939 nr_children: pcell_maybe_uninit::PCell::new(0).0,
940 stray: pcell_maybe_uninit::PCell::new(false).0,
941 level,
942 lock: PAtomicU8::new(0).0,
943 _phantom: PhantomData,
944 }
945 }
946
947 pub open spec fn walk_pte_at_view(view: crate::specs::mm::virt_mem::MemView, c: usize) -> C::E {
952 ostd_pod::decode_pod::<C::E>(view.read_bytes(c, core::mem::size_of::<C::E>()))
953 }
954
955 pub open spec fn walk_coverage_at(
960 self,
961 view: crate::specs::mm::virt_mem::MemView,
962 dom: vstd::set::Set<int>,
963 c: usize,
964 ) -> bool {
965 let pte = Self::walk_pte_at_view(view, c);
966 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(frame_to_index(pte.paddr()))
967 }
968
969 pub proof fn lemma_coverage_at(
971 self,
972 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
973 view: crate::specs::mm::virt_mem::MemView,
974 dom: vstd::set::Set<int>,
975 c: usize,
976 )
977 requires
978 self.walk_coverage_from_view(reader, view, dom),
979 reader.cursor.vaddr <= c,
980 c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
981 (c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
982 ensures
983 self.walk_coverage_at(view, dom, c),
984 {
985 }
986
987 pub proof fn lemma_item_well_formed_at(
989 self,
990 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
991 view: crate::specs::mm::virt_mem::MemView,
992 c: usize,
993 )
994 requires
995 self.walk_items_well_formed_from_view(reader, view),
996 reader.cursor.vaddr <= c,
997 c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
998 (c - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
999 ensures
1000 ({
1001 let pte = Self::walk_pte_at_view(view, c);
1002 pte.is_present() && pte.is_last(self.level) ==> C::raw_item_well_formed(
1003 pte.paddr(),
1004 self.level,
1005 pte.prop(),
1006 )
1007 }),
1008 {
1009 }
1010
1011 pub proof fn lemma_uniqueness_at_pair(
1013 self,
1014 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
1015 view: crate::specs::mm::virt_mem::MemView,
1016 c1: usize,
1017 c2: usize,
1018 )
1019 requires
1020 self.walk_uniqueness_from_view(reader, view),
1021 reader.cursor.vaddr <= c1,
1022 c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
1023 (c1 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
1024 reader.cursor.vaddr <= c2,
1025 c2 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr + reader.remain_spec(),
1026 (c2 - reader.cursor.vaddr) % core::mem::size_of::<C::E>() as int == 0,
1027 c1 != c2,
1028 Self::walk_pte_at_view(view, c1).is_present(),
1029 !Self::walk_pte_at_view(view, c1).is_last(self.level),
1030 Self::walk_pte_at_view(view, c2).is_present(),
1031 !Self::walk_pte_at_view(view, c2).is_last(self.level),
1032 ensures
1033 Self::walk_pte_at_view(view, c1).paddr() != Self::walk_pte_at_view(view, c2).paddr(),
1034 {
1035 }
1036
1037 pub open spec fn walk_coverage_from_view(
1043 self,
1044 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
1045 view: crate::specs::mm::virt_mem::MemView,
1046 dom: vstd::set::Set<int>,
1047 ) -> bool {
1048 forall|c: usize|
1049 #![trigger Self::walk_pte_at_view(view, c)]
1050 reader.cursor.vaddr <= c && c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
1051 + reader.remain_spec() && (c - reader.cursor.vaddr) % core::mem::size_of::<
1052 C::E,
1053 >() as int == 0 ==> {
1054 let pte = Self::walk_pte_at_view(view, c);
1055 pte.is_present() && !pte.is_last(self.level) ==> dom.contains(
1056 frame_to_index(pte.paddr()),
1057 )
1058 }
1059 }
1060
1061 pub open spec fn walk_items_well_formed_from_view(
1064 self,
1065 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
1066 view: crate::specs::mm::virt_mem::MemView,
1067 ) -> bool {
1068 forall|c: usize|
1069 #![trigger Self::walk_pte_at_view(view, c)]
1070 reader.cursor.vaddr <= c && c + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
1071 + reader.remain_spec() && (c - reader.cursor.vaddr) % core::mem::size_of::<
1072 C::E,
1073 >() as int == 0 ==> {
1074 let pte = Self::walk_pte_at_view(view, c);
1075 pte.is_present() && pte.is_last(self.level) ==> C::raw_item_well_formed(
1076 pte.paddr(),
1077 self.level,
1078 pte.prop(),
1079 )
1080 }
1081 }
1082
1083 pub open spec fn walk_uniqueness_from_view(
1086 self,
1087 reader: crate::mm::VmReader<'_, crate::mm::Infallible>,
1088 view: crate::specs::mm::virt_mem::MemView,
1089 ) -> bool {
1090 forall|c1: usize, c2: usize|
1091 #![trigger Self::walk_pte_at_view(view, c1), Self::walk_pte_at_view(view, c2)]
1092 reader.cursor.vaddr <= c1 && c1 + core::mem::size_of::<C::E>() <= reader.cursor.vaddr
1093 + reader.remain_spec() && (c1 - reader.cursor.vaddr) % core::mem::size_of::<
1094 C::E,
1095 >() as int == 0 && reader.cursor.vaddr <= c2 && c2 + core::mem::size_of::<C::E>()
1096 <= reader.cursor.vaddr + reader.remain_spec() && (c2 - reader.cursor.vaddr)
1097 % core::mem::size_of::<C::E>() as int == 0 && c1 != c2 ==> {
1098 let pte1 = Self::walk_pte_at_view(view, c1);
1099 let pte2 = Self::walk_pte_at_view(view, c2);
1100 pte1.is_present() && !pte1.is_last(self.level) && pte2.is_present()
1101 && !pte2.is_last(self.level) ==> pte1.paddr() != pte2.paddr()
1102 }
1103 }
1104
1105 pub open spec fn child_perms_embedding(
1110 regions: crate::specs::mm::frame::meta_region_owners::MetaRegionOwners,
1111 excluded: vstd::set::Set<int>,
1112 ) -> bool {
1113 forall|paddr: crate::mm::Paddr|
1114 #![trigger regions.slot_owners[frame_to_index(paddr)]]
1115 regions.slots.dom().contains(frame_to_index(paddr)) && !excluded.contains(
1116 frame_to_index(paddr),
1117 ) ==> {
1118 let idx = frame_to_index(paddr);
1119 let so = regions.slot_owners[idx];
1120 &&& <Frame<Self>>::from_raw_requires_safety(
1121 regions,
1122 paddr,
1123 )
1124 &&& 0 < so.ref_count() <= REF_COUNT_MAX
1126 &&& so.ref_count() == 1 ==> {
1127 &&& so.storage_perm().is_init()
1128 &&& so.in_list_perm.value() == 0
1129 &&& so.paths_in_pt.is_empty()
1130 }
1131 }
1136 }
1137}
1138
1139}