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, meta_to_index},
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, nr_subpage_per_huge_spec, page_prop::PageProperty},
29 };
32
33use super::*;
34
35verus! {
36
37broadcast use group_ghost_tree_lemmas;
38
39pub type PageTableNodeRef<'a, C> = FrameRef<'a, PageTablePageMeta<C>>;
41
42pub struct PageTableGuard<'rcu, C: PageTableConfig> {
44 pub inner: PageTableNodeRef<'rcu, C>,
45}
46
47impl<'rcu, C: PageTableConfig> Deref for PageTableGuard<'rcu, C> {
48 type Target = PageTableNodeRef<'rcu, C>;
49
50 #[verus_spec(ensures returns self.inner)]
51 fn deref(&self) -> &Self::Target {
52 &self.inner
53 }
54}
55
56pub struct Entry<'a, 'rcu, C: PageTableConfig> {
57 pub pte: C::E,
76 pub idx: usize,
78 pub node: &'a mut PageTableGuard<'rcu, C>,
80}
81
82#[verus_verify]
83impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
84 pub open spec fn new_spec(
85 pte: C::E,
86 idx: usize,
87 node: &'a mut PageTableGuard<'rcu, C>,
88 ) -> Self {
89 Self { pte, idx, node }
90 }
91
92 #[verus_spec(res =>
93 ensures
94 res.pte == pte,
95 res.idx == idx,
96 *res.node == *old(node),
97 *final(node) == *final(res.node),
98 )]
99 pub fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> Self {
100 Self { pte, idx, node }
101 }
102}
103
104#[verus_verify]
105impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
106 #[verus_spec(r =>
108 with Tracked(owner): Tracked<&EntryOwner<C>>,
109 requires
110 self.wf(*owner),
111 owner.inv(),
112 returns owner.is_absent(),
113 )]
114 pub(in crate::mm) fn is_none(&self) -> bool {
115 !self.pte.is_present()
116 }
117
118 #[verus_spec(
120 with Tracked(owner): Tracked<EntryOwner<C>>,
121 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
122 Tracked(regions): Tracked<&MetaRegionOwners>,
123 requires
124 owner.inv(),
125 self.wf(owner),
126 parent_owner.relate_guard(*self.node),
127 parent_owner.inv(),
128 parent_owner.level == owner.parent_level,
129 regions.inv(),
130 parent_owner.metaregion_sound_node(*regions),
131 returns
132 owner.is_node(),
133 )]
134 pub(in crate::mm) fn is_node(&self) -> bool {
135 self.pte.is_present() && !self.pte.is_last(
136 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
137 self.node.level(),
138 )
139 }
140
141 #[verus_spec(res =>
143 with Tracked(owner): Tracked<&EntryOwner<C>>,
144 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
145 Tracked(regions): Tracked<&mut MetaRegionOwners>,
146 requires
147 self.invariants(*owner, *old(regions)),
148 self.node_matching(*owner, *parent_owner, *self.node),
149 parent_owner.metaregion_sound_node(*old(regions)),
150 ensures
151 res.invariants(*owner, *final(regions)),
152 final(regions).slot_owners == old(regions).slot_owners,
153 forall|k: int|
154 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
155 k,
156 ),
157 forall|k: int|
158 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
159 == #[trigger] final(regions).slots[k],
160 final(regions).inv(),
161 )]
162 pub(in crate::mm) fn to_ref(&self) -> ChildRef<'rcu, C> {
163 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
164 let level = self.node.level();
165
166 let res = unsafe {
170 #[verus_spec(with Tracked(regions), Tracked(owner))]
171 ChildRef::from_pte(&self.pte, level)
172 };
173
174 res
175 }
176
177 #[verus_spec(
194 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
195 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
196 Tracked(regions): Tracked<&MetaRegionOwners>,
197 requires
198 old(owner).inv(),
199 old(self).wf(*old(owner)),
200 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
201 op.requires((old(self).pte.prop(),)),
202 old(owner).is_frame(),
203 regions.inv(),
204 regions.slots.contains_key(old(parent_owner).slot_index),
205 old(parent_owner).metaregion_sound_node(*regions),
206 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
212 #![auto]
213 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
214 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
215 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
216 #![auto]
217 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
218 ==> C::E::new_page_req(pa, level, p_out),
219 ensures
220 final(owner).inv(),
221 final(self).wf(*final(owner)),
222 final(self).node_matching(*final(owner), *final(parent_owner), *final(self).node),
223 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
224 final(owner).is_frame(),
225 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
226 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
227 final(owner).path == old(owner).path,
228 final(owner).parent_level == old(owner).parent_level,
229 final(self).idx == old(self).idx,
230 *final(self).node == *old(self).node,
231 old(self).pte.is_present() ==> op.ensures(
232 (old(owner).frame().prop,),
233 final(owner).frame().prop,
234 ),
235 crate::specs::mm::page_table::node::owners::count_present(
240 final(parent_owner).children_perm.value(),
241 ) == crate::specs::mm::page_table::node::owners::count_present(
242 old(parent_owner).children_perm.value(),
243 ),
244 final(parent_owner).meta_own.nr_children.value() == old(
245 parent_owner,
246 ).meta_own.nr_children.value(),
247 )]
248 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty) {
249 #[verus_spec(with Tracked(owner), Tracked(parent_owner), Tracked(regions))]
250 let pte = self.node.protect_child(self.idx, op);
251 self.pte = pte;
252 }
253
254 #[verus_spec(res =>
275 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
276 Tracked(owner): Tracked<&mut EntryOwner<C>>,
277 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
278 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
279 requires
280 old(self).invariants(*old(owner), *old(regions)),
281 new_child.invariants(*old(new_owner), *old(regions)),
282 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
283 old(self).new_owner_compatible(new_child, *old(owner), *old(new_owner), *old(regions)),
284 old(parent_owner).metaregion_sound_node(*old(regions)),
285 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
286 meta_to_index(node.ptr.addr()),
287 ) > 0,
288 ensures
289 final(self).invariants(*final(new_owner), *final(regions)),
290 res.invariants(*final(owner), *final(regions)),
291 final(self).node_matching(*final(new_owner), *final(parent_owner), *final(self).node),
292 final(self).idx == old(self).idx,
293 *final(self).node == *old(self).node,
294 *final(owner) == old(owner).from_pte_owner_spec(),
295 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
296 Self::metaregion_sound_neq_preserved(
297 *old(owner),
298 *final(new_owner),
299 *old(regions),
300 *final(regions),
301 ),
302 !final(new_owner).is_node() ==> Self::metaregion_sound_neq_old_preserved(
303 *old(owner),
304 *old(regions),
305 *final(regions),
306 ),
307 (!old(owner).is_node() && !final(new_owner).is_node())
308 ==> Self::metaregion_sound_preserved(*old(regions), *final(regions)),
309 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
310 C,
311 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
312 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
313 final(parent_owner).metaregion_sound_node(*final(regions)),
314 forall|idx: int|
316 #![trigger final(regions).slot_owners[idx].paths_in_pt]
317 (!final(new_owner).is_node() || final(new_owner).is_absent() || idx
318 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
319 ==> final(regions).slot_owners[idx].paths_in_pt == old(
320 regions,
321 ).slot_owners[idx].paths_in_pt,
322 forall|k: int|
324 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
325 k,
326 ),
327 forall|idx: int|
333 #![trigger final(regions).slot_owners[idx].ref_count()]
334 final(regions).slot_owners[idx].ref_count() == old(
335 regions,
336 ).slot_owners[idx].ref_count(),
337 forall|idx: int|
338 #![trigger final(regions).slot_owners[idx]]
339 final(regions).slot_owners[idx].same_permissions(
340 old(regions).slot_owners[idx],
341 ),
342 final(regions).slots == old(regions).slots,
343 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
345 &&& final(regions).slots == old(regions).slots
346 &&& forall|i: int|
347 #![trigger final(regions).slot_owners[i]]
348 final(regions).slot_owners[i] == old(
349 regions,
350 ).slot_owners[i]
351 &&& final(regions).frame_obligations == old(regions).frame_obligations
357 },
358 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
360 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
361 == #[trigger] final(regions).slots[k],
362 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
363 )]
364 #[verifier::spinoff_prover]
365 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> Child<C> {
366 let ghost cp0 = parent_owner.children_perm.value();
370
371 #[cfg(feature = "allow_panic")]
372 {
373 let guard_level = self.node.level();
374 match &new_child {
375 Child::PageTable(node) => {
376 assert!(node.level() == guard_level - 1);
377 },
378 Child::Frame(_, level, _) => {
379 assert!(*level == guard_level);
380 },
381 Child::None => {},
382 }
383 }
384
385 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
389 let level = self.node.level();
390
391 let old_child = unsafe {
392 #[verus_spec(with Tracked(regions), Tracked(owner))]
393 Child::from_pte(self.pte, level)
394 };
395
396 if old_child.is_none() && !new_child.is_none() {
397 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
398 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
399 parent_owner.slot_index,
400 );
401 #[verus_spec(with
402 Tracked(meta_points_to),
403 Tracked(&meta_slot_owner.metadata_perm),
404 Ghost(parent_owner.meta_own.nr_children.id())
405 )]
406 let nr_children = self.node.nr_children_mut();
407 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
408 proof {
409 parent_owner.nr_children_absent_slot_bound(self.idx);
410 }
411 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
412 } else if !old_child.is_none() && new_child.is_none() {
413 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
414 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
415 parent_owner.slot_index,
416 );
417 #[verus_spec(with
418 Tracked(meta_points_to),
419 Tracked(&meta_slot_owner.metadata_perm),
420 Ghost(parent_owner.meta_own.nr_children.id())
421 )]
422 let nr_children = self.node.nr_children_mut();
423 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
424 proof {
425 parent_owner.nr_children_present_slot_bound(self.idx);
426 }
427 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
428 }
429 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
430 let new_pte = new_child.into_pte();
431
432 unsafe {
437 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
438 self.node.write_pte(self.idx, new_pte)
439 };
440
441 self.pte = new_pte;
442
443 proof {
444 if new_owner.is_node() {
451 let paddr = new_owner.meta_slot_paddr().unwrap();
452 regions.lemma_contains_valid_frame_paddr(paddr);
453
454 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
455 new_meta_slot.paths_in_pt = set![new_owner.path];
456 }
457 }
458
459 proof {
460 if new_owner.is_node() || new_owner.is_frame() {
461 let paddr = new_owner.meta_slot_paddr().unwrap();
462 regions.lemma_contains_valid_frame_paddr(paddr);
463 }
464 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
465 cp0,
466 NR_ENTRIES as int,
467 self.idx as int,
468 new_pte,
469 );
470 }
471
472 old_child
473 }
474
475 #[verus_spec(res =>
492 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
493 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
494 Tracked(regions): Tracked<&mut MetaRegionOwners>,
495 Tracked(guards): Tracked<&mut Guards<'rcu>>,
496 requires
497 old(self).invariants(old(owner).value(), *old(regions)),
498 old(owner).inv(),
499 old(self).node_matching(old(owner).value(), *old(parent_owner), *old(self).node),
500 old(owner).level() < INC_LEVELS - 1,
501 old(owner).level() + old(parent_owner).level == INC_LEVELS,
506 old(parent_owner).metaregion_sound_node(*old(regions)),
507 ensures
508 final(self).invariants(final(owner).value(), *final(regions)),
509 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
510 final(self).idx == old(self).idx,
511 final(parent_owner).count_consistent(),
512 *final(self).node == *old(self).node,
513 old(owner).value().is_absent() && old(parent_owner).level > 1 ==> {
514 &&& final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node)
515 &&& final(owner).inv()
516 },
517 old(owner).value().is_absent() && old(parent_owner).level > 1 ==> {
518 &&& res is Some
519 &&& final(owner).value().is_node()
520 &&& final(owner).level() == old(owner).level()
521 &&& final(owner).value().parent_level == old(owner).value().parent_level
522 &&& final(guards).lock_held(final(owner).value().node().meta_vaddr())
523 &&& final(owner).value().node().relate_guard(res->0)
524 &&& final(owner).value().path == old(owner).value().path
525 &&& final(owner).value().metaregion_sound(*final(regions))
526 &&& OwnerSubtree::implies(
527 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
528 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr()))
529 &&& Self::metaregion_sound_neq_preserved(old(owner).value(), final(owner).value(), *old(regions), *final(regions))
530 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
531 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0))
532 &&& final(owner).subtree_satisfies(final(owner).value().path,
533 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr()))
534 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
535 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
536 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![]
537 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
539 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent()
540 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
547 (#[trigger] final(owner).children()[i])->0.value().path
548 == final(owner).value().path.push_tail(i)
549 &&& crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner))
553 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
555 (#[trigger] final(owner).child(i)).value().parent_level
556 == final(owner).value().node().level
557 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
558 (#[trigger] final(owner).child(i)).value().match_pte(
559 final(owner).value().node().children_perm.value()[i],
560 final(owner).child(i).value().parent_level)
561 &&& forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
563 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
564 &&& forall|i: int| old(regions).slots.contains_key(i)
566 ==> (#[trigger] final(regions).slots.contains_key(i))
567 &&& forall|i: int| #![trigger final(regions).slots[i]]
568 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
569 && old(regions).slots.contains_key(i)
570 ==> final(regions).slots[i] == old(regions).slots[i]
571 &&& final(regions).slot_owner(final(owner).value().meta_slot_paddr()->0)
573 .ref_count() != REF_COUNT_UNUSED
574 &&& old(regions).slot_owner(final(owner).value().meta_slot_paddr().unwrap())
576 .ref_count() == REF_COUNT_UNUSED
577 &&& !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
579 final(owner).value().meta_slot_paddr().unwrap())
580 },
581 !old(owner).value().is_absent() ==> {
582 &&& res is None
583 &&& *final(owner) == *old(owner)
584 },
585 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
586 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().meta_vaddr() ==> final(guards).unlocked(i),
587 )]
588 #[verifier::spinoff_prover]
589 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
590 PageTableGuard<'rcu, C>,
591 > {
592 let entry_is_present = self.pte.is_present();
593 let ghost cp0 = parent_owner.children_perm.value();
595
596 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
597 let level = self.node.level();
598
599 if entry_is_present || level <= 1 {
600 None
601 } else {
602 let ghost old_path = owner.value().path;
603 let ghost old_owner_val = owner.value();
604
605 proof {
606 parent_owner.nr_children_absent_slot_bound(self.idx);
607 }
608
609 proof_decl! {
610 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
611 }
612
613 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
614 let new_page = PageTableNode::<C>::alloc(level - 1);
615 let ghost fresh_children = new_node_owner.children();
616 proof {
617 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
618 #[trigger] fresh_children[i]) is Some by {
619 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
620 new_node_owner,
621 (level - 1) as PagingLevel,
622 ));
623 assert(new_node_owner.has_child(i));
624 };
625 }
626
627 proof {
628 let pte = C::E::new_pt_spec(
629 meta_to_frame(new_node_owner.value().node().meta_vaddr()),
630 );
631 C::E::lemma_page_table_entry_properties();
632 }
633
634 let ghost new_node_slot_idx = new_node_owner.value().node().slot_index;
635 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
636 #[verus_spec(with Tracked(new_node_slot_perm))]
637 let paddr = new_page.start_paddr();
638
639 let new_pte = {
640 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
641 #[verus_spec(with Tracked(new_node_value), Tracked(regions))]
642 Child::PageTable(new_page).into_pte()
643 };
644 self.pte = new_pte;
645
646 let pt_ref = unsafe {
647 #[verus_spec(with Tracked(regions))]
648 PageTableNodeRef::borrow_paddr(paddr)
649 };
650
651 let mut pt_lock_guard = {
653 let tracked new_node_value = new_node_owner.tracked_borrow_value();
654 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
655 pt_ref.lock(guard)
656 };
657
658 unsafe {
663 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
664 self.node.write_pte(self.idx, self.pte)
665 };
666
667 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
668 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
669 parent_owner.slot_index,
670 );
671 #[verus_spec(with
672 Tracked(meta_points_to),
673 Tracked(&meta_slot_owner.metadata_perm),
674 Ghost(parent_owner.meta_own.nr_children.id())
675 )]
676 let nr_children = self.node.nr_children_mut();
677 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
678 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
679
680 proof {
681 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
688 new_node_value.parent_level = level as PagingLevel;
689 new_node_value.path = old_path;
690 *owner = new_node_owner;
691 assert(owner.children() == fresh_children);
695 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
696 #[trigger] owner.children()[i]) is Some by {};
697 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
698
699 let new_paddr = owner.value().meta_slot_paddr().unwrap();
700 regions.lemma_contains_valid_frame_paddr(new_paddr);
701 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
702 new_meta_slot.paths_in_pt = set![owner.value().path];
703
704 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
708 cp0,
709 NR_ENTRIES as int,
710 self.idx as int,
711 self.pte,
712 );
713
714 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
718 let ghost new_node_addr = owner.value().node().meta_vaddr();
724 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
725 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
726 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
727
728 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
729 *owner,
730 owner.value().path,
731 f_nu,
732 );
733 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
734 *owner,
735 owner.value().path,
736 f_ms,
737 );
738 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
739 *owner,
740 owner.value().path,
741 f_pt,
742 );
743 }
744
745 Some(pt_lock_guard)
746 }
747 }
748
749 #[verifier::spinoff_prover]
765 #[verifier::rlimit(200)]
766 #[verus_spec(res =>
767 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
768 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
769 Tracked(regions): Tracked<&mut MetaRegionOwners>,
770 Tracked(guards): Tracked<&mut Guards<'rcu>>
771 requires
772 old(regions).inv(),
773 old(owner).inv(),
774 old(self).wf(old(owner).value()),
775 old(parent_owner).relate_guard(*old(self).node),
776 old(parent_owner).inv(),
777 old(parent_owner).level == old(owner).value().parent_level,
778 old(parent_owner).level < NR_LEVELS,
779 old(parent_owner).metaregion_sound_node(*old(regions)),
780 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
786 old(owner).value().metaregion_sound(*old(regions)),
787 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
791 forall |j: usize| #![trigger frame_to_index(
792 (old(owner).value().frame().mapped_pa
793 + j * PAGE_SIZE) as usize)]
794 0 < j < page_size(old(parent_owner).level) / PAGE_SIZE ==> {
795 let sub_idx = frame_to_index(
796 (old(owner).value().frame().mapped_pa
797 + j * PAGE_SIZE) as usize);
798 &&& old(regions).slots.contains_key(sub_idx)
799 &&& old(regions).slot_owners[sub_idx].usage !is MMIO ==>
800 old(regions).slot_owners[sub_idx].ref_count()
801 != REF_COUNT_UNUSED
802 },
803 ensures
804 old(owner).value().is_frame() && old(parent_owner).level > 1 ==> {
805 &&& res is Some
806 &&& final(owner).value().is_node()
807 &&& final(owner).level() == old(owner).level()
808 &&& final(parent_owner).relate_guard(*final(self).node)
809 &&& final(owner).value().node().relate_guard(res->0)
810 &&& final(owner).value().node().meta_vaddr() == res->0.inner.inner@.ptr.addr()
811 &&& final(guards).lock_held(res->0.inner.inner@.ptr.addr())
812 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
814 (#[trigger] final(owner).children()[j])->0.value().is_frame()
815 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
816 (#[trigger] final(owner).children()[j])->0.value().frame().prop
817 == old(owner).value().frame().prop
818 &&& final(owner).value().path == old(owner).value().path
819 &&& final(owner).value().metaregion_sound(*final(regions))
820 &&& OwnerSubtree::implies(
821 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
822 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
823 &&& OwnerSubtree::implies(
824 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
825 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
826 &&& final(owner).subtree_satisfies(final(owner).value().path,
827 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
828 &&& final(owner).subtree_satisfies(final(owner).value().path,
829 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
830 },
831 !old(owner).value().is_frame() || old(parent_owner).level <= 1 ==> {
832 &&& res is None
833 &&& *final(owner) == *old(owner)
834 },
835 final(owner).inv(),
836 final(owner).value().parent_level == old(owner).value().parent_level,
837 final(self).idx == old(self).idx,
838 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
839 final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node),
840 final(regions).inv(),
841 final(parent_owner).inv(),
842 final(parent_owner).level == old(parent_owner).level,
843 final(self).node.inner.inner@.ptr.addr() == old(self).node.inner.inner@.ptr.addr(),
844 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
845 forall |i: usize| old(guards).unlocked(i) ==> final(guards).unlocked(i),
846 old(owner).value().is_frame() && old(parent_owner).level > 1 ==> {
848 &&& forall|i: int| i != meta_to_index(final(owner).value().node().meta_vaddr()) ==>
849 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
850 &&& forall|i: int| old(regions).slots.contains_key(i)
852 ==> (#[trigger] final(regions).slots.contains_key(i))
853 &&& final(regions).slot_owners[meta_to_index(final(owner).value().node().meta_vaddr())]
855 .ref_count() != REF_COUNT_UNUSED
856 &&& old(regions).slot_owners[meta_to_index(final(owner).value().node().meta_vaddr())]
858 .ref_count() == REF_COUNT_UNUSED
859 },
860 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
865 forall|j: int| 0 <= j < NR_ENTRIES && j != old(self).idx ==>
866 #[trigger] final(parent_owner).children_perm.value()[j]
867 == old(parent_owner).children_perm.value()[j],
868 )]
869 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
870 PageTableGuard<'rcu, C>,
871 > {
872 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
873 let level = self.node.level();
874
875 if !(self.pte.is_last(level) && level > 1) {
876 return None;
877 }
878 let pa = self.pte.paddr();
879 let prop = self.pte.prop();
880
881 proof {
882 EntryOwner::last_pte_implies_frame_match(owner.value(), self.pte, level);
883 }
884
885 proof_decl!{
886 let tracked mut new_owner: OwnerSubtree<C>;
887 }
888
889 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
892 let new_page = PageTableNode::<C>::alloc(level - 1);
893 proof {
894 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
895 #[trigger] new_owner.children()[i]) is Some by {
896 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
897 new_owner,
898 (level - 1) as PagingLevel,
899 ));
900 assert(new_owner.has_child(i));
901 };
902 }
903
904 let ghost new_owner_slot_idx = new_owner.value().node().slot_index;
905 let tracked new_owner_slot_perm = regions.slots.tracked_borrow(new_owner_slot_idx);
906 #[verus_spec(with Tracked(new_owner_slot_perm))]
907 let paddr = new_page.start_paddr();
908
909 proof {
910 broadcast use group_page_meta;
911
912 }
913
914 let pt_ref = unsafe {
915 #[verus_spec(with Tracked(regions))]
916 PageTableNodeRef::borrow_paddr(paddr)
917 };
918
919 let mut pt_lock_guard = {
921 let tracked new_owner_value = new_owner.tracked_borrow_value();
922 #[verus_spec(with Tracked(new_owner_value.tracked_borrow_node()), Tracked(guards))]
923 pt_ref.lock(guard)
924 };
925
926 let ghost children_perm = new_owner.value().node().children_perm;
927 let ghost new_owner_path = new_owner.value().path;
928 let ghost new_owner_meta_addr = new_owner.value().node().meta_vaddr();
929
930 proof {
931 broadcast use crate::specs::mm::frame::mapping::lemma_frame_to_index_injective;
943 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
944 broadcast use group_page_meta;
945
946 let new_idx = meta_to_index(new_owner_meta_addr);
947 let new_paddr = meta_to_frame(new_owner_meta_addr);
948 let nr_pages = page_size(level) / PAGE_SIZE;
949
950 let pa_idx = frame_to_index(pa);
954 assert(pa_idx != new_idx) by {
955 if old(regions).slot_owners[pa_idx].usage
956 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
957 old(regions).lemma_contains_valid_frame_paddr(pa);
958 } else {
959 }
961 };
962
963 assert forall|j: usize|
965 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
966 0 < j < nr_pages implies {
967 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
968 &&& regions.slots.contains_key(sub_idx)
969 &&& regions.slot_owners[sub_idx].usage
970 != crate::specs::mm::frame::meta_owners::PageUsage::PageTable
971 &&& regions.slot_owners[sub_idx].usage
972 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
973 &&& regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
974 &&& regions.slot_owners[sub_idx].ref_count() > 0
975 &&& regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
976 }
977 } by {
978 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
979 assert(sub_idx != new_idx) by {
980 if old(regions).slot_owners[sub_idx].usage
981 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
982 old(regions).lemma_contains_valid_frame_paddr(
983 (pa + j * PAGE_SIZE) as usize,
984 );
985 } else {
986 }
988 };
989 };
990 }
991
992 proof {
993 C::lemma_paging_consts_properties();
994 assert(nr_subpage_per_huge_spec::<C>() == NR_ENTRIES);
995 }
996
997 for i in 0..nr_subpage_per_huge::<C>()
998 invariant
999 nr_subpage_per_huge_spec::<C>() == NR_ENTRIES,
1000 1 < level < NR_LEVELS,
1001 owner.inv(),
1002 owner.value().is_frame(),
1003 owner.value().parent_level == level,
1004 owner.value().frame().mapped_pa == pa,
1005 owner.value().frame().prop == prop,
1006 pa == old(owner).value().frame().mapped_pa,
1007 level == old(parent_owner).level,
1008 pa % page_size(level) == 0,
1009 pa + page_size(level) <= MAX_PADDR,
1010 regions.inv(),
1011 regions.frame_obligations.count(meta_to_index(new_owner_meta_addr)) > 0,
1016 parent_owner.inv(),
1017 new_owner.value().is_node(),
1018 new_owner.inv(),
1019 new_owner.value().path == new_owner_path,
1020 new_owner.value().node().meta_vaddr() == new_owner_meta_addr,
1021 new_owner.value().node().relate_guard(pt_lock_guard),
1022 guards.lock_held(new_owner_meta_addr),
1023 new_owner.value().node().level == (level - 1) as PagingLevel,
1024 forall|j: int| 0 <= j < NR_ENTRIES ==> (#[trigger] new_owner.children()[j]) is Some,
1025 forall|j: int|
1026 0 <= j < NR_ENTRIES ==> {
1027 &&& (#[trigger] new_owner.children()[j]) is Some
1028 &&& new_owner.children()[j].unwrap().value().match_pte(
1029 new_owner.value().node().children_perm.value()[j],
1030 new_owner.value().node().level,
1031 )
1032 &&& new_owner.children()[j].unwrap().value().parent_level
1033 == new_owner.value().node().level
1034 &&& new_owner.children()[j].unwrap().value().inv()
1035 &&& new_owner.children()[j].unwrap().value().path
1036 == new_owner_path.push_tail(j)
1037 },
1038 forall|j: int|
1039 i <= j < NR_ENTRIES ==> {
1040 &&& (#[trigger] new_owner.children()[j]) is Some
1041 &&& new_owner.children()[j].unwrap().value().is_absent()
1042 &&& new_owner.value().node().children_perm.value()[j]
1043 == C::E::new_absent_spec()
1044 },
1045 forall|j: int|
1047 0 <= j < i ==> {
1048 &&& (#[trigger] new_owner.children()[j]) is Some
1049 &&& new_owner.children()[j].unwrap().value().is_frame()
1050 },
1051 forall|j: usize|
1055 #![trigger frame_to_index(
1056 (pa + j * PAGE_SIZE) as usize)]
1057 0 < j < page_size(level) / PAGE_SIZE ==> {
1058 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1059 &&& regions.slots.contains_key(sub_idx)
1060 &&& regions.slot_owners[sub_idx].usage !is PageTable
1061 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1062 &&& regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1063 &&& regions.slot_owners[sub_idx].ref_count() > 0
1064 &&& regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
1065 }
1066 },
1067 regions.slots.contains_key(frame_to_index(pa)),
1069 regions.slot_owner(pa).usage !is PageTable,
1070 regions.slot_owner(pa).usage !is MMIO ==> {
1071 &&& regions.slot_owner(pa).ref_count() != REF_COUNT_UNUSED
1072 &&& 0 < regions.slot_owner(pa).ref_count() <= REF_COUNT_MAX
1073 },
1074 new_page.ptr.addr() == new_owner_meta_addr,
1075 new_owner.value().node().metaregion_sound_node(*regions),
1076 regions.slot_owners[meta_to_index(new_owner_meta_addr)].ref_count()
1081 != REF_COUNT_UNUSED,
1082 0 < regions.slot_owners[meta_to_index(new_owner_meta_addr)].ref_count()
1083 <= REF_COUNT_MAX,
1084 regions.slot_owners[meta_to_index(new_owner_meta_addr)].paths_in_pt
1085 == set![new_owner_path],
1086 {
1087 proof {
1088 C::lemma_page_table_config_constant_properties();
1089 C::lemma_paging_consts_properties();
1090 let ghost the_node = new_owner.value().node();
1092
1093 assert(0 <= i < NR_ENTRIES);
1094 assert(new_owner.has_child(i as int));
1095 assert(new_owner.inv_children());
1096 assert(new_owner.child(i as int).inv());
1097 assert(new_owner.child(i as int).level() == new_owner.level() + 1);
1098 EntryOwner::huge_frame_split_child_at(owner.value(), *regions, i as usize);
1099 }
1100
1101 let small_pa = pa + i * page_size(level - 1);
1102
1103 let tracked mut child_owner = EntryOwner::tracked_new_frame(
1104 small_pa,
1105 new_owner.value().path.push_tail(i as int),
1106 (level - 1) as PagingLevel,
1107 prop,
1108 );
1109
1110 let ghost new_owner_before_update = new_owner;
1111 let tracked mut new_owner_node = {
1114 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1115 new_owner_value.tracked_take_node()
1116 };
1117 let tracked mut new_owner_child = new_owner.tracked_borrow_mut_child(i as int);
1118 let ghost new_owner_child_before_update = *new_owner_child;
1119
1120 proof {
1121 let idx = frame_to_index(small_pa);
1122 if i != 0 {
1123 let ghost big_j =
1124 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1125 pa, level, i);
1126 }
1127 if level - 1 > 1 {
1128 let nr_subpages = page_size((level - 1) as PagingLevel) / PAGE_SIZE;
1129 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1130 (level - 1) as PagingLevel);
1131 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1132 level);
1133 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
1134 level);
1135 assert forall|j_prime: usize|
1136 #![trigger frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize)]
1137 0 < j_prime < nr_subpages implies {
1138 let sub_idx = frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize);
1139 &&& regions.slots.contains_key(sub_idx)
1140 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1141 &&& regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1142 &&& regions.slot_owners[sub_idx].ref_count() > 0
1143 &&& regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
1144 }
1145 } by {
1146 let sub_pages_per_subframe = page_size((level - 1) as PagingLevel)
1147 / PAGE_SIZE;
1148 let big_j_int: int = i * sub_pages_per_subframe + j_prime;
1149 vstd::arithmetic::mul::lemma_mul_nonnegative(
1150 i as int,
1151 sub_pages_per_subframe as int,
1152 );
1153 vstd::arithmetic::mul::lemma_mul_inequality(
1154 i + 1,
1155 NR_ENTRIES as int,
1156 sub_pages_per_subframe as int,
1157 );
1158 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1159 sub_pages_per_subframe as int,
1160 i as int,
1161 1int,
1162 );
1163 vstd::arithmetic::mul::lemma_mul_is_associative(
1164 NR_ENTRIES as int,
1165 sub_pages_per_subframe as int,
1166 PAGE_SIZE as int,
1167 );
1168 vstd::arithmetic::div_mod::lemma_div_by_multiple(
1169 NR_ENTRIES * sub_pages_per_subframe,
1170 PAGE_SIZE as int,
1171 );
1172 let big_j: usize = big_j_int as usize;
1173 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1174 PAGE_SIZE as int,
1175 i * sub_pages_per_subframe,
1176 j_prime as int,
1177 );
1178 vstd::arithmetic::mul::lemma_mul_is_associative(
1179 i as int,
1180 sub_pages_per_subframe as int,
1181 PAGE_SIZE as int,
1182 );
1183 assert((small_pa + j_prime * PAGE_SIZE) as usize == (pa + big_j
1184 * PAGE_SIZE) as usize);
1185 assert(regions.slots.contains_key(
1191 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1192 ));
1193 }
1194 }
1195 if i == 0 {
1201 assert(i * page_size((level - 1) as PagingLevel) == 0) by {
1203 vstd::arithmetic::mul::lemma_mul_by_zero_is_zero(
1204 page_size((level - 1) as PagingLevel) as int,
1205 );
1206 }
1207 } else {
1208 let ghost big_j =
1209 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1210 pa, level, i);
1211 assert(regions.slots.contains_key(
1213 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1214 ));
1215 }
1216
1217 regions.lemma_contains_valid_frame_paddr(small_pa);
1218 let tracked mut small_slot = regions.tracked_borrow_mut_slot_owner(small_pa);
1219 small_slot.paths_in_pt = small_slot.paths_in_pt.insert(child_owner.path);
1220
1221 if (level - 1) > 1 {
1224 }
1225 let ghost target_idx = frame_to_index(small_pa);
1226 if i != 0 {
1227 let ghost _ =
1228 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1229 pa, level, i);
1230
1231 }
1232 C::lemma_raw_item_well_formed_split(pa, level, prop, small_pa, i);
1233 }
1234
1235 let ghost nidx = meta_to_index(new_owner_meta_addr);
1239 proof {
1240 }
1244 let ghost regions_pre_replace = *regions;
1245 {
1246 let tracked new_owner_child_value = new_owner_child.tracked_borrow_mut_value();
1247 #[verus_spec(with Tracked(regions),
1248 Tracked(new_owner_child_value),
1249 Tracked(&mut child_owner),
1250 Tracked(&mut new_owner_node))]
1251 pt_lock_guard.replace_absent_with_frame(i, small_pa, level - 1, prop);
1252
1253 proof {
1254 *new_owner_child_value = child_owner;
1255 }
1256 }
1257
1258 proof {
1259 new_owner_child_before_update.lemma_set_value_observable_fields(child_owner);
1260 OwnerSubtree::lemma_ext_equal(
1261 *new_owner_child,
1262 new_owner_child_before_update.set_value(child_owner),
1263 );
1264 assert(new_owner_child.inv());
1265
1266 {
1267 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1268 new_owner_value.tracked_put_node(new_owner_node);
1269 }
1270
1271 let owner_with_updated_value = new_owner_before_update.set_value(new_owner.value());
1272 vstd::seq_lib::lemma_update_is_remove_insert(
1273 new_owner_before_update.children(),
1274 i as int,
1275 Some(*new_owner_child),
1276 );
1277 assert(new_owner.children() == new_owner_before_update.children().remove(
1278 i as int,
1279 ).insert(i as int, Some(*new_owner_child)));
1280 assert(owner_with_updated_value.insert(i as int, *new_owner_child).children()
1281 == new_owner_before_update.children().update(i as int, Some(*new_owner_child)));
1282 assert(new_owner.children() =~= owner_with_updated_value.insert(
1283 i as int,
1284 *new_owner_child,
1285 ).children());
1286 assert(new_owner.children() == owner_with_updated_value.insert(
1287 i as int,
1288 *new_owner_child,
1289 ).children());
1290 OwnerSubtree::lemma_ext_equal(
1291 new_owner,
1292 owner_with_updated_value.insert(i as int, *new_owner_child),
1293 );
1294 assert forall|j: int| 0 <= j < NR_ENTRIES implies (
1295 #[trigger] new_owner.children()[j]) is Some by {
1296 if j != i {
1297 assert(owner_with_updated_value.insert(
1298 i as int,
1299 *new_owner_child,
1300 ).children()[j] == owner_with_updated_value.children()[j]);
1301 }
1302 };
1303 assert(new_owner.inv());
1304
1305 }
1311 }
1312
1313 proof {
1314 }
1319 self.pte = {
1320 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1321 #[verus_spec(with Tracked(new_owner_value), Tracked(regions))]
1322 Child::PageTable(new_page).into_pte()
1323 };
1324
1325 proof {
1326 *owner = new_owner;
1327 }
1328
1329 unsafe {
1334 let tracked owner_value = owner.tracked_borrow_mut_value();
1335 #[verus_spec(with Tracked(owner_value.tracked_borrow_mut_node()), Tracked(&*regions))]
1336 self.node.write_pte(self.idx, self.pte)
1337 };
1338
1339 Some(pt_lock_guard)
1340 }
1341
1342 #[verus_spec(res =>
1358 with Tracked(owner): Tracked<&EntryOwner<C>>,
1359 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1360 Tracked(regions): Tracked<&MetaRegionOwners>,
1361 requires
1362 owner.inv(),
1363 parent_owner.inv(),
1364 parent_owner.relate_guard(*guard),
1365 idx < NR_ENTRIES,
1366 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1367 regions.inv(),
1368 regions.slots.contains_key(parent_owner.slot_index),
1369 ensures
1370 res.wf(*owner),
1371 res.idx == idx,
1372 parent_owner.relate_guard(*res.node),
1373 *res.node == *old(guard),
1376 *final(guard) == *final(res.node),
1377 )]
1378 pub(in crate::mm) unsafe fn new_at(guard: &'a mut PageTableGuard<'rcu, C>, idx: usize) -> Self {
1379 let pte = unsafe {
1381 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1382 guard.read_pte(idx)
1383 };
1384 Self::new(pte, idx, guard)
1385 }
1386}
1387
1388#[verus_verify]
1389impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
1390 #[verus_spec(res =>
1391 with Tracked(owner): Tracked<&mut EntryOwner<C>>,
1392 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1393 Tracked(regions): Tracked<&MetaRegionOwners>,
1394 requires
1395 old(owner).inv(),
1396 old(owner).is_frame(),
1397 old(owner).match_pte(
1398 old(parent_owner).children_perm.value()[idx as int],
1399 old(owner).parent_level,
1400 ),
1401 old(parent_owner).inv(),
1402 old(parent_owner).relate_guard(*old(self)),
1403 old(parent_owner).level == old(owner).parent_level,
1404 old(parent_owner).metaregion_sound_node(*regions),
1405 idx < NR_ENTRIES,
1406 op.requires((old(owner).frame().prop,)),
1407 regions.inv(),
1408 regions.slots.contains_key(old(parent_owner).slot_index),
1409 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1410 #![auto]
1411 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
1412 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
1413 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1414 #![auto]
1415 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
1416 ==> C::E::new_page_req(pa, level, p_out),
1417 ensures
1418 final(owner).inv(),
1419 final(owner).is_frame(),
1420 final(owner).match_pte(res, final(parent_owner).level),
1421 final(owner).match_pte(
1422 final(parent_owner).children_perm.value()[idx as int],
1423 final(parent_owner).level,
1424 ),
1425 res == final(parent_owner).children_perm.value()[idx as int],
1426 final(parent_owner).inv(),
1427 final(parent_owner).slot_index == old(parent_owner).slot_index,
1428 final(parent_owner).level == old(parent_owner).level,
1429 final(parent_owner).tree_level == old(parent_owner).tree_level,
1430 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1431 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1432 final(parent_owner).relate_guard(*final(self)),
1433 final(parent_owner).metaregion_sound_node(*regions),
1434 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
1435 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
1436 final(owner).path == old(owner).path,
1437 final(owner).parent_level == old(owner).parent_level,
1438 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1439 #[trigger] final(parent_owner).children_perm.value()[j]
1440 == old(parent_owner).children_perm.value()[j],
1441 crate::specs::mm::page_table::node::owners::count_present(
1444 final(parent_owner).children_perm.value(),
1445 ) == crate::specs::mm::page_table::node::owners::count_present(
1446 old(parent_owner).children_perm.value(),
1447 ),
1448 op.ensures((old(owner).frame().prop,), final(owner).frame().prop),
1449 *final(self) == *old(self),
1450 )]
1451 pub(in crate::mm) fn protect_child(
1452 &mut self,
1453 idx: usize,
1454 op: impl FnOnce(PageProperty) -> PageProperty,
1455 ) -> C::E {
1456 let ghost cp_old = parent_owner.children_perm.value();
1457 let mut pte = unsafe {
1458 #[verus_spec(with Tracked(&*parent_owner), Tracked(regions))]
1459 self.read_pte(idx)
1460 };
1461
1462 let prop = pte.prop();
1463 let new_prop = op(prop);
1464
1465 proof {
1466 assert(owner.frame().prop == prop);
1467 assert(op.ensures((prop,), new_prop));
1468 C::lemma_raw_item_well_formed_preserved(
1469 owner.frame().mapped_pa,
1470 owner.parent_level,
1471 prop,
1472 new_prop,
1473 );
1474 }
1475
1476 assume(pte.set_prop_req(new_prop));
1477 pte.set_prop(new_prop);
1478
1479 unsafe {
1480 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1481 self.write_pte(idx, pte)
1482 };
1483
1484 proof {
1485 owner.tracked_set_frame_prop(new_prop);
1486 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1490 cp_old,
1491 NR_ENTRIES as int,
1492 idx as int,
1493 pte,
1494 );
1495 }
1496
1497 pte
1498 }
1499
1500 #[verifier::spinoff_prover]
1501 #[verus_spec(res =>
1502 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
1503 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1504 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1505 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1506 requires
1507 old(owner).inv(),
1508 old(owner).metaregion_sound(*old(regions)),
1509 old(owner).match_pte(
1510 old(parent_owner).children_perm.value()[idx as int],
1511 old(owner).parent_level,
1512 ),
1513 old(parent_owner).inv(),
1514 old(parent_owner).relate_guard(*old(self)),
1515 old(parent_owner).level == old(owner).parent_level,
1516 idx < NR_ENTRIES,
1517 old(regions).inv(),
1518 old(regions).slots.contains_key(old(parent_owner).slot_index),
1519 new_child.invariants(*old(new_owner), *old(regions)),
1520 old(owner).path == old(new_owner).path,
1521 old(owner).parent_level == old(new_owner).parent_level,
1522 old(new_owner).is_node() ==> {
1523 &&& old(regions).slots.contains_key(frame_to_index(old(new_owner).meta_slot_paddr()->0))
1524 &&& old(regions).slot_owner(old(new_owner).meta_slot_paddr()->0).ref_count() != REF_COUNT_UNUSED
1525 },
1526 old(parent_owner).metaregion_sound_node(*old(regions)),
1527 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
1528 meta_to_index(node.ptr.addr()),
1529 ) > 0,
1530 ensures
1531 res.invariants(*final(owner), *final(regions)),
1532 final(new_owner).inv(),
1533 final(new_owner).metaregion_sound(*final(regions)),
1534 final(new_owner).match_pte(
1535 final(parent_owner).children_perm.value()[idx as int],
1536 final(parent_owner).level,
1537 ),
1538 final(new_owner).path == old(new_owner).path,
1539 final(new_owner).parent_level == old(new_owner).parent_level,
1540 *final(owner) == old(owner).from_pte_owner_spec(),
1541 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1542 Entry::<C>::metaregion_sound_neq_preserved(
1543 *old(owner),
1544 *final(new_owner),
1545 *old(regions),
1546 *final(regions),
1547 ),
1548 !final(new_owner).is_node() ==> Entry::<C>::metaregion_sound_neq_old_preserved(
1549 *old(owner),
1550 *old(regions),
1551 *final(regions),
1552 ),
1553 (!old(owner).is_node() && !final(new_owner).is_node())
1554 ==> Entry::<C>::metaregion_sound_preserved(*old(regions), *final(regions)),
1555 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
1556 C,
1557 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
1558 final(parent_owner).inv(),
1559 final(parent_owner).level == old(parent_owner).level,
1560 final(parent_owner).relate_guard(*final(self)),
1561 final(parent_owner).metaregion_sound_node(*final(regions)),
1562 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1563 #[trigger] final(parent_owner).children_perm.value()[j]
1564 == old(parent_owner).children_perm.value()[j],
1565 forall|slot: int|
1566 #![trigger final(regions).slot_owners[slot].paths_in_pt]
1567 (!final(new_owner).is_node() || final(new_owner).is_absent() || slot
1568 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
1569 ==> final(regions).slot_owners[slot].paths_in_pt == old(
1570 regions,
1571 ).slot_owners[slot].paths_in_pt,
1572 forall|k: int|
1573 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(k),
1574 forall|slot: int|
1575 #![trigger final(regions).slot_owners[slot].ref_count()]
1576 final(regions).slot_owners[slot].ref_count() == old(
1577 regions,
1578 ).slot_owners[slot].ref_count(),
1579 forall|slot: int|
1580 #![trigger final(regions).slot_owners[slot]]
1581 final(regions).slot_owners[slot].same_permissions(
1582 old(regions).slot_owners[slot],
1583 ),
1584 final(regions).slots == old(regions).slots,
1585 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
1586 &&& final(regions).slots == old(regions).slots
1587 &&& forall|i: int|
1588 #![trigger final(regions).slot_owners[i]]
1589 final(regions).slot_owners[i] == old(
1590 regions,
1591 ).slot_owners[i]
1592 &&& final(regions).frame_obligations == old(regions).frame_obligations
1593 },
1594 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
1595 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
1596 == #[trigger] final(regions).slots[k],
1597 Entry::<C>::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
1598 *final(self) == *old(self),
1599 )]
1600 #[verifier::spinoff_prover]
1601 pub(in crate::mm) fn replace_child(&mut self, idx: usize, new_child: Child<C>) -> Child<C> {
1602 #[cfg(feature = "allow_panic")]
1603 {
1604 let guard_level = self.level();
1605 match &new_child {
1606 Child::PageTable(node) => {
1607 assert!(node.level() == guard_level - 1);
1608 },
1609 Child::Frame(_, level, _) => {
1610 assert!(*level == guard_level);
1611 },
1612 Child::None => {},
1613 }
1614 }
1615
1616 let pte = unsafe {
1617 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1618 self.read_pte(idx)
1619 };
1620
1621 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1622 let level = self.level();
1623
1624 let old_child = unsafe {
1625 #[verus_spec(with Tracked(regions), Tracked(owner))]
1626 Child::from_pte(pte, level)
1627 };
1628
1629 let ghost cp0 = parent_owner.children_perm.value();
1631
1632 if old_child.is_none() && !new_child.is_none() {
1633 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
1634 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
1635 parent_owner.slot_index,
1636 );
1637 #[verus_spec(with
1638 Tracked(meta_points_to),
1639 Tracked(&meta_slot_owner.metadata_perm),
1640 Ghost(parent_owner.meta_own.nr_children.id())
1641 )]
1642 let nr_children = self.nr_children_mut();
1643 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1644 proof {
1645 parent_owner.nr_children_absent_slot_bound(idx);
1646 }
1647 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
1648 } else if !old_child.is_none() && new_child.is_none() {
1649 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
1650 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
1651 parent_owner.slot_index,
1652 );
1653 #[verus_spec(with
1654 Tracked(meta_points_to),
1655 Tracked(&meta_slot_owner.metadata_perm),
1656 Ghost(parent_owner.meta_own.nr_children.id())
1657 )]
1658 let nr_children = self.nr_children_mut();
1659 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1660 proof {
1661 parent_owner.nr_children_present_slot_bound(idx);
1662 }
1663 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
1664 }
1665 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
1666 let new_pte = new_child.into_pte();
1667
1668 unsafe {
1669 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1670 self.write_pte(idx, new_pte)
1671 };
1672
1673 proof {
1674 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1679 cp0,
1680 NR_ENTRIES as int,
1681 idx as int,
1682 new_pte,
1683 );
1684 }
1685
1686 proof {
1687 if new_owner.is_node() {
1688 let paddr = new_owner.meta_slot_paddr().unwrap();
1689 regions.lemma_contains_valid_frame_paddr(paddr);
1690 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
1691 new_meta_slot.paths_in_pt = set![new_owner.path];
1692 }
1693 }
1694
1695 proof {
1696 if new_owner.is_node() || new_owner.is_frame() {
1697 let paddr = new_owner.meta_slot_paddr().unwrap();
1698 regions.lemma_contains_valid_frame_paddr(paddr);
1699 }
1700 }
1701
1702 old_child
1703 }
1704
1705 #[verifier::spinoff_prover]
1706 #[verus_spec(res =>
1707 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
1708 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1709 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1710 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1711 requires
1712 old(owner).inv(),
1713 old(owner).value().is_absent(),
1714 old(owner).level() < INC_LEVELS - 1,
1715 old(owner).value().metaregion_sound(*old(regions)),
1716 old(parent_owner).inv(),
1717 old(parent_owner).relate_guard(*old(self)),
1718 old(parent_owner).level == old(owner).value().parent_level,
1719 old(parent_owner).level > 1,
1720 old(parent_owner).metaregion_sound_node(*old(regions)),
1721 idx < NR_ENTRIES,
1722 old(owner).value().match_pte(
1723 old(parent_owner).children_perm.value()[idx as int],
1724 old(owner).value().parent_level,
1725 ),
1726 old(regions).inv(),
1727 old(regions).slots.contains_key(old(parent_owner).slot_index),
1728 ensures
1729 final(owner).inv(),
1730 final(owner).value().is_node(),
1731 final(owner).level() == old(owner).level(),
1732 final(owner).value().parent_level == old(owner).value().parent_level,
1733 final(owner).value().path == old(owner).value().path,
1734 final(owner).value().metaregion_sound(*final(regions)),
1735 final(owner).value().node().relate_guard(res),
1736 final(owner).value().node().meta_vaddr() == res.inner.inner@.ptr.addr(),
1737 final(owner).value().match_pte(
1738 final(parent_owner).children_perm.value()[idx as int],
1739 final(parent_owner).level,
1740 ),
1741 final(guards).lock_held(final(owner).value().node().meta_vaddr()),
1742 OwnerSubtree::implies(
1743 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
1744 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr())),
1745 Entry::<C>::metaregion_sound_neq_preserved(
1746 old(owner).value(),
1747 final(owner).value(),
1748 *old(regions),
1749 *final(regions),
1750 ),
1751 Entry::<C>::path_tracked_pred_preserved(*old(regions), *final(regions)),
1752 old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0)),
1753 final(owner).subtree_satisfies(final(owner).value().path,
1754 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr())),
1755 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions))),
1756 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions))),
1757 PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![],
1758 forall|i: int| 0 <= i < NR_ENTRIES ==>
1759 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent(),
1760 forall|i: int| 0 <= i < NR_ENTRIES ==>
1761 (#[trigger] final(owner).children()[i])->0.value().path
1762 == final(owner).value().path.push_tail(i),
1763 crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner)),
1764 forall|i: int| 0 <= i < NR_ENTRIES ==>
1765 (#[trigger] final(owner).children()[i])->0.value().parent_level
1766 == final(owner).value().node().level,
1767 forall|i: int| 0 <= i < NR_ENTRIES ==>
1768 (#[trigger] final(owner).children()[i])->0.value().match_pte(
1769 final(owner).value().node().children_perm.value()[i],
1770 final(owner).children()[i]->0.value().parent_level),
1771 forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
1772 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i],
1773 forall|i: int| old(regions).slots.contains_key(i)
1774 ==> (#[trigger] final(regions).slots.contains_key(i)),
1775 forall|i: int| #![trigger final(regions).slots[i]]
1776 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
1777 && old(regions).slots.contains_key(i)
1778 ==> final(regions).slots[i] == old(regions).slots[i],
1779 final(regions).slot_owner(final(owner).value().meta_slot_paddr()->0)
1780 .ref_count() != REF_COUNT_UNUSED,
1781 old(regions).slot_owner(final(owner).value().meta_slot_paddr().unwrap())
1782 .ref_count() == REF_COUNT_UNUSED,
1783 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
1784 final(owner).value().meta_slot_paddr().unwrap()),
1785 final(regions).inv(),
1786 final(parent_owner).inv(),
1787 final(parent_owner).level == old(parent_owner).level,
1788 final(parent_owner).relate_guard(*final(self)),
1789 final(parent_owner).metaregion_sound_node(*final(regions)),
1790 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1791 #[trigger] final(parent_owner).children_perm.value()[j]
1792 == old(parent_owner).children_perm.value()[j],
1793 *final(self) == *old(self),
1794 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
1795 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().meta_vaddr() ==> final(guards).unlocked(i),
1796 )]
1797 pub(in crate::mm) fn alloc_absent_child<A: InAtomicMode>(
1798 &mut self,
1799 idx: usize,
1800 guard: &'rcu A,
1801 ) -> PageTableGuard<'rcu, C> {
1802 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1803 let level = self.level();
1804
1805 let ghost old_path = owner.value().path;
1806
1807 proof {
1813 parent_owner.nr_children_absent_slot_bound(idx);
1814 }
1815 let ghost regions_pre = *regions;
1816 let ghost cp0 = parent_owner.children_perm.value();
1819 let ghost old_owner_val = owner.value();
1822
1823 proof_decl! {
1824 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
1825 }
1826
1827 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(idx) => Tracked(new_node_owner))]
1828 let new_page = PageTableNode::<C>::alloc(level - 1);
1829 let ghost fresh_children = new_node_owner.children();
1830 proof {
1831 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1832 #[trigger] fresh_children[i]) is Some by {
1833 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
1834 new_node_owner,
1835 (level - 1) as PagingLevel,
1836 ));
1837 assert(new_node_owner.has_child(i));
1838 };
1839 }
1840
1841 proof {
1842 let pte = C::E::new_pt_spec(meta_to_frame(new_node_owner.value().node().meta_vaddr()));
1843 C::E::lemma_page_table_entry_properties();
1844 }
1845
1846 let ghost new_node_slot_idx = new_node_owner.value().node().slot_index;
1847 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
1848 #[verus_spec(with Tracked(new_node_slot_perm))]
1849 let paddr = new_page.start_paddr();
1850
1851 let new_pte = {
1852 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1853 #[verus_spec(with Tracked(new_node_value), Tracked(regions))]
1854 Child::PageTable(new_page).into_pte()
1855 };
1856
1857 proof {
1858 broadcast use group_page_meta;
1859
1860 }
1861
1862 let pt_ref = unsafe {
1863 #[verus_spec(with Tracked(regions))]
1864 PageTableNodeRef::borrow_paddr(paddr)
1865 };
1866
1867 let pt_lock_guard = {
1868 let tracked new_node_value = new_node_owner.tracked_borrow_value();
1869 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
1870 pt_ref.lock(guard)
1871 };
1872
1873 unsafe {
1874 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1875 self.write_pte(idx, new_pte)
1876 };
1877
1878 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
1886 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(parent_owner.slot_index);
1887 #[verus_spec(with
1888 Tracked(meta_points_to),
1889 Tracked(&meta_slot_owner.metadata_perm),
1890 Ghost(parent_owner.meta_own.nr_children.id())
1891 )]
1892 let nr_children = self.nr_children_mut();
1893 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1894 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1895
1896 proof {
1897 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1902 cp0,
1903 NR_ENTRIES as int,
1904 idx as int,
1905 new_pte,
1906 );
1907 }
1908
1909 proof {
1910 {
1911 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1912 new_node_value.parent_level = level as PagingLevel;
1913 new_node_value.path = old_path;
1914 }
1915 *owner = new_node_owner;
1916 assert(owner.children() == fresh_children);
1917 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
1918
1919 let new_paddr = owner.value().meta_slot_paddr().unwrap();
1920 regions.lemma_contains_valid_frame_paddr(new_paddr);
1921 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
1922 new_meta_slot.paths_in_pt = set![owner.value().path];
1923 }
1924
1925 proof {
1926 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1930 let ghost new_node_addr = owner.value().node().meta_vaddr();
1936 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
1937 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
1938 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
1939
1940 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1943 *owner,
1944 owner.value().path,
1945 f_nu,
1946 );
1947 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1948 *owner,
1949 owner.value().path,
1950 f_ms,
1951 );
1952 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1953 *owner,
1954 owner.value().path,
1955 f_pt,
1956 );
1957 }
1958
1959 pt_lock_guard
1960 }
1961
1962 #[verifier::spinoff_prover]
1963 #[verus_spec(
1964 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
1965 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1966 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1967 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1968 requires
1969 old(owner).inv(),
1970 old(owner).is_absent(),
1971 old(owner).metaregion_sound(*old(regions)),
1972 old(parent_owner).inv(),
1973 old(parent_owner).relate_guard(*old(self)),
1974 old(parent_owner).level == old(owner).parent_level,
1975 idx < NR_ENTRIES,
1976 old(owner).match_pte(
1977 old(parent_owner).children_perm.value()[idx as int],
1978 old(owner).parent_level,
1979 ),
1980 old(regions).inv(),
1981 old(regions).slots.contains_key(old(parent_owner).slot_index),
1982 old(parent_owner).metaregion_sound_node(*old(regions)),
1983 Child::<C>::Frame(paddr, level, prop).invariants(*old(new_owner), *old(regions)),
1984 old(owner).path == old(new_owner).path,
1985 old(owner).parent_level == old(new_owner).parent_level,
1986 ensures
1987 final(new_owner).inv(),
1988 final(parent_owner).inv(),
1989 *final(owner) == old(owner).from_pte_owner_spec(),
1990 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1991 final(new_owner).pte_invariants(
1992 final(parent_owner).children_perm.value()[idx as int],
1993 *final(regions),
1994 ),
1995 forall|i: int|
1996 0 <= i < NR_ENTRIES && i != idx ==> #[trigger] old(parent_owner).children_perm.value()[i]
1997 == final(parent_owner).children_perm.value()[i],
1998 final(parent_owner).slot_index == old(parent_owner).slot_index,
1999 final(parent_owner).level == old(parent_owner).level,
2000 final(parent_owner).tree_level == old(parent_owner).tree_level,
2001 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
2002 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
2003 final(parent_owner).relate_guard(*final(self)),
2004 final(parent_owner).metaregion_sound_node(*final(regions)),
2005 *final(regions) == *old(regions),
2006 *final(self) == *old(self),
2007 )]
2008 pub(in crate::mm) fn replace_absent_with_frame(
2009 &mut self,
2010 idx: usize,
2011 paddr: Paddr,
2012 level: PagingLevel,
2013 prop: PageProperty,
2014 ) {
2015 let ghost cp0 = parent_owner.children_perm.value();
2017 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
2018 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(parent_owner.slot_index);
2019 #[verus_spec(with
2020 Tracked(meta_points_to),
2021 Tracked(&meta_slot_owner.metadata_perm),
2022 Ghost(parent_owner.meta_own.nr_children.id())
2023 )]
2024 let nr_children = self.nr_children_mut();
2025 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
2026 proof {
2027 parent_owner.nr_children_absent_slot_bound(idx);
2028 }
2029 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
2030
2031 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
2032 let new_pte = Child::<C>::Frame(paddr, level, prop).into_pte();
2033
2034 unsafe {
2035 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
2036 self.write_pte(idx, new_pte)
2037 };
2038
2039 proof {
2040 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
2044 cp0,
2045 NR_ENTRIES as int,
2046 idx as int,
2047 new_pte,
2048 );
2049 }
2050 }
2051}
2052
2053}