1use vstd::prelude::*;
4
5use vstd_extra::ghost_tree::*;
6use vstd_extra::ownership::*;
7
8use crate::arch::mm::PagingConsts;
9use crate::mm::frame::meta::mapping::{frame_to_meta, meta_to_frame};
10use crate::mm::frame::{
11 Frame, FrameRef,
12 meta::{REF_COUNT_MAX, REF_COUNT_UNUSED},
13};
14use crate::mm::page_table::*;
15use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
16use crate::specs::arch::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
17use crate::specs::mm::frame::{
18 mapping::{frame_to_index, group_page_meta},
19 meta_region_owners::MetaRegionOwners,
20};
21use crate::specs::mm::page_table::{INC_LEVELS, PageTableOwner};
22use crate::specs::task::InAtomicMode;
23
24use core::marker::PhantomData;
25use core::ops::Deref;
26
27use crate::{
28 mm::{nr_subpage_per_huge, page_prop::PageProperty},
29 };
32
33use super::*;
34
35verus! {
36
37pub type PageTableNodeRef<'a, C> = FrameRef<'a, PageTablePageMeta<C>>;
39
40pub struct PageTableGuard<'rcu, C: PageTableConfig> {
42 pub inner: PageTableNodeRef<'rcu, C>,
43}
44
45impl<'rcu, C: PageTableConfig> Deref for PageTableGuard<'rcu, C> {
46 type Target = PageTableNodeRef<'rcu, C>;
47
48 #[verus_spec(ensures returns self.inner)]
49 fn deref(&self) -> &Self::Target {
50 &self.inner
51 }
52}
53
54pub struct Entry<'a, 'rcu, C: PageTableConfig> {
55 pub pte: C::E,
74 pub idx: usize,
76 pub node: &'a mut PageTableGuard<'rcu, C>,
78}
79
80#[verus_verify]
81impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
82 pub open spec fn new_spec(
83 pte: C::E,
84 idx: usize,
85 node: &'a mut PageTableGuard<'rcu, C>,
86 ) -> Self {
87 Self { pte, idx, node }
88 }
89
90 #[verus_spec(res =>
91 ensures
92 res.pte == pte,
93 res.idx == idx,
94 *res.node == *old(node),
95 *final(node) == *final(res.node),
96 )]
97 pub fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> Self {
98 Self { pte, idx, node }
99 }
100}
101
102#[verus_verify]
103impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
104 #[verus_spec(r =>
106 with Tracked(owner): Tracked<&EntryOwner<C>>,
107 requires
108 self.wf(*owner),
109 owner.inv(),
110 returns owner.is_absent(),
111 )]
112 pub(in crate::mm) fn is_none(&self) -> bool {
113 !self.pte.is_present()
114 }
115
116 #[verus_spec(
118 with Tracked(owner): Tracked<EntryOwner<C>>,
119 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
120 Tracked(regions): Tracked<&MetaRegionOwners>,
121 requires
122 owner.inv(),
123 self.wf(owner),
124 parent_owner.relate_guard(*self.node),
125 parent_owner.inv(),
126 parent_owner.level == owner.parent_level,
127 regions.inv(),
128 parent_owner.metaregion_sound_node(*regions),
129 returns
130 owner.is_node(),
131 )]
132 pub(in crate::mm) fn is_node(&self) -> bool {
133 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
134 parent_owner.slot_index,
135 );
136 self.pte.is_present() && !self.pte.is_last(
137 #[verus_spec(with Tracked(parent_meta_perm))]
138 self.node.level(),
139 )
140 }
141
142 #[verus_spec(res =>
144 with Tracked(owner): Tracked<&EntryOwner<C>>,
145 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
146 Tracked(regions): Tracked<&mut MetaRegionOwners>,
147 requires
148 self.invariants(*owner, *old(regions)),
149 self.node_matching(*owner, *parent_owner, *self.node),
150 parent_owner.metaregion_sound_node(*old(regions)),
151 ensures
152 res.invariants(*owner, *final(regions)),
153 final(regions).slot_owners == old(regions).slot_owners,
154 forall|k: usize|
155 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
156 k,
157 ),
158 forall|k: usize|
159 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
160 == #[trigger] final(regions).slots[k],
161 final(regions).inv(),
162 )]
163 pub(in crate::mm) fn to_ref(&self) -> ChildRef<'rcu, C> {
164 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
165 parent_owner.slot_index,
166 );
167 #[verus_spec(with Tracked(parent_meta_perm))]
168 let level = self.node.level();
169
170 let res = unsafe {
174 #[verus_spec(with Tracked(regions), Tracked(owner))]
175 ChildRef::from_pte(&self.pte, level)
176 };
177
178 res
179 }
180
181 #[verus_spec(
198 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
199 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
200 Tracked(regions): Tracked<&MetaRegionOwners>,
201 requires
202 old(owner).inv(),
203 old(self).wf(*old(owner)),
204 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
205 op.requires((old(self).pte.prop(),)),
206 old(owner).is_frame(),
207 regions.inv(),
208 regions.slots.contains_key(old(parent_owner).slot_index),
209 old(parent_owner).metaregion_sound_node(*regions),
210 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
230 #![auto]
231 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
232 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
233 ensures
234 final(owner).inv(),
235 final(self).wf(*final(owner)),
236 final(self).node_matching(*final(owner), *final(parent_owner), *final(self).node),
237 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
238 final(owner).is_frame(),
239 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
240 final(owner).frame().is_tracked == old(owner).frame().is_tracked,
241 final(owner).path == old(owner).path,
242 final(owner).parent_level == old(owner).parent_level,
243 final(self).idx == old(self).idx,
244 *final(self).node == *old(self).node,
245 old(self).pte.is_present() ==> op.ensures(
246 (old(owner).frame().prop,),
247 final(owner).frame().prop,
248 ),
249 crate::specs::mm::page_table::node::owners::count_present(
254 final(parent_owner).children_perm.value(),
255 ) == crate::specs::mm::page_table::node::owners::count_present(
256 old(parent_owner).children_perm.value(),
257 ),
258 final(parent_owner).meta_own.nr_children.value() == old(
259 parent_owner,
260 ).meta_own.nr_children.value(),
261 )]
262 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty) {
263 #[verus_spec(with Tracked(owner), Tracked(parent_owner), Tracked(regions))]
264 let pte = self.node.protect_child(self.idx, op);
265 self.pte = pte;
266 }
267
268 #[verus_spec(res =>
289 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
290 Tracked(owner): Tracked<&mut EntryOwner<C>>,
291 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
292 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
293 requires
294 old(self).invariants(*old(owner), *old(regions)),
295 new_child.invariants(*old(new_owner), *old(regions)),
296 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
297 old(self).new_owner_compatible(new_child, *old(owner), *old(new_owner), *old(regions)),
298 old(parent_owner).metaregion_sound_node(*old(regions)),
299 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
300 frame_to_index(meta_to_frame(node.ptr.addr())),
301 ) > 0,
302 ensures
303 final(self).invariants(*final(new_owner), *final(regions)),
304 res.invariants(*final(owner), *final(regions)),
305 final(self).node_matching(*final(new_owner), *final(parent_owner), *final(self).node),
306 final(self).idx == old(self).idx,
307 *final(self).node == *old(self).node,
308 *final(owner) == old(owner).from_pte_owner_spec(),
309 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
310 Self::metaregion_sound_neq_preserved(
311 *old(owner),
312 *final(new_owner),
313 *old(regions),
314 *final(regions),
315 ),
316 !final(new_owner).is_node() ==> Self::metaregion_sound_neq_old_preserved(
317 *old(owner),
318 *old(regions),
319 *final(regions),
320 ),
321 (!old(owner).is_node() && !final(new_owner).is_node())
322 ==> Self::metaregion_sound_preserved(*old(regions), *final(regions)),
323 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
324 C,
325 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
326 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
327 final(parent_owner).metaregion_sound_node(*final(regions)),
328 forall|idx: usize|
330 #![trigger final(regions).slot_owners[idx].paths_in_pt]
331 (!final(new_owner).is_node() || final(new_owner).is_absent() || idx
332 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
333 ==> final(regions).slot_owners[idx].paths_in_pt == old(
334 regions,
335 ).slot_owners[idx].paths_in_pt,
336 forall|k: usize|
338 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
339 k,
340 ),
341 forall|idx: usize|
347 #![trigger final(regions).slot_owners[idx].inner_perms.ref_count.value()]
348 final(regions).slot_owners[idx].inner_perms.ref_count.value() == old(
349 regions,
350 ).slot_owners[idx].inner_perms.ref_count.value(),
351 forall|idx: usize|
352 #![trigger final(regions).slot_owners[idx].inner_perms]
353 final(regions).slot_owners[idx].inner_perms == old(
354 regions,
355 ).slot_owners[idx].inner_perms,
356 final(regions).slots == old(regions).slots,
357 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
359 &&& final(regions).slots == old(regions).slots
360 &&& forall|i: usize|
361 #![trigger final(regions).slot_owners[i]]
362 final(regions).slot_owners[i] == old(
363 regions,
364 ).slot_owners[i]
365 &&& final(regions).frame_obligations == old(regions).frame_obligations
371 },
372 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: usize|
374 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
375 == #[trigger] final(regions).slots[k],
376 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
377 )]
378 #[verifier::spinoff_prover]
379 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> Child<C> {
380 let ghost new_idx = frame_to_index(new_owner.meta_slot_paddr().unwrap());
381 let ghost cp0 = parent_owner.children_perm.value();
385
386 #[cfg(feature = "allow_panic")]
387 {
388 let guard_level = self.node.level();
389 match &new_child {
390 Child::PageTable(node) => {
391 assert!(node.level() == guard_level - 1);
392 },
393 Child::Frame(_, level, _) => {
394 assert!(*level == guard_level);
395 },
396 Child::None => {},
397 }
398 }
399
400 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
404 parent_owner.slot_index,
405 );
406 #[verus_spec(with Tracked(parent_meta_perm))]
407 let level = self.node.level();
408
409 let old_child = unsafe {
410 #[verus_spec(with Tracked(regions), Tracked(owner))]
411 Child::from_pte(self.pte, level)
412 };
413
414 if old_child.is_none() && !new_child.is_none() {
415 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
416 parent_owner.slot_index,
417 );
418 #[verus_spec(with Tracked(parent_meta_perm2))]
419 let nr_children = self.node.nr_children_mut();
420 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
421 proof {
422 parent_owner.nr_children_absent_slot_bound(self.idx);
423 }
424 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
425 } else if !old_child.is_none() && new_child.is_none() {
426 let tracked parent_meta_perm3 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
427 parent_owner.slot_index,
428 );
429 #[verus_spec(with Tracked(parent_meta_perm3))]
430 let nr_children = self.node.nr_children_mut();
431 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
432 proof {
433 parent_owner.nr_children_present_slot_bound(self.idx);
434 }
435 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
436 }
437 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
438 let new_pte = new_child.into_pte();
439
440 unsafe {
445 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
446 self.node.write_pte(self.idx, new_pte)
447 };
448
449 self.pte = new_pte;
450
451 proof {
452 if new_owner.is_node() {
459 let paddr = new_owner.meta_slot_paddr().unwrap();
460 regions.inv_implies_correct_addr(paddr);
461
462 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
463 new_meta_slot.paths_in_pt = set![new_owner.path];
464 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
465 }
466 }
467
468 proof {
469 if !old(owner).is_node() && !new_owner.is_node() {
472 }
474 }
475
476 proof {
477 if new_owner.is_node() || new_owner.is_frame() {
478 let paddr = new_owner.meta_slot_paddr().unwrap();
479 regions.inv_implies_correct_addr(paddr);
480 }
481 }
482
483 proof {
484 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
488 cp0,
489 NR_ENTRIES as int,
490 self.idx as int,
491 new_pte,
492 );
493 }
496
497 old_child
498 }
499
500 #[verus_spec(res =>
517 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
518 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
519 Tracked(regions): Tracked<&mut MetaRegionOwners>,
520 Tracked(guards): Tracked<&mut Guards<'rcu>>,
521 requires
522 old(self).invariants(old(owner).value, *old(regions)),
523 old(owner).inv(),
524 old(self).node_matching(old(owner).value, *old(parent_owner), *old(self).node),
525 old(owner).level < INC_LEVELS - 1,
526 old(owner).level + old(parent_owner).level == INC_LEVELS,
531 old(parent_owner).metaregion_sound_node(*old(regions)),
532 ensures
533 final(self).invariants(final(owner).value, *final(regions)),
534 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
535 final(self).idx == old(self).idx,
536 final(parent_owner).count_consistent(),
537 *final(self).node == *old(self).node,
538 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
539 &&& final(self).node_matching(final(owner).value, *final(parent_owner), *final(self).node)
540 &&& final(owner).inv()
541 },
542 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
543 &&& res is Some
544 &&& final(owner).value.is_node()
545 &&& final(owner).level == old(owner).level
546 &&& final(owner).value.parent_level == old(owner).value.parent_level
547 &&& final(guards).lock_held(final(owner).value.node().meta_addr_self())
548 &&& final(owner).value.node().relate_guard(res->0)
549 &&& final(owner).value.path == old(owner).value.path
550 &&& final(owner).value.metaregion_sound(*final(regions))
551 &&& OwnerSubtree::implies(
552 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
553 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node().meta_addr_self()))
554 &&& Self::metaregion_sound_neq_preserved(old(owner).value, final(owner).value, *old(regions), *final(regions))
555 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
556 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value.meta_slot_paddr()->0))
557 &&& final(owner).tree_predicate_map(final(owner).value.path,
558 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node().meta_addr_self()))
559 &&& final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
560 &&& final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
561 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value.path) == set![]
562 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
564 #[trigger] final(owner).children[i] is Some && final(owner).children[i]->0.value.is_absent()
565 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
572 (#[trigger] final(owner).children[i])->0.value.path
573 == final(owner).value.path.push_tail(i as usize)
574 &&& crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner))
578 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
580 (#[trigger] final(owner).children[i])->0.value.parent_level
581 == final(owner).value.node().level
582 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
583 (#[trigger] final(owner).children[i])->0.value.match_pte(
584 final(owner).value.node().children_perm.value()[i],
585 final(owner).children[i]->0.value.parent_level)
586 &&& forall|i: usize| i != frame_to_index(final(owner).value.meta_slot_paddr()->0) ==>
588 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
589 &&& forall|i: usize| old(regions).slots.contains_key(i)
591 ==> (#[trigger] final(regions).slots.contains_key(i))
592 &&& forall|i: usize| #![trigger final(regions).slots[i]]
593 i != frame_to_index(final(owner).value.meta_slot_paddr()->0)
594 && old(regions).slots.contains_key(i)
595 ==> final(regions).slots[i] == old(regions).slots[i]
596 &&& final(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr()->0)]
598 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
599 &&& old(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr().unwrap())]
601 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
602 &&& !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
604 final(owner).value.meta_slot_paddr().unwrap())
605 },
606 !old(owner).value.is_absent() ==> {
607 &&& res is None
608 &&& *final(owner) == *old(owner)
609 },
610 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
611 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value.node().meta_addr_self() ==> final(guards).unlocked(i),
612 )]
613 #[verifier::spinoff_prover]
614 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
615 PageTableGuard<'rcu, C>,
616 > {
617 let entry_is_present = self.pte.is_present();
618 let ghost cp0 = parent_owner.children_perm.value();
620
621 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
622 parent_owner.slot_index,
623 );
624 #[verus_spec(with Tracked(parent_meta_perm))]
625 let level = self.node.level();
626
627 if entry_is_present || level <= 1 {
628 None
629 } else {
630 let ghost old_path = owner.value.path;
631 let ghost old_owner_val = owner.value;
632
633 proof {
634 parent_owner.nr_children_absent_slot_bound(self.idx);
641 }
642
643 let ghost regions_pre = *regions;
650 let ghost pre_meta_perm = parent_owner.meta_perm_of(*regions);
651
652 proof_decl! {
653 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
654 }
655
656 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
657 let new_page = PageTableNode::<C>::alloc(level - 1);
658
659 proof {
660 let pte = C::E::new_pt_spec(
661 meta_to_frame(new_node_owner.value.node().meta_addr_self()),
662 );
663 old(parent_owner).set_children_perm_axiom(self.idx, pte);
664 C::E::lemma_page_table_entry_properties();
665 }
666
667 let ghost new_node_slot_idx = new_node_owner.value.node().slot_index;
668 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
669 #[verus_spec(with Tracked(new_node_slot_perm))]
670 let paddr = new_page.start_paddr();
671
672 #[verus_spec(with Tracked(&mut new_node_owner.value), Tracked(regions))]
673 let new_pte = Child::PageTable(new_page).into_pte();
674 self.pte = new_pte;
675
676 proof {
677 broadcast use group_page_meta;
678
679 }
680
681 let pt_ref = unsafe {
682 #[verus_spec(with Tracked(regions))]
683 PageTableNodeRef::borrow_paddr(paddr)
684 };
685
686 #[verus_spec(with Tracked(&new_node_owner.value.tracked_borrow_node()), Tracked(guards))]
688 let mut pt_lock_guard = pt_ref.lock(guard);
689
690 unsafe {
695 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
696 self.node.write_pte(self.idx, self.pte)
697 };
698
699 proof {
700 }
713
714 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
715 parent_owner.slot_index,
716 );
717 #[verus_spec(with Tracked(parent_meta_perm2))]
718 let nr_children = self.node.nr_children_mut();
719 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
720 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
721
722 proof {
723 owner.value = new_node_owner.value;
730 owner.value.parent_level = level as PagingLevel;
731 owner.value.path = old_path;
732 owner.children = new_node_owner.children;
733 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
737
738 let new_paddr = owner.value.meta_slot_paddr().unwrap();
739 regions.inv_implies_correct_addr(new_paddr);
740 let new_idx = frame_to_index(new_paddr);
741 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
742 new_meta_slot.paths_in_pt = set![owner.value.path];
743 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
744 }
745
746 proof {
747 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
751 cp0,
752 NR_ENTRIES as int,
753 self.idx as int,
754 self.pte,
755 );
756 }
757
758 proof {
759 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
763 let ghost new_node_addr = owner.value.node().meta_addr_self();
771 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
772 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
773 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
774
775 assert forall|i: int| 0 <= i < NR_ENTRIES implies {
779 &&& #[trigger] f_nu(
780 owner.children[i].unwrap().value,
781 owner.value.path.push_tail(i as usize),
782 )
783 &&& f_ms(
784 owner.children[i].unwrap().value,
785 owner.value.path.push_tail(i as usize),
786 )
787 &&& f_pt(
788 owner.children[i].unwrap().value,
789 owner.value.path.push_tail(i as usize),
790 )
791 } by {};
792
793 crate::specs::mm::page_table::fresh_node_tree_predicate_map(
794 *owner,
795 owner.value.path,
796 f_nu,
797 );
798 crate::specs::mm::page_table::fresh_node_tree_predicate_map(
799 *owner,
800 owner.value.path,
801 f_ms,
802 );
803 crate::specs::mm::page_table::fresh_node_tree_predicate_map(
804 *owner,
805 owner.value.path,
806 f_pt,
807 );
808 }
809
810 Some(pt_lock_guard)
811 }
812 }
813
814 #[verifier::spinoff_prover]
830 #[verifier::rlimit(infinity)]
831 #[verus_spec(res =>
832 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
833 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
834 Tracked(regions): Tracked<&mut MetaRegionOwners>,
835 Tracked(guards): Tracked<&mut Guards<'rcu>>
836 requires
837 old(regions).inv(),
838 old(owner).inv(),
839 old(self).wf(old(owner).value),
840 old(parent_owner).relate_guard(*old(self).node),
841 old(parent_owner).inv(),
842 old(parent_owner).level == old(owner).value.parent_level,
843 old(parent_owner).level < NR_LEVELS,
844 old(parent_owner).metaregion_sound_node(*old(regions)),
845 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
851 old(owner).value.metaregion_sound(*old(regions)),
852 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
856 forall |j: usize| #![trigger frame_to_index(
857 (old(owner).value.frame().mapped_pa
858 + j * PAGE_SIZE) as usize)]
859 0 < j < page_size(old(parent_owner).level) / PAGE_SIZE ==> {
860 let sub_idx = frame_to_index(
861 (old(owner).value.frame().mapped_pa
862 + j * PAGE_SIZE) as usize);
863 &&& old(regions).slots.contains_key(sub_idx)
864 &&& old(regions).slot_owners[sub_idx].usage !is MMIO ==>
865 old(regions).slot_owners[sub_idx].inner_perms.ref_count.value()
866 != REF_COUNT_UNUSED
867 },
868 ensures
869 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
870 &&& res is Some
871 &&& final(owner).value.is_node()
872 &&& final(owner).level == old(owner).level
873 &&& final(parent_owner).relate_guard(*final(self).node)
874 &&& final(owner).value.node().relate_guard(res->0)
875 &&& final(owner).value.node().meta_addr_self() == res->0.inner.inner@.ptr.addr()
876 &&& final(guards).lock_held(res->0.inner.inner@.ptr.addr())
877 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
879 (#[trigger] final(owner).children[j])->0.value.is_frame()
880 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
881 (#[trigger] final(owner).children[j])->0.value.frame().prop
882 == old(owner).value.frame().prop
883 &&& final(owner).value.path == old(owner).value.path
884 &&& final(owner).value.metaregion_sound(*final(regions))
885 &&& OwnerSubtree::implies(
886 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
887 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
888 &&& OwnerSubtree::implies(
889 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
890 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
891 &&& final(owner).tree_predicate_map(final(owner).value.path,
892 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
893 &&& final(owner).tree_predicate_map(final(owner).value.path,
894 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
895 },
896 !old(owner).value.is_frame() || old(parent_owner).level <= 1 ==> {
897 &&& res is None
898 &&& *final(owner) == *old(owner)
899 },
900 final(owner).inv(),
901 final(owner).value.parent_level == old(owner).value.parent_level,
902 final(self).idx == old(self).idx,
903 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
904 final(self).node_matching(final(owner).value, *final(parent_owner), *final(self).node),
905 final(regions).inv(),
906 final(parent_owner).inv(),
907 final(parent_owner).level == old(parent_owner).level,
908 final(self).node.inner.inner@.ptr.addr() == old(self).node.inner.inner@.ptr.addr(),
909 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
910 forall |i: usize| old(guards).unlocked(i) ==> final(guards).unlocked(i),
911 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
913 &&& forall|i: usize| i != frame_to_index(meta_to_frame(final(owner).value.node().meta_addr_self())) ==>
914 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
915 &&& forall|i: usize| old(regions).slots.contains_key(i)
917 ==> (#[trigger] final(regions).slots.contains_key(i))
918 &&& final(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value.node().meta_addr_self()))]
920 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
921 &&& old(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value.node().meta_addr_self()))]
923 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
924 },
925 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
930 forall|j: int| 0 <= j < NR_ENTRIES && j != old(self).idx ==>
931 #[trigger] final(parent_owner).children_perm.value()[j]
932 == old(parent_owner).children_perm.value()[j],
933 )]
934 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
935 PageTableGuard<'rcu, C>,
936 > {
937 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
938 parent_owner.slot_index,
939 );
940 #[verus_spec(with Tracked(parent_meta_perm))]
941 let level = self.node.level();
942
943 if !(self.pte.is_last(level) && level > 1) {
944 return None;
945 }
946 let pa = self.pte.paddr();
947 let prop = self.pte.prop();
948
949 proof {
950 EntryOwner::last_pte_implies_frame_match(owner.value, self.pte, level);
951 }
952
953 proof_decl!{
954 let tracked mut new_owner: OwnerSubtree<C>;
955 }
956
957 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
960 let new_page = PageTableNode::<C>::alloc(level - 1);
961
962 let ghost new_owner_slot_idx = new_owner.value.node().slot_index;
963 let tracked new_owner_slot_perm = regions.slots.tracked_borrow(new_owner_slot_idx);
964 #[verus_spec(with Tracked(new_owner_slot_perm))]
965 let paddr = new_page.start_paddr();
966
967 proof {
968 broadcast use group_page_meta;
969
970 }
971
972 let pt_ref = unsafe {
973 #[verus_spec(with Tracked(regions))]
974 PageTableNodeRef::borrow_paddr(paddr)
975 };
976
977 #[verus_spec(with Tracked(&new_owner.value.tracked_borrow_node()), Tracked(guards))]
979 let mut pt_lock_guard = pt_ref.lock(guard);
980
981 let ghost children_perm = new_owner.value.node().children_perm;
982 let ghost new_owner_path = new_owner.value.path;
983 let ghost new_owner_meta_addr = new_owner.value.node().meta_addr_self();
984
985 proof {
986 broadcast use crate::specs::mm::frame::mapping::lemma_frame_to_index_injective;
998 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
999 broadcast use group_page_meta;
1000
1001 let new_idx = frame_to_index(meta_to_frame(new_owner_meta_addr));
1002 let new_paddr = meta_to_frame(new_owner_meta_addr);
1003 let nr_pages = page_size(level) / PAGE_SIZE;
1004
1005 let pa_idx = frame_to_index(pa);
1009 assert(pa_idx != new_idx) by {
1010 if old(regions).slot_owners[pa_idx].usage
1011 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
1012 old(regions).inv_implies_correct_addr(pa);
1013 } else {
1014 }
1016 };
1017
1018 assert forall|j: usize|
1020 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
1021 0 < j < nr_pages implies {
1022 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1023 &&& regions.slots.contains_key(sub_idx)
1024 &&& regions.slot_owners[sub_idx].usage
1025 != crate::specs::mm::frame::meta_owners::PageUsage::PageTable
1026 &&& regions.slot_owners[sub_idx].usage
1027 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
1028 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1029 != REF_COUNT_UNUSED
1030 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1031 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
1032 }
1033 } by {
1034 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1035 assert(sub_idx != new_idx) by {
1036 if old(regions).slot_owners[sub_idx].usage
1037 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
1038 old(regions).inv_implies_correct_addr((pa + j * PAGE_SIZE) as usize);
1039 } else {
1040 }
1042 };
1043 };
1044 }
1045
1046 for i in 0..nr_subpage_per_huge::<C>()
1047 invariant
1048 1 < level < NR_LEVELS,
1049 owner.inv(),
1050 owner.value.is_frame(),
1051 owner.value.parent_level == level,
1052 owner.value.frame().mapped_pa == pa,
1053 owner.value.frame().prop == prop,
1054 pa == old(owner).value.frame().mapped_pa,
1055 level == old(parent_owner).level,
1056 pa % page_size(level) == 0,
1057 pa + page_size(level) <= MAX_PADDR,
1058 regions.inv(),
1059 regions.frame_obligations.count(frame_to_index(meta_to_frame(new_owner_meta_addr)))
1064 > 0,
1065 parent_owner.inv(),
1066 new_owner.value.is_node(),
1067 new_owner.inv(),
1068 new_owner.value.path == new_owner_path,
1069 new_owner.value.node().meta_addr_self() == new_owner_meta_addr,
1070 new_owner.value.node().relate_guard(pt_lock_guard),
1071 guards.lock_held(new_owner_meta_addr),
1072 new_owner.value.node().level == (level - 1) as PagingLevel,
1073 forall|j: int|
1074 #![auto]
1075 0 <= j < NR_ENTRIES ==> {
1076 &&& new_owner.children[j] is Some
1077 &&& new_owner.children[j].unwrap().value.match_pte(
1078 new_owner.value.node().children_perm.value()[j],
1079 new_owner.value.node().level,
1080 )
1081 &&& new_owner.children[j].unwrap().value.parent_level
1082 == new_owner.value.node().level
1083 &&& new_owner.children[j].unwrap().value.inv()
1084 &&& new_owner.children[j].unwrap().value.path == new_owner_path.push_tail(
1085 j as usize,
1086 )
1087 },
1088 forall|j: int|
1089 #![auto]
1090 i <= j < NR_ENTRIES ==> {
1091 &&& new_owner.children[j].unwrap().value.is_absent()
1092 &&& new_owner.value.node().children_perm.value()[j]
1093 == C::E::new_absent_spec()
1094 },
1095 forall|j: int|
1097 #![auto]
1098 0 <= j < i ==> { new_owner.children[j].unwrap().value.is_frame() },
1099 forall|j: usize|
1103 #![trigger frame_to_index(
1104 (pa + j * PAGE_SIZE) as usize)]
1105 0 < j < page_size(level) / PAGE_SIZE ==> {
1106 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1107 &&& regions.slots.contains_key(sub_idx)
1108 &&& regions.slot_owners[sub_idx].usage !is PageTable
1109 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1110 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1111 != REF_COUNT_UNUSED
1112 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1113 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1114 <= REF_COUNT_MAX
1115 }
1116 },
1117 regions.slots.contains_key(frame_to_index(pa)),
1119 regions.slot_owners[frame_to_index(pa)].usage !is PageTable,
1120 regions.slot_owners[frame_to_index(pa)].usage !is MMIO ==> {
1121 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
1122 != REF_COUNT_UNUSED
1123 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value() > 0
1124 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
1125 <= REF_COUNT_MAX
1126 },
1127 new_page.ptr.addr() == new_owner_meta_addr,
1128 new_owner.value.node().metaregion_sound_node(*regions),
1129 regions.slot_owners[frame_to_index(
1134 meta_to_frame(new_owner_meta_addr),
1135 )].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
1136 0 < regions.slot_owners[frame_to_index(
1137 meta_to_frame(new_owner_meta_addr),
1138 )].inner_perms.ref_count.value() <= REF_COUNT_MAX,
1139 regions.slot_owners[frame_to_index(meta_to_frame(new_owner_meta_addr))].paths_in_pt
1140 == set![new_owner_path],
1141 {
1142 proof {
1143 C::lemma_page_table_config_constant_properties();
1144 C::lemma_paging_consts_properties();
1145 let ghost the_node = new_owner.value.node();
1147
1148 OwnerSubtree::child_some_properties(new_owner, i as usize);
1149 EntryOwner::huge_frame_split_child_at(owner.value, *regions, i as usize);
1150 }
1151
1152 let small_pa = pa + i * page_size(level - 1);
1153
1154 let tracked mut child_owner = EntryOwner::tracked_new_frame(
1155 small_pa,
1156 new_owner.value.path.push_tail(i as usize),
1157 (level - 1) as PagingLevel,
1158 prop,
1159 owner.value.frame().is_tracked,
1161 );
1162
1163 let tracked mut new_owner_child = new_owner.children.tracked_remove(
1164 i as int,
1165 ).tracked_unwrap();
1166
1167 proof {
1168 let idx = frame_to_index(small_pa);
1169 if i != 0 {
1170 let ghost big_j =
1171 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1172 pa, level, i);
1173 }
1174 if level - 1 > 1 {
1175 let nr_subpages = page_size((level - 1) as PagingLevel) / PAGE_SIZE;
1176 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1177 (level - 1) as PagingLevel);
1178 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1179 level);
1180 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
1181 level);
1182 assert forall|j_prime: usize|
1183 #![trigger frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize)]
1184 0 < j_prime < nr_subpages implies {
1185 let sub_idx = frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize);
1186 &&& regions.slots.contains_key(sub_idx)
1187 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1188 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1189 != REF_COUNT_UNUSED
1190 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1191 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1192 <= REF_COUNT_MAX
1193 }
1194 } by {
1195 let sub_pages_per_subframe = page_size((level - 1) as PagingLevel)
1196 / PAGE_SIZE;
1197 let big_j_int: int = i * sub_pages_per_subframe + j_prime;
1198 vstd::arithmetic::mul::lemma_mul_nonnegative(
1199 i as int,
1200 sub_pages_per_subframe as int,
1201 );
1202 vstd::arithmetic::mul::lemma_mul_inequality(
1203 i + 1,
1204 NR_ENTRIES as int,
1205 sub_pages_per_subframe as int,
1206 );
1207 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1208 sub_pages_per_subframe as int,
1209 i as int,
1210 1int,
1211 );
1212 vstd::arithmetic::mul::lemma_mul_is_associative(
1213 NR_ENTRIES as int,
1214 sub_pages_per_subframe as int,
1215 PAGE_SIZE as int,
1216 );
1217 vstd::arithmetic::div_mod::lemma_div_by_multiple(
1218 NR_ENTRIES * sub_pages_per_subframe,
1219 PAGE_SIZE as int,
1220 );
1221 let big_j: usize = big_j_int as usize;
1222 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1223 PAGE_SIZE as int,
1224 i * sub_pages_per_subframe,
1225 j_prime as int,
1226 );
1227 vstd::arithmetic::mul::lemma_mul_is_associative(
1228 i as int,
1229 sub_pages_per_subframe as int,
1230 PAGE_SIZE as int,
1231 );
1232 assert((small_pa + j_prime * PAGE_SIZE) as usize == (pa + big_j
1233 * PAGE_SIZE) as usize);
1234 assert(regions.slots.contains_key(
1240 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1241 ));
1242 }
1243 }
1244 let small_idx = frame_to_index(small_pa);
1245
1246 if i == 0 {
1251 assert(i * page_size((level - 1) as PagingLevel) == 0) by {
1253 vstd::arithmetic::mul::lemma_mul_by_zero_is_zero(
1254 page_size((level - 1) as PagingLevel) as int,
1255 );
1256 }
1257 } else {
1258 let ghost big_j =
1259 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1260 pa, level, i);
1261 assert(regions.slots.contains_key(
1263 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1264 ));
1265 }
1266
1267 regions.inv_implies_correct_addr(small_pa);
1270 let tracked mut small_slot = regions.slot_owners.tracked_remove(small_idx);
1271 small_slot.paths_in_pt = small_slot.paths_in_pt.insert(child_owner.path);
1272 regions.slot_owners.tracked_insert(small_idx, small_slot);
1273
1274 if (level - 1) > 1 {
1277 }
1278 let ghost target_idx = frame_to_index(small_pa);
1279 if i != 0 {
1280 let ghost _ =
1281 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1282 pa, level, i);
1283
1284 }
1285 }
1286
1287 let tracked mut new_owner_node = new_owner.value.tracked_take_node();
1292 let ghost nidx = frame_to_index(meta_to_frame(new_owner_meta_addr));
1296 proof {
1297 }
1301 let ghost regions_pre_replace = *regions;
1302 #[verus_spec(with Tracked(regions),
1303 Tracked(&mut new_owner_child.value),
1304 Tracked(&mut child_owner),
1305 Tracked(&mut new_owner_node))]
1306 pt_lock_guard.replace_absent_with_frame(i, small_pa, level - 1, prop);
1307
1308 proof {
1309 new_owner.value.tracked_put_node(new_owner_node);
1310 OwnerSubtree::set_value_property(new_owner_child, child_owner);
1311 new_owner_child.value = child_owner;
1312 new_owner.children.tracked_insert(i as int, Some(new_owner_child));
1313
1314 TreePath::push_tail_property_len(new_owner_path, i as usize);
1315 OwnerSubtree::insert_preserves_inv(new_owner, i as usize, new_owner_child);
1316
1317 }
1323 }
1324
1325 proof {
1326 }
1331 self.pte = (#[verus_spec(with Tracked(&mut new_owner.value), Tracked(regions))]
1332 Child::PageTable(new_page).into_pte());
1333
1334 proof {
1335 new_owner.level = owner.level;
1336 *owner = new_owner;
1337 }
1338
1339 unsafe {
1344 #[verus_spec(with Tracked(owner.value.tracked_borrow_mut_node()), Tracked(&*regions))]
1345 self.node.write_pte(self.idx, self.pte)
1346 };
1347
1348 Some(pt_lock_guard)
1349 }
1350
1351 #[verus_spec(res =>
1367 with Tracked(owner): Tracked<&EntryOwner<C>>,
1368 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1369 Tracked(regions): Tracked<&MetaRegionOwners>,
1370 requires
1371 owner.inv(),
1372 parent_owner.inv(),
1373 parent_owner.relate_guard(*guard),
1374 idx < NR_ENTRIES,
1375 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1376 regions.inv(),
1377 regions.slots.contains_key(parent_owner.slot_index),
1378 ensures
1379 res.wf(*owner),
1380 res.idx == idx,
1381 parent_owner.relate_guard(*res.node),
1382 *res.node == *old(guard),
1385 *final(guard) == *final(res.node),
1386 )]
1387 pub(in crate::mm) unsafe fn new_at(guard: &'a mut PageTableGuard<'rcu, C>, idx: usize) -> Self {
1388 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1390 let pte = guard.read_pte(idx);
1391 Self::new(pte, idx, guard)
1392 }
1393}
1394
1395#[verus_verify]
1396impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
1397 #[verus_spec(res =>
1398 with Tracked(owner): Tracked<&mut EntryOwner<C>>,
1399 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1400 Tracked(regions): Tracked<&MetaRegionOwners>,
1401 requires
1402 old(owner).inv(),
1403 old(owner).is_frame(),
1404 old(owner).match_pte(
1405 old(parent_owner).children_perm.value()[idx as int],
1406 old(owner).parent_level,
1407 ),
1408 old(parent_owner).inv(),
1409 old(parent_owner).relate_guard(*old(self)),
1410 old(parent_owner).level == old(owner).parent_level,
1411 old(parent_owner).metaregion_sound_node(*regions),
1412 idx < NR_ENTRIES,
1413 op.requires((old(owner).frame().prop,)),
1414 regions.inv(),
1415 regions.slots.contains_key(old(parent_owner).slot_index),
1416 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1417 #![auto]
1418 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
1419 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
1420 ensures
1421 final(owner).inv(),
1422 final(owner).is_frame(),
1423 final(owner).match_pte(res, final(parent_owner).level),
1424 final(owner).match_pte(
1425 final(parent_owner).children_perm.value()[idx as int],
1426 final(parent_owner).level,
1427 ),
1428 res == final(parent_owner).children_perm.value()[idx as int],
1429 final(parent_owner).inv(),
1430 final(parent_owner).slot_index == old(parent_owner).slot_index,
1431 final(parent_owner).level == old(parent_owner).level,
1432 final(parent_owner).tree_level == old(parent_owner).tree_level,
1433 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1434 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1435 final(parent_owner).relate_guard(*final(self)),
1436 final(parent_owner).metaregion_sound_node(*regions),
1437 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
1438 final(owner).frame().is_tracked == old(owner).frame().is_tracked,
1439 final(owner).path == old(owner).path,
1440 final(owner).parent_level == old(owner).parent_level,
1441 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1442 #[trigger] final(parent_owner).children_perm.value()[j]
1443 == old(parent_owner).children_perm.value()[j],
1444 crate::specs::mm::page_table::node::owners::count_present(
1447 final(parent_owner).children_perm.value(),
1448 ) == crate::specs::mm::page_table::node::owners::count_present(
1449 old(parent_owner).children_perm.value(),
1450 ),
1451 op.ensures((old(owner).frame().prop,), final(owner).frame().prop),
1452 *final(self) == *old(self),
1453 )]
1454 pub(in crate::mm) fn protect_child(
1455 &mut self,
1456 idx: usize,
1457 op: impl FnOnce(PageProperty) -> PageProperty,
1458 ) -> C::E {
1459 let ghost cp_old = parent_owner.children_perm.value();
1460 let mut pte = unsafe {
1461 #[verus_spec(with Tracked(&*parent_owner), Tracked(regions))]
1462 self.read_pte(idx)
1463 };
1464
1465 let prop = pte.prop();
1466 let new_prop = op(prop);
1467
1468 assume(pte.set_prop_req(new_prop));
1469 pte.set_prop(new_prop);
1470
1471 unsafe {
1472 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1473 self.write_pte(idx, pte)
1474 };
1475
1476 proof {
1477 owner.tracked_borrow_mut_frame().prop = new_prop;
1478 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1482 cp_old,
1483 NR_ENTRIES as int,
1484 idx as int,
1485 pte,
1486 );
1487 }
1488
1489 pte
1490 }
1491
1492 #[verifier::spinoff_prover]
1493 #[verus_spec(res =>
1494 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
1495 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1496 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1497 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1498 requires
1499 old(owner).inv(),
1500 old(owner).metaregion_sound(*old(regions)),
1501 old(owner).match_pte(
1502 old(parent_owner).children_perm.value()[idx as int],
1503 old(owner).parent_level,
1504 ),
1505 old(parent_owner).inv(),
1506 old(parent_owner).relate_guard(*old(self)),
1507 old(parent_owner).level == old(owner).parent_level,
1508 idx < NR_ENTRIES,
1509 old(regions).inv(),
1510 old(regions).slots.contains_key(old(parent_owner).slot_index),
1511 new_child.invariants(*old(new_owner), *old(regions)),
1512 old(owner).path == old(new_owner).path,
1513 old(owner).parent_level == old(new_owner).parent_level,
1514 old(new_owner).is_node() ==> {
1515 &&& old(regions).slots.contains_key(frame_to_index(old(new_owner).meta_slot_paddr()->0))
1516 &&& old(regions).slot_owners[frame_to_index(
1517 old(new_owner).meta_slot_paddr()->0,
1518 )].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1519 },
1520 old(parent_owner).metaregion_sound_node(*old(regions)),
1521 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
1522 frame_to_index(meta_to_frame(node.ptr.addr())),
1523 ) > 0,
1524 ensures
1525 res.invariants(*final(owner), *final(regions)),
1526 final(new_owner).inv(),
1527 final(new_owner).metaregion_sound(*final(regions)),
1528 final(new_owner).match_pte(
1529 final(parent_owner).children_perm.value()[idx as int],
1530 final(parent_owner).level,
1531 ),
1532 final(new_owner).path == old(new_owner).path,
1533 final(new_owner).parent_level == old(new_owner).parent_level,
1534 *final(owner) == old(owner).from_pte_owner_spec(),
1535 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1536 Entry::<C>::metaregion_sound_neq_preserved(
1537 *old(owner),
1538 *final(new_owner),
1539 *old(regions),
1540 *final(regions),
1541 ),
1542 !final(new_owner).is_node() ==> Entry::<C>::metaregion_sound_neq_old_preserved(
1543 *old(owner),
1544 *old(regions),
1545 *final(regions),
1546 ),
1547 (!old(owner).is_node() && !final(new_owner).is_node())
1548 ==> Entry::<C>::metaregion_sound_preserved(*old(regions), *final(regions)),
1549 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
1550 C,
1551 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
1552 final(parent_owner).inv(),
1553 final(parent_owner).level == old(parent_owner).level,
1554 final(parent_owner).relate_guard(*final(self)),
1555 final(parent_owner).metaregion_sound_node(*final(regions)),
1556 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1557 #[trigger] final(parent_owner).children_perm.value()[j]
1558 == old(parent_owner).children_perm.value()[j],
1559 forall|slot: usize|
1560 #![trigger final(regions).slot_owners[slot].paths_in_pt]
1561 (!final(new_owner).is_node() || final(new_owner).is_absent() || slot
1562 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
1563 ==> final(regions).slot_owners[slot].paths_in_pt == old(
1564 regions,
1565 ).slot_owners[slot].paths_in_pt,
1566 forall|k: usize|
1567 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
1568 k,
1569 ),
1570 forall|slot: usize|
1571 #![trigger final(regions).slot_owners[slot].inner_perms.ref_count.value()]
1572 final(regions).slot_owners[slot].inner_perms.ref_count.value() == old(
1573 regions,
1574 ).slot_owners[slot].inner_perms.ref_count.value(),
1575 forall|slot: usize|
1576 #![trigger final(regions).slot_owners[slot].inner_perms]
1577 final(regions).slot_owners[slot].inner_perms == old(
1578 regions,
1579 ).slot_owners[slot].inner_perms,
1580 final(regions).slots == old(regions).slots,
1581 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
1582 &&& final(regions).slots == old(regions).slots
1583 &&& forall|i: usize|
1584 #![trigger final(regions).slot_owners[i]]
1585 final(regions).slot_owners[i] == old(
1586 regions,
1587 ).slot_owners[i]
1588 &&& final(regions).frame_obligations == old(regions).frame_obligations
1589 },
1590 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: usize|
1591 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
1592 == #[trigger] final(regions).slots[k],
1593 Entry::<C>::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
1594 *final(self) == *old(self),
1595 )]
1596 #[verifier::spinoff_prover]
1597 pub(in crate::mm) fn replace_child(&mut self, idx: usize, new_child: Child<C>) -> Child<C> {
1598 #[cfg(feature = "allow_panic")]
1599 {
1600 let guard_level = self.level();
1601 match &new_child {
1602 Child::PageTable(node) => {
1603 assert!(node.level() == guard_level - 1);
1604 },
1605 Child::Frame(_, level, _) => {
1606 assert!(*level == guard_level);
1607 },
1608 Child::None => {},
1609 }
1610 }
1611
1612 let pte = unsafe {
1613 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1614 self.read_pte(idx)
1615 };
1616
1617 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1618 parent_owner.slot_index,
1619 );
1620 #[verus_spec(with Tracked(parent_meta_perm))]
1621 let level = self.level();
1622
1623 let old_child = unsafe {
1624 #[verus_spec(with Tracked(regions), Tracked(owner))]
1625 Child::from_pte(pte, level)
1626 };
1627
1628 let ghost cp0 = parent_owner.children_perm.value();
1630
1631 if old_child.is_none() && !new_child.is_none() {
1632 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1633 parent_owner.slot_index,
1634 );
1635 #[verus_spec(with Tracked(parent_meta_perm2))]
1636 let nr_children = self.nr_children_mut();
1637 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1638 proof {
1639 parent_owner.nr_children_absent_slot_bound(idx);
1640 }
1641 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
1642 } else if !old_child.is_none() && new_child.is_none() {
1643 let tracked parent_meta_perm3 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1644 parent_owner.slot_index,
1645 );
1646 #[verus_spec(with Tracked(parent_meta_perm3))]
1647 let nr_children = self.nr_children_mut();
1648 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1649 proof {
1650 parent_owner.nr_children_present_slot_bound(idx);
1651 }
1652 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
1653 }
1654 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
1655 let new_pte = new_child.into_pte();
1656
1657 unsafe {
1658 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1659 self.write_pte(idx, new_pte)
1660 };
1661
1662 proof {
1663 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1668 cp0,
1669 NR_ENTRIES as int,
1670 idx as int,
1671 new_pte,
1672 );
1673 }
1674
1675 proof {
1676 if new_owner.is_node() {
1677 let paddr = new_owner.meta_slot_paddr().unwrap();
1678 regions.inv_implies_correct_addr(paddr);
1679
1680 let new_idx = frame_to_index(new_owner.meta_slot_paddr().unwrap());
1681 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
1682 new_meta_slot.paths_in_pt = set![new_owner.path];
1683 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
1684 }
1685 }
1686
1687 proof {
1688 if new_owner.is_node() || new_owner.is_frame() {
1689 let paddr = new_owner.meta_slot_paddr().unwrap();
1690 regions.inv_implies_correct_addr(paddr);
1691 }
1692 }
1693
1694 old_child
1695 }
1696
1697 #[verifier::spinoff_prover]
1698 #[verus_spec(res =>
1699 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
1700 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1701 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1702 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1703 requires
1704 old(owner).inv(),
1705 old(owner).value.is_absent(),
1706 old(owner).level < INC_LEVELS - 1,
1707 old(owner).value.metaregion_sound(*old(regions)),
1708 old(parent_owner).inv(),
1709 old(parent_owner).relate_guard(*old(self)),
1710 old(parent_owner).level == old(owner).value.parent_level,
1711 old(parent_owner).level > 1,
1712 old(parent_owner).metaregion_sound_node(*old(regions)),
1713 idx < NR_ENTRIES,
1714 old(owner).value.match_pte(
1715 old(parent_owner).children_perm.value()[idx as int],
1716 old(owner).value.parent_level,
1717 ),
1718 old(regions).inv(),
1719 old(regions).slots.contains_key(old(parent_owner).slot_index),
1720 ensures
1721 final(owner).inv(),
1722 final(owner).value.is_node(),
1723 final(owner).level == old(owner).level,
1724 final(owner).value.parent_level == old(owner).value.parent_level,
1725 final(owner).value.path == old(owner).value.path,
1726 final(owner).value.metaregion_sound(*final(regions)),
1727 final(owner).value.node().relate_guard(res),
1728 final(owner).value.node().meta_addr_self() == res.inner.inner@.ptr.addr(),
1729 final(owner).value.match_pte(
1730 final(parent_owner).children_perm.value()[idx as int],
1731 final(parent_owner).level,
1732 ),
1733 final(guards).lock_held(final(owner).value.node().meta_addr_self()),
1734 OwnerSubtree::implies(
1735 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
1736 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node().meta_addr_self())),
1737 Entry::<C>::metaregion_sound_neq_preserved(
1738 old(owner).value,
1739 final(owner).value,
1740 *old(regions),
1741 *final(regions),
1742 ),
1743 Entry::<C>::path_tracked_pred_preserved(*old(regions), *final(regions)),
1744 old(regions).slots.contains_key(frame_to_index(final(owner).value.meta_slot_paddr()->0)),
1745 final(owner).tree_predicate_map(final(owner).value.path,
1746 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node().meta_addr_self())),
1747 final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions))),
1748 final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::path_tracked_pred(*final(regions))),
1749 PageTableOwner(*final(owner)).view_rec(final(owner).value.path) == set![],
1750 forall|i: int| 0 <= i < NR_ENTRIES ==>
1751 #[trigger] final(owner).children[i] is Some && final(owner).children[i]->0.value.is_absent(),
1752 forall|i: int| 0 <= i < NR_ENTRIES ==>
1753 (#[trigger] final(owner).children[i])->0.value.path
1754 == final(owner).value.path.push_tail(i as usize),
1755 crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner)),
1756 forall|i: int| 0 <= i < NR_ENTRIES ==>
1757 (#[trigger] final(owner).children[i])->0.value.parent_level
1758 == final(owner).value.node().level,
1759 forall|i: int| 0 <= i < NR_ENTRIES ==>
1760 (#[trigger] final(owner).children[i])->0.value.match_pte(
1761 final(owner).value.node().children_perm.value()[i],
1762 final(owner).children[i]->0.value.parent_level),
1763 forall|i: usize| i != frame_to_index(final(owner).value.meta_slot_paddr()->0) ==>
1764 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i],
1765 forall|i: usize| old(regions).slots.contains_key(i)
1766 ==> (#[trigger] final(regions).slots.contains_key(i)),
1767 forall|i: usize| #![trigger final(regions).slots[i]]
1768 i != frame_to_index(final(owner).value.meta_slot_paddr()->0)
1769 && old(regions).slots.contains_key(i)
1770 ==> final(regions).slots[i] == old(regions).slots[i],
1771 final(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr()->0)]
1772 .inner_perms.ref_count.value() != REF_COUNT_UNUSED,
1773 old(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr().unwrap())]
1774 .inner_perms.ref_count.value() == REF_COUNT_UNUSED,
1775 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
1776 final(owner).value.meta_slot_paddr().unwrap()),
1777 final(regions).inv(),
1778 final(parent_owner).inv(),
1779 final(parent_owner).level == old(parent_owner).level,
1780 final(parent_owner).relate_guard(*final(self)),
1781 final(parent_owner).metaregion_sound_node(*final(regions)),
1782 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1783 #[trigger] final(parent_owner).children_perm.value()[j]
1784 == old(parent_owner).children_perm.value()[j],
1785 *final(self) == *old(self),
1786 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
1787 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value.node().meta_addr_self() ==> final(guards).unlocked(i),
1788 )]
1789 pub(in crate::mm) fn alloc_absent_child<A: InAtomicMode>(
1790 &mut self,
1791 idx: usize,
1792 guard: &'rcu A,
1793 ) -> PageTableGuard<'rcu, C> {
1794 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1795 parent_owner.slot_index,
1796 );
1797 #[verus_spec(with Tracked(parent_meta_perm))]
1798 let level = self.level();
1799
1800 let ghost old_path = owner.value.path;
1801
1802 proof {
1808 parent_owner.nr_children_absent_slot_bound(idx);
1809 }
1810 let ghost regions_pre = *regions;
1811 let ghost cp0 = parent_owner.children_perm.value();
1814 let ghost old_owner_val = owner.value;
1817
1818 proof_decl! {
1819 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
1820 }
1821
1822 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(idx) => Tracked(new_node_owner))]
1823 let new_page = PageTableNode::<C>::alloc(level - 1);
1824
1825 proof {
1826 let pte = C::E::new_pt_spec(
1827 meta_to_frame(new_node_owner.value.node().meta_addr_self()),
1828 );
1829 old(parent_owner).set_children_perm_axiom(idx, pte);
1830 C::E::lemma_page_table_entry_properties();
1831 }
1832
1833 let ghost new_node_slot_idx = new_node_owner.value.node().slot_index;
1834 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
1835 #[verus_spec(with Tracked(new_node_slot_perm))]
1836 let paddr = new_page.start_paddr();
1837
1838 #[verus_spec(with Tracked(&mut new_node_owner.value), Tracked(regions))]
1839 let new_pte = Child::PageTable(new_page).into_pte();
1840
1841 proof {
1842 broadcast use group_page_meta;
1843
1844 }
1845
1846 let pt_ref = unsafe {
1847 #[verus_spec(with Tracked(regions))]
1848 PageTableNodeRef::borrow_paddr(paddr)
1849 };
1850
1851 #[verus_spec(with Tracked(&new_node_owner.value.tracked_borrow_node()), Tracked(guards))]
1852 let pt_lock_guard = pt_ref.lock(guard);
1853
1854 unsafe {
1855 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1856 self.write_pte(idx, new_pte)
1857 };
1858
1859 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1867 parent_owner.slot_index,
1868 );
1869 #[verus_spec(with Tracked(parent_meta_perm2))]
1870 let nr_children = self.nr_children_mut();
1871 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1872 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1873
1874 proof {
1875 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1880 cp0,
1881 NR_ENTRIES as int,
1882 idx as int,
1883 new_pte,
1884 );
1885 }
1886
1887 proof {
1888 owner.value = new_node_owner.value;
1889 owner.value.parent_level = level as PagingLevel;
1890 owner.value.path = old_path;
1891 owner.children = new_node_owner.children;
1892 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
1893
1894 let new_paddr = owner.value.meta_slot_paddr().unwrap();
1895 regions.inv_implies_correct_addr(new_paddr);
1896 let new_idx = frame_to_index(new_paddr);
1897 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
1898 new_meta_slot.paths_in_pt = set![owner.value.path];
1899 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
1900 }
1901
1902 proof {
1903 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1907 let ghost new_node_addr = owner.value.node().meta_addr_self();
1915 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
1916 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
1917 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
1918
1919 assert forall|i: int| 0 <= i < NR_ENTRIES implies {
1923 &&& #[trigger] f_nu(
1924 owner.children[i].unwrap().value,
1925 owner.value.path.push_tail(i as usize),
1926 )
1927 &&& f_ms(owner.children[i].unwrap().value, owner.value.path.push_tail(i as usize))
1928 &&& f_pt(owner.children[i].unwrap().value, owner.value.path.push_tail(i as usize))
1929 } by {};
1930
1931 crate::specs::mm::page_table::fresh_node_tree_predicate_map(
1932 *owner,
1933 owner.value.path,
1934 f_nu,
1935 );
1936 crate::specs::mm::page_table::fresh_node_tree_predicate_map(
1937 *owner,
1938 owner.value.path,
1939 f_ms,
1940 );
1941 crate::specs::mm::page_table::fresh_node_tree_predicate_map(
1942 *owner,
1943 owner.value.path,
1944 f_pt,
1945 );
1946 }
1947
1948 pt_lock_guard
1949 }
1950
1951 #[verifier::spinoff_prover]
1952 #[verus_spec(
1953 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
1954 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1955 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1956 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1957 requires
1958 old(owner).inv(),
1959 old(owner).is_absent(),
1960 old(owner).metaregion_sound(*old(regions)),
1961 old(parent_owner).inv(),
1962 old(parent_owner).relate_guard(*old(self)),
1963 old(parent_owner).level == old(owner).parent_level,
1964 idx < NR_ENTRIES,
1965 old(owner).match_pte(
1966 old(parent_owner).children_perm.value()[idx as int],
1967 old(owner).parent_level,
1968 ),
1969 old(regions).inv(),
1970 old(regions).slots.contains_key(old(parent_owner).slot_index),
1971 old(parent_owner).metaregion_sound_node(*old(regions)),
1972 Child::<C>::Frame(paddr, level, prop).invariants(*old(new_owner), *old(regions)),
1973 old(owner).path == old(new_owner).path,
1974 old(owner).parent_level == old(new_owner).parent_level,
1975 ensures
1976 final(new_owner).inv(),
1977 final(parent_owner).inv(),
1978 *final(owner) == old(owner).from_pte_owner_spec(),
1979 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1980 final(new_owner).pte_invariants(
1981 final(parent_owner).children_perm.value()[idx as int],
1982 *final(regions),
1983 ),
1984 forall|i: int|
1985 0 <= i < NR_ENTRIES && i != idx ==> #[trigger] old(parent_owner).children_perm.value()[i]
1986 == final(parent_owner).children_perm.value()[i],
1987 final(parent_owner).slot_index == old(parent_owner).slot_index,
1988 final(parent_owner).level == old(parent_owner).level,
1989 final(parent_owner).tree_level == old(parent_owner).tree_level,
1990 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1991 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1992 final(parent_owner).relate_guard(*final(self)),
1993 final(parent_owner).metaregion_sound_node(*final(regions)),
1994 *final(regions) == *old(regions),
1995 *final(self) == *old(self),
1996 )]
1997 pub(in crate::mm) fn replace_absent_with_frame(
1998 &mut self,
1999 idx: usize,
2000 paddr: Paddr,
2001 level: PagingLevel,
2002 prop: PageProperty,
2003 ) {
2004 let ghost cp0 = parent_owner.children_perm.value();
2006 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
2007 parent_owner.slot_index,
2008 );
2009 #[verus_spec(with Tracked(parent_meta_perm))]
2010 let nr_children = self.nr_children_mut();
2011 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
2012 proof {
2013 parent_owner.nr_children_absent_slot_bound(idx);
2014 }
2015 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
2016
2017 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
2018 let new_pte = Child::<C>::Frame(paddr, level, prop).into_pte();
2019
2020 unsafe {
2021 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
2022 self.write_pte(idx, new_pte)
2023 };
2024
2025 proof {
2026 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
2030 cp0,
2031 NR_ENTRIES as int,
2032 idx as int,
2033 new_pte,
2034 );
2035 }
2036 }
2037}
2038
2039}