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|
315 #![trigger final(regions).slot_owners[idx].paths_in_pt]
316 (!final(new_owner).is_node() || final(new_owner).is_absent() || idx
317 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
318 ==> final(regions).slot_owners[idx].paths_in_pt == old(
319 regions,
320 ).slot_owners[idx].paths_in_pt,
321 forall|k: int|
322 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
323 k,
324 ),
325 forall|idx: int|
326 #![trigger final(regions).slot_owners[idx].ref_count()]
327 final(regions).slot_owners[idx].ref_count() == old(
328 regions,
329 ).slot_owners[idx].ref_count(),
330 forall|idx: int|
331 #![trigger final(regions).slot_owners[idx]]
332 final(regions).slot_owners[idx].same_permissions(
333 old(regions).slot_owners[idx],
334 ),
335 final(regions).slots == old(regions).slots,
336 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
338 &&& final(regions).slots == old(regions).slots
339 &&& forall|i: int|
340 #![trigger final(regions).slot_owners[i]]
341 final(regions).slot_owners[i] == old(
342 regions,
343 ).slot_owners[i]
344 &&& final(regions).frame_obligations == old(regions).frame_obligations
350 },
351 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
353 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
354 == #[trigger] final(regions).slots[k],
355 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
356 )]
357 #[verifier::spinoff_prover]
358 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> Child<C> {
359 let ghost cp0 = parent_owner.children_perm.value();
363
364 #[cfg(feature = "allow_panic")]
365 {
366 let guard_level = self.node.level();
367 match &new_child {
368 Child::PageTable(node) => {
369 assert!(node.level() == guard_level - 1);
370 },
371 Child::Frame(_, level, _) => {
372 assert!(*level == guard_level);
373 },
374 Child::None => {},
375 }
376 }
377
378 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
382 let level = self.node.level();
383
384 let old_child = unsafe {
385 #[verus_spec(with Tracked(regions), Tracked(owner))]
386 Child::from_pte(self.pte, level)
387 };
388
389 if old_child.is_none() && !new_child.is_none() {
390 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
391 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
392 parent_owner.slot_index,
393 );
394 #[verus_spec(with
395 Tracked(meta_points_to),
396 Tracked(&meta_slot_owner.metadata_perm),
397 Ghost(parent_owner.meta_own.nr_children.id())
398 )]
399 let nr_children = self.node.nr_children_mut();
400 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
401 proof {
402 parent_owner.nr_children_absent_slot_bound(self.idx);
403 }
404 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
405 } else if !old_child.is_none() && new_child.is_none() {
406 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
407 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
408 parent_owner.slot_index,
409 );
410 #[verus_spec(with
411 Tracked(meta_points_to),
412 Tracked(&meta_slot_owner.metadata_perm),
413 Ghost(parent_owner.meta_own.nr_children.id())
414 )]
415 let nr_children = self.node.nr_children_mut();
416 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
417 proof {
418 parent_owner.nr_children_present_slot_bound(self.idx);
419 }
420 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
421 }
422 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
423 let new_pte = new_child.into_pte();
424
425 unsafe {
430 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
431 self.node.write_pte(self.idx, new_pte)
432 };
433
434 self.pte = new_pte;
435
436 proof {
437 if new_owner.is_node() {
444 let paddr = new_owner.meta_slot_paddr().unwrap();
445 regions.lemma_contains_valid_frame_paddr(paddr);
446
447 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
448 new_meta_slot.paths_in_pt = set![new_owner.path];
449 }
450 }
451
452 proof {
453 if new_owner.is_node() || new_owner.is_frame() {
454 let paddr = new_owner.meta_slot_paddr().unwrap();
455 regions.lemma_contains_valid_frame_paddr(paddr);
456 }
457 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
458 cp0,
459 NR_ENTRIES as int,
460 self.idx as int,
461 new_pte,
462 );
463 }
464
465 old_child
466 }
467
468 #[verus_spec(res =>
485 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
486 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
487 Tracked(regions): Tracked<&mut MetaRegionOwners>,
488 Tracked(guards): Tracked<&mut Guards<'rcu>>,
489 requires
490 old(self).invariants(old(owner).value(), *old(regions)),
491 old(owner).inv(),
492 old(self).node_matching(old(owner).value(), *old(parent_owner), *old(self).node),
493 old(owner).level() < INC_LEVELS - 1,
494 old(owner).level() + old(parent_owner).level == INC_LEVELS,
499 old(parent_owner).metaregion_sound_node(*old(regions)),
500 ensures
501 final(self).invariants(final(owner).value(), *final(regions)),
502 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
503 final(self).idx == old(self).idx,
504 final(parent_owner).count_consistent(),
505 *final(self).node == *old(self).node,
506 old(owner).value().is_absent() && old(parent_owner).level > 1 ==> {
507 &&& final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node)
508 &&& final(owner).inv()
509 },
510 old(owner).value().is_absent() && old(parent_owner).level > 1 ==> {
511 &&& res is Some
512 &&& final(owner).value().is_node()
513 &&& final(owner).level() == old(owner).level()
514 &&& final(owner).value().parent_level == old(owner).value().parent_level
515 &&& final(guards).lock_held(final(owner).value().node().meta_vaddr())
516 &&& final(owner).value().node().relate_guard(res->0)
517 &&& final(owner).value().path == old(owner).value().path
518 &&& final(owner).value().metaregion_sound(*final(regions))
519 &&& OwnerSubtree::implies(
520 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
521 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr()))
522 &&& Self::metaregion_sound_neq_preserved(old(owner).value(), final(owner).value(), *old(regions), *final(regions))
523 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
524 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0))
525 &&& final(owner).subtree_satisfies(final(owner).value().path,
526 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr()))
527 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
528 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
529 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![]
530 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
532 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent()
533 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
540 (#[trigger] final(owner).children()[i])->0.value().path
541 == final(owner).value().path.push_tail(i)
542 &&& crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner))
546 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
548 (#[trigger] final(owner).child(i)).value().parent_level
549 == final(owner).value().node().level
550 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
551 (#[trigger] final(owner).child(i)).value().match_pte(
552 final(owner).value().node().children_perm.value()[i],
553 final(owner).child(i).value().parent_level)
554 &&& forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
556 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
557 &&& forall|i: int| old(regions).slots.contains_key(i)
559 ==> (#[trigger] final(regions).slots.contains_key(i))
560 &&& forall|i: int| #![trigger final(regions).slots[i]]
561 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
562 && old(regions).slots.contains_key(i)
563 ==> final(regions).slots[i] == old(regions).slots[i]
564 &&& final(regions).slot_owner(final(owner).value().meta_slot_paddr()->0)
566 .ref_count() != REF_COUNT_UNUSED
567 &&& old(regions).slot_owner(final(owner).value().meta_slot_paddr().unwrap())
569 .ref_count() == REF_COUNT_UNUSED
570 &&& !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
572 final(owner).value().meta_slot_paddr().unwrap())
573 },
574 !old(owner).value().is_absent() ==> {
575 &&& res is None
576 &&& *final(owner) == *old(owner)
577 },
578 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
579 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().meta_vaddr() ==> final(guards).unlocked(i),
580 )]
581 #[verifier::spinoff_prover]
582 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
583 PageTableGuard<'rcu, C>,
584 > {
585 let entry_is_present = self.pte.is_present();
586 let ghost cp0 = parent_owner.children_perm.value();
588
589 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
590 let level = self.node.level();
591
592 if entry_is_present || level <= 1 {
593 None
594 } else {
595 let ghost old_path = owner.value().path;
596 let ghost old_owner_val = owner.value();
597
598 proof {
599 parent_owner.nr_children_absent_slot_bound(self.idx);
600 }
601
602 proof_decl! {
603 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
604 }
605
606 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
607 let new_page = PageTableNode::<C>::alloc(level - 1);
608 let ghost fresh_children = new_node_owner.children();
609 proof {
610 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
611 #[trigger] fresh_children[i]) is Some by {
612 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
613 new_node_owner,
614 (level - 1) as PagingLevel,
615 ));
616 assert(new_node_owner.has_child(i));
617 };
618 }
619
620 proof {
621 let pte = C::E::new_pt_spec(
622 meta_to_frame(new_node_owner.value().node().meta_vaddr()),
623 );
624 C::E::lemma_page_table_entry_properties();
625 }
626
627 let ghost new_node_slot_idx = new_node_owner.value().node().slot_index;
628 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
629 #[verus_spec(with Tracked(new_node_slot_perm))]
630 let paddr = new_page.start_paddr();
631
632 let new_pte = {
633 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
634 #[verus_spec(with Tracked(new_node_value), Tracked(regions))]
635 Child::PageTable(new_page).into_pte()
636 };
637 self.pte = new_pte;
638
639 let pt_ref = unsafe {
640 #[verus_spec(with Tracked(regions))]
641 PageTableNodeRef::borrow_paddr(paddr)
642 };
643
644 let mut pt_lock_guard = {
646 let tracked new_node_value = new_node_owner.tracked_borrow_value();
647 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
648 pt_ref.lock(guard)
649 };
650
651 unsafe {
656 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
657 self.node.write_pte(self.idx, self.pte)
658 };
659
660 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
661 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
662 parent_owner.slot_index,
663 );
664 #[verus_spec(with
665 Tracked(meta_points_to),
666 Tracked(&meta_slot_owner.metadata_perm),
667 Ghost(parent_owner.meta_own.nr_children.id())
668 )]
669 let nr_children = self.node.nr_children_mut();
670 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
671 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
672
673 proof {
674 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
681 new_node_value.parent_level = level as PagingLevel;
682 new_node_value.path = old_path;
683 *owner = new_node_owner;
684 assert(owner.children() == fresh_children);
688 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
689 #[trigger] owner.children()[i]) is Some by {};
690 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
691
692 let new_paddr = owner.value().meta_slot_paddr().unwrap();
693 regions.lemma_contains_valid_frame_paddr(new_paddr);
694 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
695 new_meta_slot.paths_in_pt = set![owner.value().path];
696
697 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
701 cp0,
702 NR_ENTRIES as int,
703 self.idx as int,
704 self.pte,
705 );
706
707 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
711 let ghost new_node_addr = owner.value().node().meta_vaddr();
717 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
718 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
719 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
720
721 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
722 *owner,
723 owner.value().path,
724 f_nu,
725 );
726 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
727 *owner,
728 owner.value().path,
729 f_ms,
730 );
731 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
732 *owner,
733 owner.value().path,
734 f_pt,
735 );
736 }
737
738 Some(pt_lock_guard)
739 }
740 }
741
742 #[verifier::spinoff_prover]
758 #[verifier::rlimit(200)]
759 #[verus_spec(res =>
760 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
761 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
762 Tracked(regions): Tracked<&mut MetaRegionOwners>,
763 Tracked(guards): Tracked<&mut Guards<'rcu>>
764 requires
765 old(regions).inv(),
766 old(owner).inv(),
767 old(self).wf(old(owner).value()),
768 old(parent_owner).relate_guard(*old(self).node),
769 old(parent_owner).inv(),
770 old(parent_owner).level == old(owner).value().parent_level,
771 old(parent_owner).level < NR_LEVELS,
772 old(parent_owner).metaregion_sound_node(*old(regions)),
773 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
779 old(owner).value().metaregion_sound(*old(regions)),
780 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
784 forall |j: usize| #![trigger frame_to_index(
785 (old(owner).value().frame().mapped_pa
786 + j * PAGE_SIZE) as usize)]
787 0 < j < page_size(old(parent_owner).level) / PAGE_SIZE ==> {
788 let sub_idx = frame_to_index(
789 (old(owner).value().frame().mapped_pa
790 + j * PAGE_SIZE) as usize);
791 &&& old(regions).slots.contains_key(sub_idx)
792 &&& old(regions).slot_owners[sub_idx].usage !is MMIO ==>
793 old(regions).slot_owners[sub_idx].ref_count()
794 != REF_COUNT_UNUSED
795 },
796 ensures
797 old(owner).value().is_frame() && old(parent_owner).level > 1 ==> {
798 &&& res is Some
799 &&& final(owner).value().is_node()
800 &&& final(owner).level() == old(owner).level()
801 &&& final(parent_owner).relate_guard(*final(self).node)
802 &&& final(owner).value().node().relate_guard(res->0)
803 &&& final(owner).value().node().meta_vaddr() == res->0.inner.inner@.ptr.addr()
804 &&& final(guards).lock_held(res->0.inner.inner@.ptr.addr())
805 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
807 (#[trigger] final(owner).children()[j])->0.value().is_frame()
808 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
809 (#[trigger] final(owner).children()[j])->0.value().frame().prop
810 == old(owner).value().frame().prop
811 &&& final(owner).value().path == old(owner).value().path
812 &&& final(owner).value().metaregion_sound(*final(regions))
813 &&& OwnerSubtree::implies(
814 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
815 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
816 &&& OwnerSubtree::implies(
817 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
818 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
819 &&& final(owner).subtree_satisfies(final(owner).value().path,
820 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
821 &&& final(owner).subtree_satisfies(final(owner).value().path,
822 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
823 },
824 !old(owner).value().is_frame() || old(parent_owner).level <= 1 ==> {
825 &&& res is None
826 &&& *final(owner) == *old(owner)
827 },
828 final(owner).inv(),
829 final(owner).value().parent_level == old(owner).value().parent_level,
830 final(self).idx == old(self).idx,
831 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
832 final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node),
833 final(regions).inv(),
834 final(parent_owner).inv(),
835 final(parent_owner).level == old(parent_owner).level,
836 final(self).node.inner.inner@.ptr.addr() == old(self).node.inner.inner@.ptr.addr(),
837 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
838 forall |i: usize| old(guards).unlocked(i) ==> final(guards).unlocked(i),
839 old(owner).value().is_frame() && old(parent_owner).level > 1 ==> {
841 &&& forall|i: int| i != meta_to_index(final(owner).value().node().meta_vaddr()) ==>
842 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
843 &&& forall|i: int| old(regions).slots.contains_key(i)
845 ==> (#[trigger] final(regions).slots.contains_key(i))
846 &&& final(regions).slot_owners[meta_to_index(final(owner).value().node().meta_vaddr())]
848 .ref_count() != REF_COUNT_UNUSED
849 &&& old(regions).slot_owners[meta_to_index(final(owner).value().node().meta_vaddr())]
851 .ref_count() == REF_COUNT_UNUSED
852 },
853 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
858 forall|j: int| 0 <= j < NR_ENTRIES && j != old(self).idx ==>
859 #[trigger] final(parent_owner).children_perm.value()[j]
860 == old(parent_owner).children_perm.value()[j],
861 )]
862 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
863 PageTableGuard<'rcu, C>,
864 > {
865 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
866 let level = self.node.level();
867
868 if !(self.pte.is_last(level) && level > 1) {
869 return None;
870 }
871 let pa = self.pte.paddr();
872 let prop = self.pte.prop();
873
874 proof {
875 EntryOwner::last_pte_implies_frame_match(owner.value(), self.pte, level);
876 }
877
878 proof_decl!{
879 let tracked mut new_owner: OwnerSubtree<C>;
880 }
881
882 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
885 let new_page = PageTableNode::<C>::alloc(level - 1);
886 proof {
887 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
888 #[trigger] new_owner.children()[i]) is Some by {
889 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
890 new_owner,
891 (level - 1) as PagingLevel,
892 ));
893 assert(new_owner.has_child(i));
894 };
895 }
896
897 let ghost new_owner_slot_idx = new_owner.value().node().slot_index;
898 let tracked new_owner_slot_perm = regions.slots.tracked_borrow(new_owner_slot_idx);
899 #[verus_spec(with Tracked(new_owner_slot_perm))]
900 let paddr = new_page.start_paddr();
901
902 proof {
903 broadcast use group_page_meta;
904
905 }
906
907 let pt_ref = unsafe {
908 #[verus_spec(with Tracked(regions))]
909 PageTableNodeRef::borrow_paddr(paddr)
910 };
911
912 let mut pt_lock_guard = {
914 let tracked new_owner_value = new_owner.tracked_borrow_value();
915 #[verus_spec(with Tracked(new_owner_value.tracked_borrow_node()), Tracked(guards))]
916 pt_ref.lock(guard)
917 };
918
919 let ghost children_perm = new_owner.value().node().children_perm;
920 let ghost new_owner_path = new_owner.value().path;
921 let ghost new_owner_meta_addr = new_owner.value().node().meta_vaddr();
922
923 proof {
924 broadcast use crate::specs::mm::frame::mapping::lemma_frame_to_index_injective;
936 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
937 broadcast use group_page_meta;
938
939 let new_idx = meta_to_index(new_owner_meta_addr);
940 let new_paddr = meta_to_frame(new_owner_meta_addr);
941 let nr_pages = page_size(level) / PAGE_SIZE;
942
943 let pa_idx = frame_to_index(pa);
947 assert(pa_idx != new_idx) by {
948 if old(regions).slot_owners[pa_idx].usage
949 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
950 old(regions).lemma_contains_valid_frame_paddr(pa);
951 } else {
952 }
954 };
955
956 assert forall|j: usize|
958 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
959 0 < j < nr_pages implies {
960 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
961 &&& regions.slots.contains_key(sub_idx)
962 &&& regions.slot_owners[sub_idx].usage
963 != crate::specs::mm::frame::meta_owners::PageUsage::PageTable
964 &&& regions.slot_owners[sub_idx].usage
965 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
966 &&& regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
967 &&& regions.slot_owners[sub_idx].ref_count() > 0
968 &&& regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
969 }
970 } by {
971 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
972 assert(sub_idx != new_idx) by {
973 if old(regions).slot_owners[sub_idx].usage
974 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
975 old(regions).lemma_contains_valid_frame_paddr(
976 (pa + j * PAGE_SIZE) as usize,
977 );
978 } else {
979 }
980 };
981 };
982 }
983
984 proof {
985 C::lemma_paging_consts_properties();
986 assert(nr_subpage_per_huge_spec::<C>() == NR_ENTRIES);
987 }
988
989 for i in 0..nr_subpage_per_huge::<C>()
990 invariant
991 nr_subpage_per_huge_spec::<C>() == NR_ENTRIES,
992 1 < level < NR_LEVELS,
993 owner.inv(),
994 owner.value().is_frame(),
995 owner.value().parent_level == level,
996 owner.value().frame().mapped_pa == pa,
997 owner.value().frame().prop == prop,
998 pa == old(owner).value().frame().mapped_pa,
999 level == old(parent_owner).level,
1000 pa % page_size(level) == 0,
1001 pa + page_size(level) <= MAX_PADDR,
1002 regions.inv(),
1003 regions.frame_obligations.count(meta_to_index(new_owner_meta_addr)) > 0,
1008 parent_owner.inv(),
1009 new_owner.value().is_node(),
1010 new_owner.inv(),
1011 new_owner.value().path == new_owner_path,
1012 new_owner.value().node().meta_vaddr() == new_owner_meta_addr,
1013 new_owner.value().node().relate_guard(pt_lock_guard),
1014 guards.lock_held(new_owner_meta_addr),
1015 new_owner.value().node().level == (level - 1) as PagingLevel,
1016 forall|j: int| 0 <= j < NR_ENTRIES ==> (#[trigger] new_owner.children()[j]) is Some,
1017 forall|j: int|
1018 0 <= j < NR_ENTRIES ==> {
1019 &&& (#[trigger] new_owner.children()[j]) is Some
1020 &&& new_owner.children()[j].unwrap().value().match_pte(
1021 new_owner.value().node().children_perm.value()[j],
1022 new_owner.value().node().level,
1023 )
1024 &&& new_owner.children()[j].unwrap().value().parent_level
1025 == new_owner.value().node().level
1026 &&& new_owner.children()[j].unwrap().value().inv()
1027 &&& new_owner.children()[j].unwrap().value().path
1028 == new_owner_path.push_tail(j)
1029 },
1030 forall|j: int|
1031 i <= j < NR_ENTRIES ==> {
1032 &&& (#[trigger] new_owner.children()[j]) is Some
1033 &&& new_owner.children()[j].unwrap().value().is_absent()
1034 &&& new_owner.value().node().children_perm.value()[j]
1035 == C::E::new_absent_spec()
1036 },
1037 forall|j: int|
1039 0 <= j < i ==> {
1040 &&& (#[trigger] new_owner.children()[j]) is Some
1041 &&& new_owner.children()[j].unwrap().value().is_frame()
1042 },
1043 forall|j: usize|
1047 #![trigger frame_to_index(
1048 (pa + j * PAGE_SIZE) as usize)]
1049 0 < j < page_size(level) / PAGE_SIZE ==> {
1050 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1051 &&& regions.slots.contains_key(sub_idx)
1052 &&& regions.slot_owners[sub_idx].usage !is PageTable
1053 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1054 &&& regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1055 &&& regions.slot_owners[sub_idx].ref_count() > 0
1056 &&& regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
1057 }
1058 },
1059 regions.slots.contains_key(frame_to_index(pa)),
1060 regions.slot_owner(pa).usage !is PageTable,
1061 regions.slot_owner(pa).usage !is MMIO ==> {
1062 &&& regions.slot_owner(pa).ref_count() != REF_COUNT_UNUSED
1063 &&& 0 < regions.slot_owner(pa).ref_count() <= REF_COUNT_MAX
1064 },
1065 new_page.ptr.addr() == new_owner_meta_addr,
1066 new_owner.value().node().metaregion_sound_node(*regions),
1067 regions.slot_owners[meta_to_index(new_owner_meta_addr)].ref_count()
1068 != REF_COUNT_UNUSED,
1069 0 < regions.slot_owners[meta_to_index(new_owner_meta_addr)].ref_count()
1070 <= REF_COUNT_MAX,
1071 regions.slot_owners[meta_to_index(new_owner_meta_addr)].paths_in_pt
1072 == set![new_owner_path],
1073 {
1074 proof {
1075 C::lemma_page_table_config_constant_properties();
1076 C::lemma_paging_consts_properties();
1077 let ghost the_node = new_owner.value().node();
1078
1079 assert(0 <= i < NR_ENTRIES);
1080 assert(new_owner.has_child(i as int));
1081 assert(new_owner.inv_children());
1082 assert(new_owner.child(i as int).inv());
1083 assert(new_owner.child(i as int).level() == new_owner.level() + 1);
1084 EntryOwner::huge_frame_split_child_at(owner.value(), *regions, i as usize);
1085 }
1086
1087 let small_pa = pa + i * page_size(level - 1);
1088
1089 let tracked mut child_owner = EntryOwner::tracked_new_frame(
1090 small_pa,
1091 new_owner.value().path.push_tail(i as int),
1092 (level - 1) as PagingLevel,
1093 prop,
1094 );
1095
1096 let ghost new_owner_before_update = new_owner;
1097 let tracked mut new_owner_node = {
1098 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1099 new_owner_value.tracked_take_node()
1100 };
1101 let tracked mut new_owner_child = new_owner.tracked_borrow_mut_child(i as int);
1102 let ghost new_owner_child_before_update = *new_owner_child;
1103
1104 proof {
1105 let idx = frame_to_index(small_pa);
1106 if i != 0 {
1107 let ghost big_j =
1108 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1109 pa, level, i);
1110 }
1111 if level - 1 > 1 {
1112 let nr_subpages = page_size((level - 1) as PagingLevel) / PAGE_SIZE;
1113 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1114 (level - 1) as PagingLevel);
1115 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1116 level);
1117 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
1118 level);
1119 assert forall|j_prime: usize|
1120 #![trigger frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize)]
1121 0 < j_prime < nr_subpages implies {
1122 let sub_idx = frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize);
1123 &&& regions.slots.contains_key(sub_idx)
1124 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1125 &&& regions.slot_owners[sub_idx].ref_count() != REF_COUNT_UNUSED
1126 &&& regions.slot_owners[sub_idx].ref_count() > 0
1127 &&& regions.slot_owners[sub_idx].ref_count() <= REF_COUNT_MAX
1128 }
1129 } by {
1130 let sub_pages_per_subframe = page_size((level - 1) as PagingLevel)
1131 / PAGE_SIZE;
1132 let big_j_int: int = i * sub_pages_per_subframe + j_prime;
1133 vstd::arithmetic::mul::lemma_mul_nonnegative(
1134 i as int,
1135 sub_pages_per_subframe as int,
1136 );
1137 vstd::arithmetic::mul::lemma_mul_inequality(
1138 i + 1,
1139 NR_ENTRIES as int,
1140 sub_pages_per_subframe as int,
1141 );
1142 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1143 sub_pages_per_subframe as int,
1144 i as int,
1145 1int,
1146 );
1147 vstd::arithmetic::mul::lemma_mul_is_associative(
1148 NR_ENTRIES as int,
1149 sub_pages_per_subframe as int,
1150 PAGE_SIZE as int,
1151 );
1152 vstd::arithmetic::div_mod::lemma_div_by_multiple(
1153 NR_ENTRIES * sub_pages_per_subframe,
1154 PAGE_SIZE as int,
1155 );
1156 let big_j: usize = big_j_int as usize;
1157 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1158 PAGE_SIZE as int,
1159 i * sub_pages_per_subframe,
1160 j_prime as int,
1161 );
1162 vstd::arithmetic::mul::lemma_mul_is_associative(
1163 i as int,
1164 sub_pages_per_subframe as int,
1165 PAGE_SIZE as int,
1166 );
1167 assert((small_pa + j_prime * PAGE_SIZE) as usize == (pa + big_j
1168 * PAGE_SIZE) as usize);
1169 assert(regions.slots.contains_key(
1170 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1171 ));
1172 }
1173 }
1174 if i == 0 {
1175 assert(i * page_size((level - 1) as PagingLevel) == 0) by {
1176 vstd::arithmetic::mul::lemma_mul_by_zero_is_zero(
1177 page_size((level - 1) as PagingLevel) as int,
1178 );
1179 }
1180 } else {
1181 let ghost big_j =
1182 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1183 pa, level, i);
1184 assert(regions.slots.contains_key(
1185 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1186 ));
1187 }
1188
1189 regions.lemma_contains_valid_frame_paddr(small_pa);
1190 let tracked mut small_slot = regions.tracked_borrow_mut_slot_owner(small_pa);
1191 small_slot.paths_in_pt = small_slot.paths_in_pt.insert(child_owner.path);
1192
1193 if (level - 1) > 1 {
1194 }
1195 let ghost target_idx = frame_to_index(small_pa);
1196 if i != 0 {
1197 let ghost _ =
1198 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1199 pa, level, i);
1200
1201 }
1202 C::lemma_raw_item_well_formed_split(pa, level, prop, small_pa, i);
1203 }
1204
1205 let ghost nidx = meta_to_index(new_owner_meta_addr);
1209 proof {
1210 }
1214 let ghost regions_pre_replace = *regions;
1215 {
1216 let tracked new_owner_child_value = new_owner_child.tracked_borrow_mut_value();
1217 #[verus_spec(with Tracked(regions),
1218 Tracked(new_owner_child_value),
1219 Tracked(&mut child_owner),
1220 Tracked(&mut new_owner_node))]
1221 pt_lock_guard.replace_absent_with_frame(i, small_pa, level - 1, prop);
1222
1223 proof {
1224 *new_owner_child_value = child_owner;
1225 }
1226 }
1227
1228 proof {
1229 new_owner_child_before_update.lemma_set_value_observable_fields(child_owner);
1230 OwnerSubtree::lemma_ext_equal(
1231 *new_owner_child,
1232 new_owner_child_before_update.set_value(child_owner),
1233 );
1234 assert(new_owner_child.inv());
1235
1236 {
1237 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1238 new_owner_value.tracked_put_node(new_owner_node);
1239 }
1240
1241 let owner_with_updated_value = new_owner_before_update.set_value(new_owner.value());
1242 vstd::seq_lib::lemma_update_is_remove_insert(
1243 new_owner_before_update.children(),
1244 i as int,
1245 Some(*new_owner_child),
1246 );
1247 assert(new_owner.children() == new_owner_before_update.children().remove(
1248 i as int,
1249 ).insert(i as int, Some(*new_owner_child)));
1250 assert(owner_with_updated_value.insert(i as int, *new_owner_child).children()
1251 == new_owner_before_update.children().update(i as int, Some(*new_owner_child)));
1252 assert(new_owner.children() =~= owner_with_updated_value.insert(
1253 i as int,
1254 *new_owner_child,
1255 ).children());
1256 assert(new_owner.children() == owner_with_updated_value.insert(
1257 i as int,
1258 *new_owner_child,
1259 ).children());
1260 OwnerSubtree::lemma_ext_equal(
1261 new_owner,
1262 owner_with_updated_value.insert(i as int, *new_owner_child),
1263 );
1264 assert forall|j: int| 0 <= j < NR_ENTRIES implies (
1265 #[trigger] new_owner.children()[j]) is Some by {
1266 if j != i {
1267 assert(owner_with_updated_value.insert(
1268 i as int,
1269 *new_owner_child,
1270 ).children()[j] == owner_with_updated_value.children()[j]);
1271 }
1272 };
1273 assert(new_owner.inv());
1274
1275 }
1276 }
1277
1278 self.pte = {
1279 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1280 #[verus_spec(with Tracked(new_owner_value), Tracked(regions))]
1281 Child::PageTable(new_page).into_pte()
1282 };
1283
1284 proof {
1285 *owner = new_owner;
1286 }
1287
1288 unsafe {
1293 let tracked owner_value = owner.tracked_borrow_mut_value();
1294 #[verus_spec(with Tracked(owner_value.tracked_borrow_mut_node()), Tracked(&*regions))]
1295 self.node.write_pte(self.idx, self.pte)
1296 };
1297
1298 Some(pt_lock_guard)
1299 }
1300
1301 #[verus_spec(res =>
1317 with Tracked(owner): Tracked<&EntryOwner<C>>,
1318 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1319 Tracked(regions): Tracked<&MetaRegionOwners>,
1320 requires
1321 owner.inv(),
1322 parent_owner.inv(),
1323 parent_owner.relate_guard(*guard),
1324 idx < NR_ENTRIES,
1325 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1326 regions.inv(),
1327 regions.slots.contains_key(parent_owner.slot_index),
1328 ensures
1329 res.wf(*owner),
1330 res.idx == idx,
1331 parent_owner.relate_guard(*res.node),
1332 *res.node == *old(guard),
1335 *final(guard) == *final(res.node),
1336 )]
1337 pub(in crate::mm) unsafe fn new_at(guard: &'a mut PageTableGuard<'rcu, C>, idx: usize) -> Self {
1338 let pte = unsafe {
1340 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1341 guard.read_pte(idx)
1342 };
1343 Self::new(pte, idx, guard)
1344 }
1345}
1346
1347#[verus_verify]
1348impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
1349 #[verus_spec(res =>
1350 with Tracked(owner): Tracked<&mut EntryOwner<C>>,
1351 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1352 Tracked(regions): Tracked<&MetaRegionOwners>,
1353 requires
1354 old(owner).inv(),
1355 old(owner).is_frame(),
1356 old(owner).match_pte(
1357 old(parent_owner).children_perm.value()[idx as int],
1358 old(owner).parent_level,
1359 ),
1360 old(parent_owner).inv(),
1361 old(parent_owner).relate_guard(*old(self)),
1362 old(parent_owner).level == old(owner).parent_level,
1363 old(parent_owner).metaregion_sound_node(*regions),
1364 idx < NR_ENTRIES,
1365 op.requires((old(owner).frame().prop,)),
1366 regions.inv(),
1367 regions.slots.contains_key(old(parent_owner).slot_index),
1368 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1369 #![auto]
1370 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
1371 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
1372 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1373 #![auto]
1374 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
1375 ==> C::E::new_page_req(pa, level, p_out),
1376 ensures
1377 final(owner).inv(),
1378 final(owner).is_frame(),
1379 final(owner).match_pte(res, final(parent_owner).level),
1380 final(owner).match_pte(
1381 final(parent_owner).children_perm.value()[idx as int],
1382 final(parent_owner).level,
1383 ),
1384 res == final(parent_owner).children_perm.value()[idx as int],
1385 final(parent_owner).inv(),
1386 final(parent_owner).slot_index == old(parent_owner).slot_index,
1387 final(parent_owner).level == old(parent_owner).level,
1388 final(parent_owner).tree_level == old(parent_owner).tree_level,
1389 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1390 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1391 final(parent_owner).relate_guard(*final(self)),
1392 final(parent_owner).metaregion_sound_node(*regions),
1393 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
1394 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
1395 final(owner).path == old(owner).path,
1396 final(owner).parent_level == old(owner).parent_level,
1397 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1398 #[trigger] final(parent_owner).children_perm.value()[j]
1399 == old(parent_owner).children_perm.value()[j],
1400 crate::specs::mm::page_table::node::owners::count_present(
1401 final(parent_owner).children_perm.value(),
1402 ) == crate::specs::mm::page_table::node::owners::count_present(
1403 old(parent_owner).children_perm.value(),
1404 ),
1405 op.ensures((old(owner).frame().prop,), final(owner).frame().prop),
1406 *final(self) == *old(self),
1407 )]
1408 pub(in crate::mm) fn protect_child(
1409 &mut self,
1410 idx: usize,
1411 op: impl FnOnce(PageProperty) -> PageProperty,
1412 ) -> C::E {
1413 let ghost cp_old = parent_owner.children_perm.value();
1414 let mut pte = unsafe {
1415 #[verus_spec(with Tracked(&*parent_owner), Tracked(regions))]
1416 self.read_pte(idx)
1417 };
1418
1419 let prop = pte.prop();
1420 let new_prop = op(prop);
1421
1422 proof {
1423 assert(owner.frame().prop == prop);
1424 assert(op.ensures((prop,), new_prop));
1425 C::lemma_raw_item_well_formed_preserved(
1426 owner.frame().mapped_pa,
1427 owner.parent_level,
1428 prop,
1429 new_prop,
1430 );
1431 }
1432
1433 assume(pte.set_prop_req(new_prop));
1434 pte.set_prop(new_prop);
1435
1436 unsafe {
1437 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1438 self.write_pte(idx, pte)
1439 };
1440
1441 proof {
1442 owner.tracked_set_frame_prop(new_prop);
1443 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1447 cp_old,
1448 NR_ENTRIES as int,
1449 idx as int,
1450 pte,
1451 );
1452 }
1453
1454 pte
1455 }
1456
1457 #[verifier::spinoff_prover]
1458 #[verus_spec(res =>
1459 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
1460 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1461 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1462 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1463 requires
1464 old(owner).inv(),
1465 old(owner).metaregion_sound(*old(regions)),
1466 old(owner).match_pte(
1467 old(parent_owner).children_perm.value()[idx as int],
1468 old(owner).parent_level,
1469 ),
1470 old(parent_owner).inv(),
1471 old(parent_owner).relate_guard(*old(self)),
1472 old(parent_owner).level == old(owner).parent_level,
1473 idx < NR_ENTRIES,
1474 old(regions).inv(),
1475 old(regions).slots.contains_key(old(parent_owner).slot_index),
1476 new_child.invariants(*old(new_owner), *old(regions)),
1477 old(owner).path == old(new_owner).path,
1478 old(owner).parent_level == old(new_owner).parent_level,
1479 old(new_owner).is_node() ==> {
1480 &&& old(regions).slots.contains_key(frame_to_index(old(new_owner).meta_slot_paddr()->0))
1481 &&& old(regions).slot_owner(old(new_owner).meta_slot_paddr()->0).ref_count() != REF_COUNT_UNUSED
1482 },
1483 old(parent_owner).metaregion_sound_node(*old(regions)),
1484 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
1485 meta_to_index(node.ptr.addr()),
1486 ) > 0,
1487 ensures
1488 res.invariants(*final(owner), *final(regions)),
1489 final(new_owner).inv(),
1490 final(new_owner).metaregion_sound(*final(regions)),
1491 final(new_owner).match_pte(
1492 final(parent_owner).children_perm.value()[idx as int],
1493 final(parent_owner).level,
1494 ),
1495 final(new_owner).path == old(new_owner).path,
1496 final(new_owner).parent_level == old(new_owner).parent_level,
1497 *final(owner) == old(owner).from_pte_owner_spec(),
1498 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1499 Entry::<C>::metaregion_sound_neq_preserved(
1500 *old(owner),
1501 *final(new_owner),
1502 *old(regions),
1503 *final(regions),
1504 ),
1505 !final(new_owner).is_node() ==> Entry::<C>::metaregion_sound_neq_old_preserved(
1506 *old(owner),
1507 *old(regions),
1508 *final(regions),
1509 ),
1510 (!old(owner).is_node() && !final(new_owner).is_node())
1511 ==> Entry::<C>::metaregion_sound_preserved(*old(regions), *final(regions)),
1512 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
1513 C,
1514 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
1515 final(parent_owner).inv(),
1516 final(parent_owner).level == old(parent_owner).level,
1517 final(parent_owner).relate_guard(*final(self)),
1518 final(parent_owner).metaregion_sound_node(*final(regions)),
1519 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1520 #[trigger] final(parent_owner).children_perm.value()[j]
1521 == old(parent_owner).children_perm.value()[j],
1522 forall|slot: int|
1523 #![trigger final(regions).slot_owners[slot].paths_in_pt]
1524 (!final(new_owner).is_node() || final(new_owner).is_absent() || slot
1525 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
1526 ==> final(regions).slot_owners[slot].paths_in_pt == old(
1527 regions,
1528 ).slot_owners[slot].paths_in_pt,
1529 forall|k: int|
1530 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(k),
1531 forall|slot: int|
1532 #![trigger final(regions).slot_owners[slot].ref_count()]
1533 final(regions).slot_owners[slot].ref_count() == old(
1534 regions,
1535 ).slot_owners[slot].ref_count(),
1536 forall|slot: int|
1537 #![trigger final(regions).slot_owners[slot]]
1538 final(regions).slot_owners[slot].same_permissions(
1539 old(regions).slot_owners[slot],
1540 ),
1541 final(regions).slots == old(regions).slots,
1542 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
1543 &&& final(regions).slots == old(regions).slots
1544 &&& forall|i: int|
1545 #![trigger final(regions).slot_owners[i]]
1546 final(regions).slot_owners[i] == old(
1547 regions,
1548 ).slot_owners[i]
1549 &&& final(regions).frame_obligations == old(regions).frame_obligations
1550 },
1551 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
1552 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
1553 == #[trigger] final(regions).slots[k],
1554 Entry::<C>::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
1555 *final(self) == *old(self),
1556 )]
1557 #[verifier::spinoff_prover]
1558 pub(in crate::mm) fn replace_child(&mut self, idx: usize, new_child: Child<C>) -> Child<C> {
1559 #[cfg(feature = "allow_panic")]
1560 {
1561 let guard_level = self.level();
1562 match &new_child {
1563 Child::PageTable(node) => {
1564 assert!(node.level() == guard_level - 1);
1565 },
1566 Child::Frame(_, level, _) => {
1567 assert!(*level == guard_level);
1568 },
1569 Child::None => {},
1570 }
1571 }
1572
1573 let pte = unsafe {
1574 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1575 self.read_pte(idx)
1576 };
1577
1578 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1579 let level = self.level();
1580
1581 let old_child = unsafe {
1582 #[verus_spec(with Tracked(regions), Tracked(owner))]
1583 Child::from_pte(pte, level)
1584 };
1585
1586 let ghost cp0 = parent_owner.children_perm.value();
1588
1589 if old_child.is_none() && !new_child.is_none() {
1590 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
1591 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
1592 parent_owner.slot_index,
1593 );
1594 #[verus_spec(with
1595 Tracked(meta_points_to),
1596 Tracked(&meta_slot_owner.metadata_perm),
1597 Ghost(parent_owner.meta_own.nr_children.id())
1598 )]
1599 let nr_children = self.nr_children_mut();
1600 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1601 proof {
1602 parent_owner.nr_children_absent_slot_bound(idx);
1603 }
1604 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
1605 } else if !old_child.is_none() && new_child.is_none() {
1606 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
1607 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(
1608 parent_owner.slot_index,
1609 );
1610 #[verus_spec(with
1611 Tracked(meta_points_to),
1612 Tracked(&meta_slot_owner.metadata_perm),
1613 Ghost(parent_owner.meta_own.nr_children.id())
1614 )]
1615 let nr_children = self.nr_children_mut();
1616 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1617 proof {
1618 parent_owner.nr_children_present_slot_bound(idx);
1619 }
1620 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
1621 }
1622 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
1623 let new_pte = new_child.into_pte();
1624
1625 unsafe {
1626 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1627 self.write_pte(idx, new_pte)
1628 };
1629
1630 proof {
1631 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1632 cp0,
1633 NR_ENTRIES as int,
1634 idx as int,
1635 new_pte,
1636 );
1637 }
1638
1639 proof {
1640 if new_owner.is_node() {
1641 let paddr = new_owner.meta_slot_paddr().unwrap();
1642 regions.lemma_contains_valid_frame_paddr(paddr);
1643 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
1644 new_meta_slot.paths_in_pt = set![new_owner.path];
1645 }
1646 }
1647
1648 proof {
1649 if new_owner.is_node() || new_owner.is_frame() {
1650 let paddr = new_owner.meta_slot_paddr().unwrap();
1651 regions.lemma_contains_valid_frame_paddr(paddr);
1652 }
1653 }
1654
1655 old_child
1656 }
1657
1658 #[verifier::spinoff_prover]
1659 #[verus_spec(res =>
1660 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
1661 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1662 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1663 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1664 requires
1665 old(owner).inv(),
1666 old(owner).value().is_absent(),
1667 old(owner).level() < INC_LEVELS - 1,
1668 old(owner).value().metaregion_sound(*old(regions)),
1669 old(parent_owner).inv(),
1670 old(parent_owner).relate_guard(*old(self)),
1671 old(parent_owner).level == old(owner).value().parent_level,
1672 old(parent_owner).level > 1,
1673 old(parent_owner).metaregion_sound_node(*old(regions)),
1674 idx < NR_ENTRIES,
1675 old(owner).value().match_pte(
1676 old(parent_owner).children_perm.value()[idx as int],
1677 old(owner).value().parent_level,
1678 ),
1679 old(regions).inv(),
1680 old(regions).slots.contains_key(old(parent_owner).slot_index),
1681 ensures
1682 final(owner).inv(),
1683 final(owner).value().is_node(),
1684 final(owner).level() == old(owner).level(),
1685 final(owner).value().parent_level == old(owner).value().parent_level,
1686 final(owner).value().path == old(owner).value().path,
1687 final(owner).value().metaregion_sound(*final(regions)),
1688 final(owner).value().node().relate_guard(res),
1689 final(owner).value().node().meta_vaddr() == res.inner.inner@.ptr.addr(),
1690 final(owner).value().match_pte(
1691 final(parent_owner).children_perm.value()[idx as int],
1692 final(parent_owner).level,
1693 ),
1694 final(guards).lock_held(final(owner).value().node().meta_vaddr()),
1695 OwnerSubtree::implies(
1696 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
1697 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr())),
1698 Entry::<C>::metaregion_sound_neq_preserved(
1699 old(owner).value(),
1700 final(owner).value(),
1701 *old(regions),
1702 *final(regions),
1703 ),
1704 Entry::<C>::path_tracked_pred_preserved(*old(regions), *final(regions)),
1705 old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0)),
1706 final(owner).subtree_satisfies(final(owner).value().path,
1707 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr())),
1708 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions))),
1709 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions))),
1710 PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![],
1711 forall|i: int| 0 <= i < NR_ENTRIES ==>
1712 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent(),
1713 forall|i: int| 0 <= i < NR_ENTRIES ==>
1714 (#[trigger] final(owner).children()[i])->0.value().path
1715 == final(owner).value().path.push_tail(i),
1716 crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner)),
1717 forall|i: int| 0 <= i < NR_ENTRIES ==>
1718 (#[trigger] final(owner).children()[i])->0.value().parent_level
1719 == final(owner).value().node().level,
1720 forall|i: int| 0 <= i < NR_ENTRIES ==>
1721 (#[trigger] final(owner).children()[i])->0.value().match_pte(
1722 final(owner).value().node().children_perm.value()[i],
1723 final(owner).children()[i]->0.value().parent_level),
1724 forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
1725 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i],
1726 forall|i: int| old(regions).slots.contains_key(i)
1727 ==> (#[trigger] final(regions).slots.contains_key(i)),
1728 forall|i: int| #![trigger final(regions).slots[i]]
1729 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
1730 && old(regions).slots.contains_key(i)
1731 ==> final(regions).slots[i] == old(regions).slots[i],
1732 final(regions).slot_owner(final(owner).value().meta_slot_paddr()->0)
1733 .ref_count() != REF_COUNT_UNUSED,
1734 old(regions).slot_owner(final(owner).value().meta_slot_paddr().unwrap())
1735 .ref_count() == REF_COUNT_UNUSED,
1736 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
1737 final(owner).value().meta_slot_paddr().unwrap()),
1738 final(regions).inv(),
1739 final(parent_owner).inv(),
1740 final(parent_owner).level == old(parent_owner).level,
1741 final(parent_owner).relate_guard(*final(self)),
1742 final(parent_owner).metaregion_sound_node(*final(regions)),
1743 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1744 #[trigger] final(parent_owner).children_perm.value()[j]
1745 == old(parent_owner).children_perm.value()[j],
1746 *final(self) == *old(self),
1747 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
1748 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().meta_vaddr() ==> final(guards).unlocked(i),
1749 )]
1750 pub(in crate::mm) fn alloc_absent_child<A: InAtomicMode>(
1751 &mut self,
1752 idx: usize,
1753 guard: &'rcu A,
1754 ) -> PageTableGuard<'rcu, C> {
1755 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1756 let level = self.level();
1757
1758 let ghost old_path = owner.value().path;
1759
1760 proof {
1766 parent_owner.nr_children_absent_slot_bound(idx);
1767 }
1768 let ghost regions_pre = *regions;
1769 let ghost cp0 = parent_owner.children_perm.value();
1772 let ghost old_owner_val = owner.value();
1775
1776 proof_decl! {
1777 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
1778 }
1779
1780 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(idx) => Tracked(new_node_owner))]
1781 let new_page = PageTableNode::<C>::alloc(level - 1);
1782 let ghost fresh_children = new_node_owner.children();
1783 proof {
1784 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1785 #[trigger] fresh_children[i]) is Some by {
1786 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
1787 new_node_owner,
1788 (level - 1) as PagingLevel,
1789 ));
1790 assert(new_node_owner.has_child(i));
1791 };
1792 }
1793
1794 proof {
1795 let pte = C::E::new_pt_spec(meta_to_frame(new_node_owner.value().node().meta_vaddr()));
1796 C::E::lemma_page_table_entry_properties();
1797 }
1798
1799 let ghost new_node_slot_idx = new_node_owner.value().node().slot_index;
1800 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
1801 #[verus_spec(with Tracked(new_node_slot_perm))]
1802 let paddr = new_page.start_paddr();
1803
1804 let new_pte = {
1805 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1806 #[verus_spec(with Tracked(new_node_value), Tracked(regions))]
1807 Child::PageTable(new_page).into_pte()
1808 };
1809
1810 proof {
1811 broadcast use group_page_meta;
1812
1813 }
1814
1815 let pt_ref = unsafe {
1816 #[verus_spec(with Tracked(regions))]
1817 PageTableNodeRef::borrow_paddr(paddr)
1818 };
1819
1820 let pt_lock_guard = {
1821 let tracked new_node_value = new_node_owner.tracked_borrow_value();
1822 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
1823 pt_ref.lock(guard)
1824 };
1825
1826 unsafe {
1827 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1828 self.write_pte(idx, new_pte)
1829 };
1830
1831 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
1839 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(parent_owner.slot_index);
1840 #[verus_spec(with
1841 Tracked(meta_points_to),
1842 Tracked(&meta_slot_owner.metadata_perm),
1843 Ghost(parent_owner.meta_own.nr_children.id())
1844 )]
1845 let nr_children = self.nr_children_mut();
1846 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1847 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1848
1849 proof {
1850 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1855 cp0,
1856 NR_ENTRIES as int,
1857 idx as int,
1858 new_pte,
1859 );
1860 }
1861
1862 proof {
1863 {
1864 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1865 new_node_value.parent_level = level as PagingLevel;
1866 new_node_value.path = old_path;
1867 }
1868 *owner = new_node_owner;
1869 assert(owner.children() == fresh_children);
1870 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
1871
1872 let new_paddr = owner.value().meta_slot_paddr().unwrap();
1873 regions.lemma_contains_valid_frame_paddr(new_paddr);
1874 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
1875 new_meta_slot.paths_in_pt = set![owner.value().path];
1876 }
1877
1878 proof {
1879 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1880
1881 let ghost new_node_addr = owner.value().node().meta_vaddr();
1882 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
1883 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
1884 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
1885
1886 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1889 *owner,
1890 owner.value().path,
1891 f_nu,
1892 );
1893 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1894 *owner,
1895 owner.value().path,
1896 f_ms,
1897 );
1898 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1899 *owner,
1900 owner.value().path,
1901 f_pt,
1902 );
1903 }
1904
1905 pt_lock_guard
1906 }
1907
1908 #[verifier::spinoff_prover]
1909 #[verus_spec(
1910 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
1911 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1912 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1913 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1914 requires
1915 old(owner).inv(),
1916 old(owner).is_absent(),
1917 old(owner).metaregion_sound(*old(regions)),
1918 old(parent_owner).inv(),
1919 old(parent_owner).relate_guard(*old(self)),
1920 old(parent_owner).level == old(owner).parent_level,
1921 idx < NR_ENTRIES,
1922 old(owner).match_pte(
1923 old(parent_owner).children_perm.value()[idx as int],
1924 old(owner).parent_level,
1925 ),
1926 old(regions).inv(),
1927 old(regions).slots.contains_key(old(parent_owner).slot_index),
1928 old(parent_owner).metaregion_sound_node(*old(regions)),
1929 Child::<C>::Frame(paddr, level, prop).invariants(*old(new_owner), *old(regions)),
1930 old(owner).path == old(new_owner).path,
1931 old(owner).parent_level == old(new_owner).parent_level,
1932 ensures
1933 final(new_owner).inv(),
1934 final(parent_owner).inv(),
1935 *final(owner) == old(owner).from_pte_owner_spec(),
1936 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1937 final(new_owner).pte_invariants(
1938 final(parent_owner).children_perm.value()[idx as int],
1939 *final(regions),
1940 ),
1941 forall|i: int|
1942 0 <= i < NR_ENTRIES && i != idx ==> #[trigger] old(parent_owner).children_perm.value()[i]
1943 == final(parent_owner).children_perm.value()[i],
1944 final(parent_owner).slot_index == old(parent_owner).slot_index,
1945 final(parent_owner).level == old(parent_owner).level,
1946 final(parent_owner).tree_level == old(parent_owner).tree_level,
1947 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1948 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1949 final(parent_owner).relate_guard(*final(self)),
1950 final(parent_owner).metaregion_sound_node(*final(regions)),
1951 *final(regions) == *old(regions),
1952 *final(self) == *old(self),
1953 )]
1954 pub(in crate::mm) fn replace_absent_with_frame(
1955 &mut self,
1956 idx: usize,
1957 paddr: Paddr,
1958 level: PagingLevel,
1959 prop: PageProperty,
1960 ) {
1961 let ghost cp0 = parent_owner.children_perm.value();
1963 let tracked meta_points_to = regions.slots.tracked_borrow(parent_owner.slot_index);
1964 let tracked meta_slot_owner = regions.slot_owners.tracked_borrow(parent_owner.slot_index);
1965 #[verus_spec(with
1966 Tracked(meta_points_to),
1967 Tracked(&meta_slot_owner.metadata_perm),
1968 Ghost(parent_owner.meta_own.nr_children.id())
1969 )]
1970 let nr_children = self.nr_children_mut();
1971 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1972 proof {
1973 parent_owner.nr_children_absent_slot_bound(idx);
1974 }
1975 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1976
1977 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
1978 let new_pte = Child::<C>::Frame(paddr, level, prop).into_pte();
1979
1980 unsafe {
1981 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1982 self.write_pte(idx, new_pte)
1983 };
1984
1985 proof {
1986 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1990 cp0,
1991 NR_ENTRIES as int,
1992 idx as int,
1993 new_pte,
1994 );
1995 }
1996 }
1997}
1998
1999}