1use vstd::prelude::*;
4use vstd_extra::{ghost_tree::*, ownership::*};
5
6use crate::specs::{
7 arch::*,
8 mm::{
9 frame::{
10 mapping::{frame_to_index, meta_to_index},
11 meta_region_owners::MetaRegionOwners,
12 },
13 page_table::{INC_LEVELS, PageTableOwner},
14 },
15 task::InAtomicMode,
16};
17
18use super::*;
19use crate::arch::mm::PagingConsts;
20use crate::mm::frame::meta::mapping::{frame_to_meta, meta_to_frame};
21use crate::mm::frame::{Frame, FrameRef, meta::REF_COUNT_UNUSED};
22use crate::mm::page_table::*;
23use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
24use crate::{
25 mm::{nr_subpage_per_huge, nr_subpage_per_huge_spec, page_prop::PageProperty},
26 };
29use core::marker::PhantomData;
30use core::ops::Deref;
31
32verus! {
33
34broadcast use group_ghost_tree_lemmas;
35
36pub type PageTableNodeRef<'a, C> = FrameRef<'a, PageTablePageMeta<C>>;
38
39pub struct PageTableGuard<'rcu, C: PageTableConfig> {
41 pub inner: PageTableNodeRef<'rcu, C>,
42}
43
44impl<'rcu, C: PageTableConfig> Deref for PageTableGuard<'rcu, C> {
45 type Target = PageTableNodeRef<'rcu, C>;
46
47 #[verus_spec(ensures returns self.inner)]
48 fn deref(&self) -> &Self::Target {
49 &self.inner
50 }
51}
52
53pub struct Entry<'a, 'rcu, C: PageTableConfig> {
54 pub pte: C::E,
73 pub idx: usize,
75 pub node: &'a mut PageTableGuard<'rcu, C>,
77}
78
79#[verus_verify]
80impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
81 pub open spec fn new_spec(
82 pte: C::E,
83 idx: usize,
84 node: &'a mut PageTableGuard<'rcu, C>,
85 ) -> Self {
86 Self { pte, idx, node }
87 }
88
89 #[verus_spec(res =>
90 ensures
91 res.pte == pte,
92 res.idx == idx,
93 *res.node == *old(node),
94 *final(node) == *final(res.node),
95 )]
96 pub fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> Self {
97 Self { pte, idx, node }
98 }
99}
100
101#[verus_verify]
102impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
103 #[verus_spec(r =>
105 with Tracked(owner): Tracked<&EntryOwner<C>>,
106 requires
107 self.wf(*owner),
108 owner.inv(),
109 returns owner.is_absent(),
110 )]
111 pub(in crate::mm) fn is_none(&self) -> bool {
112 !self.pte.is_present()
113 }
114
115 #[verus_spec(
117 with Tracked(owner): Tracked<EntryOwner<C>>,
118 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
119 requires
120 owner.inv(),
121 self.wf(owner),
122 parent_owner.relate_guard(*self.node),
123 parent_owner.inv(),
124 parent_owner.level() == owner.parent_level,
125 returns
126 owner.is_node(),
127 )]
128 pub(in crate::mm) fn is_node(&self) -> bool {
129 self.pte.is_present() && !self.pte.is_last(
130 #[verus_spec(with Tracked(&*parent_owner))]
131 self.node.level(),
132 )
133 }
134
135 #[verus_spec(res =>
137 with Tracked(owner): Tracked<&EntryOwner<C>>,
138 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
139 Tracked(regions): Tracked<&mut MetaRegionOwners>,
140 requires
141 self.invariants(*owner, *old(regions)),
142 self.node_matching(*owner, *parent_owner, *self.node),
143 parent_owner.metaregion_sound_node(*old(regions)),
144 ensures
145 res.invariants(*owner, *final(regions)),
146 final(regions).slots == old(regions).slots,
147 final(regions).slot_owners == old(regions).slot_owners,
148 forall|k: int|
149 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
150 k,
151 ),
152 forall|k: int|
153 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
154 == #[trigger] final(regions).slots[k],
155 final(regions).inv(),
156 )]
157 pub(in crate::mm) fn to_ref(&self) -> ChildRef<'rcu, C> {
158 #[verus_spec(with Tracked(&*parent_owner))]
159 let level = self.node.level();
160
161 let res = unsafe {
165 #[verus_spec(with Tracked(regions), Tracked(owner))]
166 ChildRef::from_pte(&self.pte, level)
167 };
168
169 res
170 }
171
172 #[verus_spec(
189 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
190 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
191 Tracked(regions): Tracked<&MetaRegionOwners>,
192 requires
193 old(owner).inv(),
194 old(self).wf(*old(owner)),
195 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
196 op.requires((old(self).pte.prop(),)),
197 old(owner).is_frame(),
198 regions.inv(),
199 regions.slots.contains_key(old(parent_owner).slot_index),
200 old(parent_owner).metaregion_sound_node(*regions),
201 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty,
207 perm: Tracked<Option<C::Perm>>|
208 #![auto]
209 op.ensures((p_in,), p_out) ==> (
210 C::item_into_raw(C::item_from_raw(pa, level, p_out, perm)).3@
211 is Some
212 ) == (perm@ is Some),
213 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
214 #![auto]
215 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
216 ==> C::E::new_page_req(pa, level, p_out),
217 ensures
218 final(owner).inv(),
219 final(self).wf(*final(owner)),
220 final(self).node_matching(*final(owner), *final(parent_owner), *final(self).node),
221 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
222 final(owner).is_frame(),
223 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
224 final(owner).frame_permission() == old(owner).frame_permission(),
225 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
226 final(owner).path == old(owner).path,
227 final(owner).parent_level == old(owner).parent_level,
228 final(self).idx == old(self).idx,
229 *final(self).node == *old(self).node,
230 old(self).pte.is_present() ==> op.ensures(
231 (old(owner).frame().prop,),
232 final(owner).frame().prop,
233 ),
234 crate::specs::mm::page_table::node::owners::count_present(
239 final(parent_owner).children_perm.value(),
240 ) == crate::specs::mm::page_table::node::owners::count_present(
241 old(parent_owner).children_perm.value(),
242 ),
243 final(parent_owner).meta_own.nr_children.value() == old(
244 parent_owner,
245 ).meta_own.nr_children.value(),
246 )]
247 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty) {
248 #[verus_spec(with Tracked(owner), Tracked(parent_owner), Tracked(regions))]
249 let pte = self.node.protect_child(self.idx, op);
250 self.pte = pte;
251 }
252
253 #[verus_spec(res =>
274 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
275 Tracked(owner): Tracked<&mut EntryOwner<C>>,
276 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
277 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
278 requires
279 old(self).invariants(*old(owner), *old(regions)),
280 new_child.invariants(*old(new_owner), *old(regions)),
281 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
282 old(self).new_owner_compatible(new_child, *old(owner), *old(new_owner), *old(regions)),
283 old(parent_owner).metaregion_sound_node(*old(regions)),
284 ensures
285 res matches Child::PageTable(node) ==> {
286 &&& node.tracked_slot_perm@ == final(regions).slots[final(owner).node().slot_index]
287 &&& node.tracked_metadata_perm@ is None
288 },
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|idx: int|
322 #![trigger final(regions).slot_owners[idx].ref_count()]
323 final(regions).ref_count(idx) == old(
324 regions,
325 ).ref_count(idx),
326 forall|idx: int|
327 #![trigger final(regions).slot_owners[idx]]
328 final(regions).slot_owners[idx].same_permissions(
329 old(regions).slot_owners[idx],
330 ),
331 final(regions).slots == old(regions).slots,
332 forall|idx: int| #![trigger final(regions).slot_owners[idx].usage]
333 old(regions).contains(idx) ==>
334 final(regions).slot_owners[idx].usage == old(regions).slot_owners[idx].usage,
335 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
337 &&& forall|i: int|
338 #![trigger final(regions).slot_owners[i]]
339 final(regions).slot_owners[i] == old(
340 regions,
341 ).slot_owners[i]
342 },
343 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
344 )]
345 #[verifier::spinoff_prover]
346 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> Child<C> {
347 let ghost cp0 = parent_owner.children_perm.value();
348 let ghost initial_regions = *regions;
349 let ghost initial_owner = *owner;
350
351 #[cfg(feature = "allow_panic")]
352 {
353 let guard_level = self.node.level();
354 match &new_child {
355 Child::PageTable(node) => {
356 assert!(node.level() == guard_level - 1);
357 },
358 Child::Frame(_, level, _) => {
359 assert!(*level == guard_level);
360 },
361 Child::None => {},
362 }
363 }
364
365 #[verus_spec(with Tracked(&*parent_owner))]
369 let level = self.node.level();
370
371 let old_child = unsafe {
372 #[verus_spec(with Tracked(regions), Tracked(owner))]
373 Child::from_pte(self.pte, level)
374 };
375
376 if old_child.is_none() && !new_child.is_none() {
377 #[verus_spec(with
378 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
379 &parent_owner.frame_permission,
380 )),
381 Ghost(parent_owner.meta_own.nr_children.id())
382 )]
383 let nr_children = self.node.nr_children_mut();
384 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
385 proof {
386 parent_owner.lemma_nr_children_absent_slot_bound(self.idx);
387 }
388 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
389 } else if !old_child.is_none() && new_child.is_none() {
390 #[verus_spec(with
391 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
392 &parent_owner.frame_permission,
393 )),
394 Ghost(parent_owner.meta_own.nr_children.id())
395 )]
396 let nr_children = self.node.nr_children_mut();
397 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
398 proof {
399 parent_owner.nr_children_present_slot_bound(self.idx);
400 }
401 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
402 }
403 #[verus_spec(with Tracked(new_owner))]
404 let new_pte = new_child.into_pte();
405
406 unsafe {
411 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
412 self.node.write_pte(self.idx, new_pte)
413 };
414
415 self.pte = new_pte;
416
417 proof {
418 if new_owner.is_node() {
420 let paddr = new_owner.meta_slot_paddr().unwrap();
421
422 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
423 new_meta_slot.paths_in_pt = set![new_owner.path];
424 }
425 }
426
427 proof {
428 if new_owner.is_node() || new_owner.is_frame() {
429 let paddr = new_owner.meta_slot_paddr().unwrap();
430 }
431 if owner.is_frame() {
432 let paddr = owner.frame().mapped_pa;
433 let slot = frame_to_index(paddr);
434 C::lemma_perm_well_formed_with_region_preserved(
435 paddr,
436 Tracked(owner.frame_permission()),
437 initial_regions,
438 *regions,
439 );
440 }
441 if new_owner.is_frame() {
442 let paddr = new_owner.frame().mapped_pa;
443 let slot = frame_to_index(paddr);
444 }
445 assert(Self::metaregion_sound_neq_preserved(
446 initial_owner,
447 *new_owner,
448 initial_regions,
449 *regions,
450 )) by {
451 let f = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
452 entry.meta_slot_paddr_neq(initial_owner) && entry.meta_slot_paddr_neq(
453 *new_owner,
454 ) && entry.metaregion_sound(initial_regions);
455 let g = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
456 entry.metaregion_sound(*regions);
457 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
458 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
459 if entry.is_frame() {
460 let paddr = entry.frame().mapped_pa;
461 C::lemma_perm_well_formed_with_region_preserved(
462 paddr,
463 Tracked(entry.frame_permission()),
464 initial_regions,
465 *regions,
466 );
467 }
468 };
469 };
470 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
471 cp0,
472 NR_ENTRIES as int,
473 self.idx as int,
474 new_pte,
475 );
476 }
477
478 old_child
479 }
480
481 #[verus_spec(res =>
498 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
499 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
500 Tracked(regions): Tracked<&mut MetaRegionOwners>,
501 Tracked(guards): Tracked<&mut Guards>,
502 requires
503 old(self).invariants(old(owner).value(), *old(regions)),
504 old(owner).inv(),
505 old(owner).value().path.len() == old(owner).level(),
506 old(self).node_matching(old(owner).value(), *old(parent_owner), *old(self).node),
507 old(owner).level() < INC_LEVELS - 1,
508 old(owner).level() + old(parent_owner).level() == INC_LEVELS,
509 old(parent_owner).metaregion_sound_node(*old(regions)),
510 ensures
511 final(regions).slots == old(regions).slots,
512 final(self).invariants(final(owner).value(), *final(regions)),
513 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
514 final(self).idx == old(self).idx,
515 final(parent_owner).count_consistent(),
516 *final(self).node == *old(self).node,
517 old(owner).value().is_absent() && old(parent_owner).level() > 1 ==> {
518 &&& final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node)
519 &&& final(owner).inv()
520 },
521 old(owner).value().is_absent() && old(parent_owner).level() > 1 ==> {
522 &&& res is Some
523 &&& final(owner).value().is_node()
524 &&& final(owner).level() == old(owner).level()
525 &&& final(owner).value().parent_level == old(owner).value().parent_level
526 &&& final(guards).lock_held(final(owner).value().node().slot_vaddr())
527 &&& final(owner).value().node().relate_guard(res->0)
528 &&& final(owner).value().path == old(owner).value().path
529 &&& final(owner).value().metaregion_sound(*final(regions))
530 &&& MetaSlot::claim_unused_slot_region_spec(
531 final(owner).value().meta_slot_paddr()->0,
532 false, *old(regions), *final(regions))
533 &&& OwnerSubtree::implies(
534 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
535 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr()))
536 &&& Self::metaregion_sound_neq_preserved(old(owner).value(), final(owner).value(), *old(regions), *final(regions))
537 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
538 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0))
539 &&& final(owner).subtree_satisfies(final(owner).value().path,
540 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr()))
541 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
542 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
543 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![]
544 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
545 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent()
546 &&& 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))
550 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
551 (#[trigger] final(owner).child(i)).value().parent_level
552 == final(owner).value().node().level()
553 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
554 (#[trigger] final(owner).child(i)).value().match_pte(
555 final(owner).value().node().children_perm.value()[i],
556 final(owner).child(i).value().parent_level)
557 },
558 !old(owner).value().is_absent() ==> {
559 &&& res is None
560 &&& *final(owner) == *old(owner)
561 },
562 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
563 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().slot_vaddr() ==> final(guards).unlocked(i),
564 )]
565 #[verifier::spinoff_prover]
566 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
567 PageTableGuard<'rcu, C>,
568 > {
569 let entry_is_present = self.pte.is_present();
570 let ghost cp0 = parent_owner.children_perm.value();
571
572 #[verus_spec(with Tracked(&*parent_owner))]
573 let level = self.node.level();
574
575 if entry_is_present || level <= 1 {
576 None
577 } else {
578 let ghost old_path = owner.value().path;
579 let ghost old_owner_val = owner.value();
580
581 proof {
582 parent_owner.lemma_nr_children_absent_slot_bound(self.idx);
583 }
584
585 proof_decl! {
586 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
587 }
588
589 #[verus_spec(with Tracked(regions), Tracked(guards) => Tracked(new_node_owner))]
590 let new_page = PageTableNode::<C>::alloc(level - 1);
591 let ghost fresh_children = new_node_owner.children();
592 proof {
593 assert forall|i: int| 0 <= i < NR_ENTRIES implies {
594 &&& (#[trigger] fresh_children[i]) is Some
595 &&& fresh_children[i]->0.value().is_absent()
596 &&& fresh_children[i]->0.value().parent_level == (level - 1) as PagingLevel
597 } by {
598 assert(new_node_owner.has_child(i));
599 };
600 assert forall|i: int, j: int|
601 0 <= i < NR_ENTRIES && 0 <= j
602 < NR_ENTRIES implies !#[trigger] fresh_children[i]->0.has_child(j) by {
603 assert(!new_node_owner.child(i).has_child(j));
604 };
605 }
606
607 let paddr = new_page.start_paddr();
608
609 let new_pte = {
610 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
611 #[verus_spec(with Tracked(new_node_value))]
612 Child::PageTable(new_page).into_pte()
613 };
614 self.pte = new_pte;
615
616 let tracked new_node = new_node_owner.tracked_borrow_value().tracked_borrow_node();
617 let tracked slot_perm = *regions.slots.tracked_borrow(new_node.slot_index);
618 let pt_ref = unsafe {
619 #[verus_spec(with Tracked(slot_perm), Tracked(&new_node.frame_permission))]
620 PageTableNodeRef::borrow_paddr(paddr)
621 };
622
623 let mut pt_lock_guard = {
625 #[verus_spec(with Tracked(new_node_owner.tracked_borrow_value().tracked_borrow_node()), Tracked(guards))]
626 pt_ref.lock(guard)
627 };
628
629 unsafe {
634 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
635 self.node.write_pte(self.idx, self.pte)
636 };
637
638 #[verus_spec(with
639 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
640 &parent_owner.frame_permission,
641 )),
642 Ghost(parent_owner.meta_own.nr_children.id())
643 )]
644 let nr_children = self.node.nr_children_mut();
645 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
646 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
647
648 proof {
649 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
650 new_node_value.parent_level = level as PagingLevel;
651 new_node_value.path = old_path;
652 *owner = new_node_owner;
653 crate::specs::mm::page_table::tracked_rebase_freshly_allocated_children(
654 owner,
655 old_path,
656 );
657 let new_paddr = owner.value().meta_slot_paddr().unwrap();
658 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
659 new_meta_slot.paths_in_pt = set![owner.value().path];
660
661 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
662 cp0,
663 NR_ENTRIES as int,
664 self.idx as int,
665 self.pte,
666 );
667
668 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(
669 *guards,
670 owner.value().node().slot_vaddr(),
671 );
672 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
673 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
674 Entry::<C>::lemma_allocated_node_preserves_disjoint_entries(
675 old_owner_val,
676 owner.value(),
677 *old(regions),
678 *regions,
679 );
680
681 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
682 *owner,
683 owner.value().path,
684 f_nu,
685 );
686 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
687 *owner,
688 owner.value().path,
689 f_ms,
690 );
691 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
692 *owner,
693 owner.value().path,
694 f_pt,
695 );
696 let pt = PageTableOwner(*owner);
697 pt.lemma_view_rec_contains(old_path);
698 }
699 Some(pt_lock_guard)
700 }
701 }
702
703 #[verifier::spinoff_prover]
719 #[verifier::rlimit(200)]
720 #[verus_spec(res =>
721 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
722 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
723 Tracked(regions): Tracked<&mut MetaRegionOwners>,
724 Tracked(guards): Tracked<&mut Guards>
725 requires
726 old(regions).inv(),
727 old(owner).inv(),
728 old(owner).value().path.len() == old(owner).level(),
729 old(self).wf(old(owner).value()),
730 old(parent_owner).relate_guard(*old(self).node),
731 old(parent_owner).inv(),
732 old(parent_owner).level() == old(owner).value().parent_level,
733 old(parent_owner).level() < NR_LEVELS,
734 old(owner).level() + old(parent_owner).level() == INC_LEVELS,
735 old(self).node_matching(old(owner).value(), *old(parent_owner), *old(self).node),
736 old(parent_owner).metaregion_sound_node(*old(regions)),
737 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==>
738 old(owner).value().metaregion_sound(*old(regions)),
739 ensures
740 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==> {
741 &&& res is Some
742 &&& final(owner).value().is_node()
743 &&& final(owner).level() == old(owner).level()
744 &&& final(parent_owner).relate_guard(*final(self).node)
745 &&& final(owner).value().node().relate_guard(res->0)
746 &&& final(owner).value().node().slot_vaddr() == res->0.inner.inner@.slot_vaddr()
747 &&& PageTableOwner(*final(owner)).pt_inv()
748 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value().path)
749 == Set::<int>::range(0, NR_ENTRIES as int).map(|i: int|
750 CursorView::<C>::split_index(
751 PageTableOwner(*old(owner)).view_rec(old(owner).value().path).choose(),
752 page_size::<PagingConsts>((old(parent_owner).level() - 1) as PagingLevel),
753 i as usize))
754 &&& final(guards).lock_held(res->0.inner.inner@.slot_vaddr())
755 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
756 (#[trigger] final(owner).children()[j])->0.value().is_frame()
757 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
758 (#[trigger] final(owner).children()[j])->0.value().frame().prop
759 == old(owner).value().frame().prop
760 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
761 (#[trigger] final(owner).children()[j])->0.value().frame().mapped_pa
762 == old(owner).value().frame().mapped_pa
763 + j * page_size::<PagingConsts>((old(parent_owner).level() - 1) as PagingLevel)
764 &&& final(owner).value().path == old(owner).value().path
765 &&& final(owner).value().metaregion_sound(*final(regions))
766 &&& OwnerSubtree::implies(
767 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
768 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr()))
769 &&& OwnerSubtree::implies(
770 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
771 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
772 &&& final(owner).subtree_satisfies(final(owner).value().path,
773 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr()))
774 &&& final(owner).subtree_satisfies(final(owner).value().path,
775 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
776 },
777 !old(owner).value().is_frame() || old(parent_owner).level() <= 1 ==> {
778 &&& res is None
779 &&& *final(owner) == *old(owner)
780 },
781 final(owner).inv(),
782 final(owner).value().parent_level == old(owner).value().parent_level,
783 final(self).idx == old(self).idx,
784 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==>
785 final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node),
786 final(regions).inv(),
787 final(parent_owner).inv(),
788 final(parent_owner).level() == old(parent_owner).level(),
789 final(parent_owner).tree_level == old(parent_owner).tree_level,
790 *final(self).node == *old(self).node,
791 *final(final(self).node) == *final(old(self).node),
792 final(parent_owner).metaregion_sound_node(*final(regions)),
793 final(parent_owner).slot_index == old(parent_owner).slot_index,
794 final(parent_owner).meta_own == old(parent_owner).meta_own,
795 final(parent_owner).frame_permission == old(parent_owner).frame_permission,
796 final(regions).slots == old(regions).slots,
797 final(self).node.inner.inner@.slot_vaddr() == old(self).node.inner.inner@.slot_vaddr(),
798 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
799 forall |i: usize| old(guards).unlocked(i)
800 && i != final(owner).value().node().slot_vaddr() ==> final(guards).unlocked(i),
801 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==>
802 MetaSlot::claim_unused_slot_region_spec(
803 final(owner).value().meta_slot_paddr()->0,
804 false, *old(regions), *final(regions)),
805 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==>
810 forall|j: int| 0 <= j < NR_ENTRIES && j != old(self).idx ==>
811 #[trigger] final(parent_owner).children_perm.value()[j]
812 == old(parent_owner).children_perm.value()[j],
813 )]
814 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
815 PageTableGuard<'rcu, C>,
816 > {
817 #[verus_spec(with Tracked(&*parent_owner))]
818 let level = self.node.level();
819
820 if !(self.pte.is_last(level) && level > 1) {
821 return None;
822 }
823 let pa = self.pte.paddr();
824 let prop = self.pte.prop();
825
826 proof {
827 C::lemma_huge_raw_item_untracked(
828 pa,
829 level,
830 prop,
831 Tracked(owner.value().frame_permission()),
832 );
833 }
834
835 proof_decl!{
836 let tracked mut new_owner: OwnerSubtree<C>;
837 }
838
839 #[verus_spec(with Tracked(regions), Tracked(guards) => Tracked(new_owner))]
842 let new_page = PageTableNode::<C>::alloc(level - 1);
843 let ghost fresh_children = new_owner.children();
844 proof {
845 assert forall|i: int, j: int|
846 0 <= i < NR_ENTRIES && 0 <= j
847 < NR_ENTRIES implies !#[trigger] fresh_children[i]->0.has_child(j) by {
848 assert(!new_owner.child(i).has_child(j));
849 };
850 assert forall|i: int| 0 <= i < NR_ENTRIES implies {
851 &&& (#[trigger] fresh_children[i]) is Some
852 &&& fresh_children[i]->0.value().is_absent()
853 &&& fresh_children[i]->0.value().parent_level == (level - 1) as PagingLevel
854 } by {
855 assert(new_owner.has_child(i));
856 };
857 }
858 proof {
859 let tracked new_value = new_owner.tracked_borrow_mut_value();
860 new_value.path = owner.value().path;
861 crate::specs::mm::page_table::tracked_rebase_freshly_allocated_children(
862 &mut new_owner,
863 owner.value().path,
864 );
865 }
866 let paddr = new_page.start_paddr();
867
868 let tracked new_node = new_owner.tracked_borrow_value().tracked_borrow_node();
869 let tracked slot_perm = *regions.slots.tracked_borrow(new_node.slot_index);
870 let pt_ref = unsafe {
871 #[verus_spec(with Tracked(slot_perm), Tracked(&new_node.frame_permission))]
872 PageTableNodeRef::borrow_paddr(paddr)
873 };
874
875 let mut pt_lock_guard = {
877 #[verus_spec(with Tracked(new_owner.tracked_borrow_value().tracked_borrow_node()), Tracked(guards))]
878 pt_ref.lock(guard)
879 };
880
881 let ghost new_owner_path = new_owner.value().path;
882 let ghost new_owner_meta_addr = new_owner.value().node().slot_vaddr();
883
884 proof {
885 C::lemma_paging_consts_properties();
886 C::axiom_current_paging_consts_hardcoded();
887 }
888
889 for i in 0..nr_subpage_per_huge::<C>()
890 invariant
891 nr_subpage_per_huge_spec::<C>() == NR_ENTRIES,
892 1 < level < NR_LEVELS,
893 *self == *old(self),
894 *final(self.node) == *final(old(self).node),
896 owner.inv(),
897 *owner == *old(owner),
898 new_owner.level() == old(owner).level(),
899 new_owner.value().parent_level == level,
900 new_owner.value().path == old(owner).value().path,
901 forall|j: int|
902 0 <= j < i ==> #[trigger] new_owner.child(j).value().frame().prop == prop,
903 forall|j: int|
904 0 <= j < i ==> #[trigger] new_owner.child(j).value().frame().mapped_pa == pa + j
905 * page_size::<PagingConsts>((level - 1) as PagingLevel),
906 owner.value().is_frame(),
907 owner.value().parent_level == level,
908 owner.value().frame().mapped_pa == pa,
909 owner.value().frame().prop == prop,
910 !owner.value().frame_is_tracked(),
911 owner.value().frame_permission() is None,
912 pa == old(owner).value().frame().mapped_pa,
913 level == old(parent_owner).level(),
914 pa % page_size::<PagingConsts>(level) == 0,
915 pa + page_size::<PagingConsts>(level) <= MAX_PADDR,
916 regions.inv(),
917 MetaSlot::claim_unused_slot_region_spec(
918 meta_to_frame(new_owner_meta_addr),
919 false,
920 *old(regions),
921 *regions,
922 ),
923 crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(new_owner),
924 forall|j: int|
925 0 <= j < i ==> #[trigger] new_owner.child(j).value().metaregion_sound(*regions),
926 parent_owner.inv(),
927 parent_owner.metaregion_sound_node(*regions),
928 *parent_owner == *old(parent_owner),
929 new_owner.value().is_node(),
930 new_owner.inv(),
931 new_owner.value().path == new_owner_path,
932 new_owner.value().node().slot_vaddr() == new_owner_meta_addr,
933 new_owner.value().node().relate_guard(pt_lock_guard),
934 guards.lock_held(new_owner_meta_addr),
935 forall|addr: usize| #[trigger]
936 old(guards).lock_held(addr) ==> guards.lock_held(addr),
937 forall|addr: usize| #[trigger]
938 old(guards).unlocked(addr) && addr != new_owner_meta_addr ==> guards.unlocked(
939 addr,
940 ),
941 new_owner.value().node().level() == (level - 1) as PagingLevel,
942 forall|j: int| 0 <= j < NR_ENTRIES ==> (#[trigger] new_owner.children()[j]) is Some,
943 forall|j: int|
944 0 <= j < NR_ENTRIES ==> {
945 &&& (#[trigger] new_owner.children()[j]) is Some
946 &&& new_owner.children()[j].unwrap().value().match_pte(
947 new_owner.value().node().children_perm.value()[j],
948 new_owner.value().node().level(),
949 )
950 &&& new_owner.children()[j].unwrap().value().parent_level
951 == new_owner.value().node().level()
952 &&& new_owner.children()[j].unwrap().value().inv()
953 &&& new_owner.children()[j].unwrap().value().path
954 == new_owner_path.push_tail(j)
955 },
956 forall|j: int|
957 i <= j < NR_ENTRIES ==> {
958 &&& (#[trigger] new_owner.children()[j]) is Some
959 &&& new_owner.children()[j].unwrap().value().is_absent()
960 &&& new_owner.value().node().children_perm.value()[j]
961 == C::E::new_absent_spec()
962 },
963 forall|j: int|
965 0 <= j < i ==> {
966 &&& (#[trigger] new_owner.children()[j]) is Some
967 &&& new_owner.children()[j].unwrap().value().is_frame()
968 },
969 new_page.slot_vaddr() == new_owner_meta_addr,
970 new_owner.value().node().metaregion_sound_node(*regions),
971 regions.slot_owners[meta_to_index(new_owner_meta_addr)].paths_in_pt.is_empty(),
972 {
973 proof {
974 C::lemma_page_table_config_constant_properties();
975 C::axiom_current_paging_consts_hardcoded();
976
977 assert(new_owner.child(i as int).inv());
978 EntryOwner::huge_frame_split_child_at(owner.value(), *regions, i as usize);
979 }
980
981 let small_pa = pa + i * page_size::<C>(level - 1);
982
983 let tracked mut child_owner = EntryOwner::tracked_new_frame(
984 small_pa,
985 new_owner.value().path.push_tail(i as int),
986 (level - 1) as PagingLevel,
987 prop,
988 None,
989 );
990
991 let ghost new_owner_before_update = new_owner;
992 let tracked mut new_owner_node = {
993 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
994 new_owner_value.tracked_take_node()
995 };
996 let tracked mut new_owner_child = new_owner.tracked_borrow_mut_child(i as int);
997 let ghost new_owner_child_before_update = *new_owner_child;
998
999 proof {
1000 C::lemma_raw_item_well_formed_split(
1001 pa,
1002 level,
1003 prop,
1004 small_pa,
1005 i,
1006 Tracked(owner.value().frame_permission()),
1007 );
1008 child_owner.lemma_untracked_frame_metaregion_sound(*regions);
1009 }
1010
1011 {
1012 let tracked new_owner_child_value = new_owner_child.tracked_borrow_mut_value();
1013 #[verus_spec(with Tracked(regions),
1014 Tracked(new_owner_child_value),
1015 Tracked(&mut child_owner),
1016 Tracked(&mut new_owner_node))]
1017 pt_lock_guard.replace_absent_with_frame(i, small_pa, level - 1, prop);
1018
1019 proof {
1020 *new_owner_child_value = child_owner;
1021 }
1022 }
1023
1024 proof {
1025 OwnerSubtree::lemma_ext_equal(
1026 *new_owner_child,
1027 new_owner_child_before_update.set_value(child_owner),
1028 );
1029 {
1030 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1031 new_owner_value.tracked_put_node(new_owner_node);
1032 }
1033
1034 let owner_with_updated_value = new_owner_before_update.set_value(new_owner.value());
1035 OwnerSubtree::lemma_ext_equal(
1036 new_owner,
1037 owner_with_updated_value.insert(i as int, *new_owner_child),
1038 );
1039 assert forall|j: int, k: int|
1040 0 <= j < NR_ENTRIES && 0 <= k < NR_ENTRIES implies !#[trigger] new_owner.child(
1041 j,
1042 ).has_child(k) by {
1043 assert(!new_owner_before_update.child(j).has_child(k));
1044 };
1045 assert forall|j: int| 0 <= j <= i implies #[trigger] new_owner.child(
1046 j,
1047 ).value().frame().prop == prop by {
1048 if j != i {
1049 assert(new_owner.child(j) == new_owner_before_update.child(j));
1050 }
1051 };
1052 assert forall|j: int| 0 <= j <= i implies #[trigger] new_owner.child(
1053 j,
1054 ).value().frame().mapped_pa == pa + j * page_size::<PagingConsts>(
1055 (level - 1) as PagingLevel,
1056 ) by {
1057 if j != i {
1058 assert(new_owner.child(j) == new_owner_before_update.child(j));
1059 }
1060 };
1061 assert forall|j: int| 0 <= j <= i implies #[trigger] new_owner.child(
1062 j,
1063 ).value().metaregion_sound(*regions) by {
1064 if j != i {
1065 assert(new_owner.child(j) == new_owner_before_update.child(j));
1066 }
1067 };
1068 }
1069 }
1070
1071 self.pte = {
1072 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1073 #[verus_spec(with Tracked(new_owner_value))]
1074 Child::PageTable(new_page).into_pte()
1075 };
1076
1077 proof {
1078 *owner = new_owner;
1079 }
1080
1081 unsafe {
1086 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1087 self.node.write_pte(self.idx, self.pte)
1088 };
1089
1090 let ghost regions_before_registration = *regions;
1091 proof {
1092 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1093 old(parent_owner).children_perm.value(),
1094 NR_ENTRIES as int,
1095 self.idx as int,
1096 self.pte,
1097 );
1098 let tracked new_slot = regions.tracked_borrow_mut_slot_owner(
1099 owner.value().meta_slot_paddr().unwrap(),
1100 );
1101 new_slot.paths_in_pt = set![owner.value().path];
1102 assert forall|j: int| 0 <= j < NR_ENTRIES implies #[trigger] owner.child(
1103 j,
1104 ).value().metaregion_sound(*regions) by {
1105 assert(owner.child(j).value().metaregion_sound(regions_before_registration));
1106 owner.child(j).value().lemma_metaregion_sound_one_slot_changed(
1107 regions_before_registration,
1108 *regions,
1109 frame_to_index(owner.value().meta_slot_paddr()->0),
1110 );
1111 };
1112 PageTableOwner::<C>::lemma_fresh_node_pt_inv(*owner);
1113 PageTableOwner(*owner).lemma_split_node_view(PageTableOwner(*old(owner)));
1114 let absent = EntryOwner::<C>::new_absent(
1115 owner.value().path,
1116 owner.value().parent_level,
1117 );
1118 Entry::<C>::lemma_allocated_node_preserves_disjoint_entries(
1119 absent,
1120 owner.value(),
1121 *old(regions),
1122 *regions,
1123 );
1124 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
1125 *owner,
1126 owner.value().path,
1127 CursorOwner::<'rcu, C>::node_unlocked_except(
1128 *guards,
1129 owner.value().node().slot_vaddr(),
1130 ),
1131 );
1132 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
1133 *owner,
1134 owner.value().path,
1135 PageTableOwner::<C>::metaregion_sound_pred(*regions),
1136 );
1137 assert forall|j: int| 0 <= j < NR_ENTRIES implies (
1138 #[trigger] owner.children()[j])->0.value().frame().mapped_pa == old(
1139 owner,
1140 ).value().frame().mapped_pa + j * page_size::<PagingConsts>(
1141 (old(parent_owner).level() - 1) as PagingLevel,
1142 ) by {
1143 assert(owner.child(j).value().frame().mapped_pa == pa + j * page_size::<
1144 PagingConsts,
1145 >((level - 1) as PagingLevel));
1146 };
1147 assert forall|j: int| 0 <= j < NR_ENTRIES implies (
1148 #[trigger] owner.children()[j])->0.value().frame().prop == old(
1149 owner,
1150 ).value().frame().prop by {
1151 assert(owner.child(j).value().frame().prop == prop);
1152 };
1153 }
1154 Some(pt_lock_guard)
1155 }
1156
1157 #[verus_spec(res =>
1173 with Tracked(owner): Tracked<&EntryOwner<C>>,
1174 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1175 Tracked(regions): Tracked<&MetaRegionOwners>,
1176 requires
1177 owner.inv(),
1178 parent_owner.inv(),
1179 parent_owner.relate_guard(*guard),
1180 idx < NR_ENTRIES,
1181 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1182 regions.inv(),
1183 regions.slots.contains_key(parent_owner.slot_index),
1184 ensures
1185 res.wf(*owner),
1186 res.idx == idx,
1187 parent_owner.relate_guard(*res.node),
1188 *res.node == *old(guard),
1191 *final(guard) == *final(res.node),
1192 )]
1193 pub(in crate::mm) unsafe fn new_at(guard: &'a mut PageTableGuard<'rcu, C>, idx: usize) -> Self {
1194 let pte = unsafe {
1196 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1197 guard.read_pte(idx)
1198 };
1199 Self::new(pte, idx, guard)
1200 }
1201}
1202
1203#[verus_verify]
1204impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
1205 #[verus_spec(res =>
1206 with Tracked(owner): Tracked<&mut EntryOwner<C>>,
1207 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1208 Tracked(regions): Tracked<&MetaRegionOwners>,
1209 requires
1210 old(owner).inv(),
1211 old(owner).is_frame(),
1212 old(owner).match_pte(
1213 old(parent_owner).children_perm.value()[idx as int],
1214 old(owner).parent_level,
1215 ),
1216 old(parent_owner).inv(),
1217 old(parent_owner).relate_guard(*old(self)),
1218 old(parent_owner).level() == old(owner).parent_level,
1219 old(parent_owner).metaregion_sound_node(*regions),
1220 idx < NR_ENTRIES,
1221 op.requires((old(owner).frame().prop,)),
1222 regions.inv(),
1223 regions.slots.contains_key(old(parent_owner).slot_index),
1224 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty,
1225 perm: Tracked<Option<C::Perm>>|
1226 #![auto]
1227 op.ensures((p_in,), p_out) ==> (
1228 C::item_into_raw(C::item_from_raw(pa, level, p_out, perm)).3@
1229 is Some
1230 ) == (perm@ is Some),
1231 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1232 #![auto]
1233 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
1234 ==> C::E::new_page_req(pa, level, p_out),
1235 ensures
1236 final(owner).inv(),
1237 final(owner).is_frame(),
1238 final(owner).match_pte(res, final(parent_owner).level()),
1239 final(owner).match_pte(
1240 final(parent_owner).children_perm.value()[idx as int],
1241 final(parent_owner).level(),
1242 ),
1243 res == final(parent_owner).children_perm.value()[idx as int],
1244 final(parent_owner).inv(),
1245 final(parent_owner).slot_index == old(parent_owner).slot_index,
1246 final(parent_owner).level() == old(parent_owner).level(),
1247 final(parent_owner).tree_level == old(parent_owner).tree_level,
1248 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1249 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1250 final(parent_owner).relate_guard(*final(self)),
1251 final(parent_owner).metaregion_sound_node(*regions),
1252 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
1253 final(owner).frame_permission() == old(owner).frame_permission(),
1254 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
1255 final(owner).path == old(owner).path,
1256 final(owner).parent_level == old(owner).parent_level,
1257 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1258 #[trigger] final(parent_owner).children_perm.value()[j]
1259 == old(parent_owner).children_perm.value()[j],
1260 crate::specs::mm::page_table::node::owners::count_present(
1261 final(parent_owner).children_perm.value(),
1262 ) == crate::specs::mm::page_table::node::owners::count_present(
1263 old(parent_owner).children_perm.value(),
1264 ),
1265 op.ensures((old(owner).frame().prop,), final(owner).frame().prop),
1266 *final(self) == *old(self),
1267 )]
1268 pub(in crate::mm) fn protect_child(
1269 &mut self,
1270 idx: usize,
1271 op: impl FnOnce(PageProperty) -> PageProperty,
1272 ) -> C::E {
1273 let ghost cp_old = parent_owner.children_perm.value();
1274 let mut pte = unsafe {
1275 #[verus_spec(with Tracked(&*parent_owner), Tracked(regions))]
1276 self.read_pte(idx)
1277 };
1278
1279 let prop = pte.prop();
1280 let new_prop = op(prop);
1281
1282 proof {
1283 assert(owner.frame().prop == prop);
1284 assert(op.ensures((prop,), new_prop));
1285 C::lemma_raw_item_well_formed_preserved(
1286 owner.frame().mapped_pa,
1287 owner.parent_level,
1288 prop,
1289 new_prop,
1290 Tracked(owner.frame_permission()),
1291 );
1292 }
1293
1294 assume(pte.set_prop_req(new_prop));
1295 pte.set_prop(new_prop);
1296
1297 unsafe {
1298 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1299 self.write_pte(idx, pte)
1300 };
1301
1302 proof {
1303 owner.tracked_set_frame_prop(new_prop);
1304 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1308 cp_old,
1309 NR_ENTRIES as int,
1310 idx as int,
1311 pte,
1312 );
1313 }
1314
1315 pte
1316 }
1317
1318 #[verifier::spinoff_prover]
1319 #[verus_spec(res =>
1320 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
1321 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1322 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1323 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1324 requires
1325 old(owner).inv(),
1326 old(owner).metaregion_sound(*old(regions)),
1327 old(owner).match_pte(
1328 old(parent_owner).children_perm.value()[idx as int],
1329 old(owner).parent_level,
1330 ),
1331 old(parent_owner).inv(),
1332 old(parent_owner).relate_guard(*old(self)),
1333 old(parent_owner).level() == old(owner).parent_level,
1334 idx < NR_ENTRIES,
1335 old(regions).inv(),
1336 old(regions).slots.contains_key(old(parent_owner).slot_index),
1337 new_child.invariants(*old(new_owner), *old(regions)),
1338 old(owner).path == old(new_owner).path,
1339 old(owner).parent_level == old(new_owner).parent_level,
1340 old(new_owner).is_node() ==> {
1341 &&& old(regions).slots.contains_key(frame_to_index(old(new_owner).meta_slot_paddr()->0))
1342 &&& old(regions).slot_owner(old(new_owner).meta_slot_paddr()->0).ref_count() != REF_COUNT_UNUSED
1343 },
1344 old(parent_owner).metaregion_sound_node(*old(regions)),
1345 ensures
1346 res matches Child::PageTable(node) ==> {
1347 &&& node.tracked_slot_perm@ == final(regions).slots[final(owner).node().slot_index]
1348 &&& node.tracked_metadata_perm@ is None
1349 },
1350 res.invariants(*final(owner), *final(regions)),
1351 final(new_owner).inv(),
1352 final(new_owner).metaregion_sound(*final(regions)),
1353 final(new_owner).match_pte(
1354 final(parent_owner).children_perm.value()[idx as int],
1355 final(parent_owner).level(),
1356 ),
1357 final(new_owner).path == old(new_owner).path,
1358 final(new_owner).parent_level == old(new_owner).parent_level,
1359 *final(owner) == old(owner).from_pte_owner_spec(),
1360 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1361 Entry::<C>::metaregion_sound_neq_preserved(
1362 *old(owner),
1363 *final(new_owner),
1364 *old(regions),
1365 *final(regions),
1366 ),
1367 !final(new_owner).is_node() ==> Entry::<C>::metaregion_sound_neq_old_preserved(
1368 *old(owner),
1369 *old(regions),
1370 *final(regions),
1371 ),
1372 (!old(owner).is_node() && !final(new_owner).is_node())
1373 ==> Entry::<C>::metaregion_sound_preserved(*old(regions), *final(regions)),
1374 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
1375 C,
1376 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
1377 final(parent_owner).inv(),
1378 final(parent_owner).level() == old(parent_owner).level(),
1379 final(parent_owner).relate_guard(*final(self)),
1380 final(parent_owner).metaregion_sound_node(*final(regions)),
1381 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1382 #[trigger] final(parent_owner).children_perm.value()[j]
1383 == old(parent_owner).children_perm.value()[j],
1384 forall|slot: int|
1385 #![trigger final(regions).slot_owners[slot].paths_in_pt]
1386 (!final(new_owner).is_node() || final(new_owner).is_absent() || slot
1387 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
1388 ==> final(regions).slot_owners[slot].paths_in_pt == old(
1389 regions,
1390 ).slot_owners[slot].paths_in_pt,
1391 forall|slot: int|
1392 #![trigger final(regions).slot_owners[slot].ref_count()]
1393 final(regions).ref_count(slot) == old(
1394 regions,
1395 ).ref_count(slot),
1396 forall|slot: int|
1397 #![trigger final(regions).slot_owners[slot]]
1398 final(regions).slot_owners[slot].same_permissions(
1399 old(regions).slot_owners[slot],
1400 ),
1401 final(regions).slots == old(regions).slots,
1402 forall|slot: int| #![trigger final(regions).slot_owners[slot].usage]
1403 old(regions).contains(slot) ==>
1404 final(regions).slot_owners[slot].usage == old(regions).slot_owners[slot].usage,
1405 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
1406 &&& forall|i: int|
1407 #![trigger final(regions).slot_owners[i]]
1408 final(regions).slot_owners[i] == old(
1409 regions,
1410 ).slot_owners[i]
1411 },
1412 Entry::<C>::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
1413 *final(self) == *old(self),
1414 )]
1415 #[verifier::spinoff_prover]
1416 pub(in crate::mm) fn replace_child(&mut self, idx: usize, new_child: Child<C>) -> Child<C> {
1417 let ghost initial_regions = *regions;
1418 let ghost initial_owner = *owner;
1419 #[cfg(feature = "allow_panic")]
1420 {
1421 let guard_level = self.level();
1422 match &new_child {
1423 Child::PageTable(node) => {
1424 assert!(node.level() == guard_level - 1);
1425 },
1426 Child::Frame(_, level, _) => {
1427 assert!(*level == guard_level);
1428 },
1429 Child::None => {},
1430 }
1431 }
1432
1433 let pte = unsafe {
1434 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1435 self.read_pte(idx)
1436 };
1437
1438 #[verus_spec(with Tracked(&*parent_owner))]
1439 let level = self.level();
1440
1441 let old_child = unsafe {
1442 #[verus_spec(with Tracked(regions), Tracked(owner))]
1443 Child::from_pte(pte, level)
1444 };
1445
1446 let ghost cp0 = parent_owner.children_perm.value();
1448
1449 if old_child.is_none() && !new_child.is_none() {
1450 #[verus_spec(with
1451 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
1452 &parent_owner.frame_permission,
1453 )),
1454 Ghost(parent_owner.meta_own.nr_children.id())
1455 )]
1456 let nr_children = self.nr_children_mut();
1457 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1458 proof {
1459 parent_owner.lemma_nr_children_absent_slot_bound(idx);
1460 }
1461 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
1462 } else if !old_child.is_none() && new_child.is_none() {
1463 #[verus_spec(with
1464 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
1465 &parent_owner.frame_permission,
1466 )),
1467 Ghost(parent_owner.meta_own.nr_children.id())
1468 )]
1469 let nr_children = self.nr_children_mut();
1470 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1471 proof {
1472 parent_owner.nr_children_present_slot_bound(idx);
1473 }
1474 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
1475 }
1476 #[verus_spec(with Tracked(new_owner))]
1477 let new_pte = new_child.into_pte();
1478
1479 unsafe {
1480 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1481 self.write_pte(idx, new_pte)
1482 };
1483
1484 proof {
1485 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1486 cp0,
1487 NR_ENTRIES as int,
1488 idx as int,
1489 new_pte,
1490 );
1491 if new_owner.is_node() {
1492 let paddr = new_owner.meta_slot_paddr().unwrap();
1493 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
1494 new_meta_slot.paths_in_pt = set![new_owner.path];
1495 }
1496 if owner.is_frame() {
1497 let paddr = owner.frame().mapped_pa;
1498 let slot = frame_to_index(paddr);
1499 C::lemma_perm_well_formed_with_region_preserved(
1500 paddr,
1501 Tracked(owner.frame_permission()),
1502 initial_regions,
1503 *regions,
1504 );
1505 }
1506 assert(Entry::<C>::metaregion_sound_neq_preserved(
1507 initial_owner,
1508 *new_owner,
1509 initial_regions,
1510 *regions,
1511 )) by {
1512 let f = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1513 entry.meta_slot_paddr_neq(initial_owner) && entry.meta_slot_paddr_neq(
1514 *new_owner,
1515 ) && entry.metaregion_sound(initial_regions);
1516 let g = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1517 entry.metaregion_sound(*regions);
1518 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1519 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
1520 if entry.is_frame() {
1521 let paddr = entry.frame().mapped_pa;
1522 let slot = frame_to_index(paddr);
1523 C::lemma_perm_well_formed_with_region_preserved(
1524 paddr,
1525 Tracked(entry.frame_permission()),
1526 initial_regions,
1527 *regions,
1528 );
1529 }
1530 };
1531 };
1532 }
1533
1534 old_child
1535 }
1536
1537 #[verifier::spinoff_prover]
1538 #[verus_spec(res =>
1539 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
1540 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1541 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1542 Tracked(guards): Tracked<&mut Guards>,
1543 requires
1544 old(owner).inv(),
1545 old(owner).value().path.len() == old(owner).level(),
1546 old(owner).value().is_absent(),
1547 old(owner).level() < INC_LEVELS - 1,
1548 old(owner).value().metaregion_sound(*old(regions)),
1549 old(parent_owner).inv(),
1550 old(parent_owner).relate_guard(*old(self)),
1551 old(parent_owner).level() == old(owner).value().parent_level,
1552 old(parent_owner).level() > 1,
1553 old(owner).level() + old(parent_owner).level() == INC_LEVELS,
1554 old(parent_owner).metaregion_sound_node(*old(regions)),
1555 idx < NR_ENTRIES,
1556 old(owner).value().match_pte(
1557 old(parent_owner).children_perm.value()[idx as int],
1558 old(owner).value().parent_level,
1559 ),
1560 old(regions).inv(),
1561 old(regions).slots.contains_key(old(parent_owner).slot_index),
1562 ensures
1563 final(regions).slots == old(regions).slots,
1564 final(owner).inv(),
1565 final(owner).value().is_node(),
1566 final(owner).level() == old(owner).level(),
1567 final(owner).value().parent_level == old(owner).value().parent_level,
1568 final(owner).value().path == old(owner).value().path,
1569 final(owner).value().metaregion_sound(*final(regions)),
1570 final(owner).value().node().relate_guard(res),
1571 final(owner).value().node().slot_vaddr() == res.inner.inner@.slot_vaddr(),
1572 final(owner).value().match_pte(
1573 final(parent_owner).children_perm.value()[idx as int],
1574 final(parent_owner).level(),
1575 ),
1576 final(guards).lock_held(final(owner).value().node().slot_vaddr()),
1577 OwnerSubtree::implies(
1578 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
1579 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr())),
1580 Entry::<C>::metaregion_sound_neq_preserved(
1581 old(owner).value(),
1582 final(owner).value(),
1583 *old(regions),
1584 *final(regions),
1585 ),
1586 Entry::<C>::path_tracked_pred_preserved(*old(regions), *final(regions)),
1587 old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0)),
1588 final(owner).subtree_satisfies(final(owner).value().path,
1589 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr())),
1590 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions))),
1591 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions))),
1592 PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![],
1593 forall|i: int| 0 <= i < NR_ENTRIES ==>
1594 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent(),
1595 forall|i: int| 0 <= i < NR_ENTRIES ==>
1596 (#[trigger] final(owner).children()[i])->0.value().path
1597 == final(owner).value().path.push_tail(i),
1598 crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner)),
1599 forall|i: int| 0 <= i < NR_ENTRIES ==>
1600 (#[trigger] final(owner).children()[i])->0.value().parent_level
1601 == final(owner).value().node().level(),
1602 forall|i: int| 0 <= i < NR_ENTRIES ==>
1603 (#[trigger] final(owner).children()[i])->0.value().match_pte(
1604 final(owner).value().node().children_perm.value()[i],
1605 final(owner).children()[i]->0.value().parent_level),
1606 forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
1607 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i],
1608 forall|i: int| old(regions).slots.contains_key(i)
1609 ==> (#[trigger] final(regions).slots.contains_key(i)),
1610 forall|i: int| #![trigger final(regions).slots[i]]
1611 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
1612 && old(regions).slots.contains_key(i)
1613 ==> final(regions).slots[i] == old(regions).slots[i],
1614 final(regions).slot_owner(final(owner).value().meta_slot_paddr()->0)
1615 .ref_count() != REF_COUNT_UNUSED,
1616 old(regions).slot_owner(final(owner).value().meta_slot_paddr().unwrap())
1617 .ref_count() == REF_COUNT_UNUSED,
1618 final(regions).inv(),
1619 final(parent_owner).inv(),
1620 final(parent_owner).level() == old(parent_owner).level(),
1621 final(parent_owner).relate_guard(*final(self)),
1622 final(parent_owner).metaregion_sound_node(*final(regions)),
1623 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1624 #[trigger] final(parent_owner).children_perm.value()[j]
1625 == old(parent_owner).children_perm.value()[j],
1626 *final(self) == *old(self),
1627 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
1628 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().slot_vaddr() ==> final(guards).unlocked(i),
1629 )]
1630 pub(in crate::mm) fn alloc_absent_child<A: InAtomicMode>(
1631 &mut self,
1632 idx: usize,
1633 guard: &'rcu A,
1634 ) -> PageTableGuard<'rcu, C> {
1635 #[verus_spec(with Tracked(&*parent_owner))]
1636 let level = self.level();
1637
1638 let ghost old_path = owner.value().path;
1639
1640 proof {
1646 parent_owner.lemma_nr_children_absent_slot_bound(idx);
1647 }
1648 let ghost cp0 = parent_owner.children_perm.value();
1651 let ghost old_owner_val = owner.value();
1654
1655 proof_decl! {
1656 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
1657 }
1658
1659 #[verus_spec(with Tracked(regions), Tracked(guards) => Tracked(new_node_owner))]
1660 let new_page = PageTableNode::<C>::alloc(level - 1);
1661 let ghost fresh_children = new_node_owner.children();
1662
1663 proof {
1664 assert forall|i: int| 0 <= i < NR_ENTRIES implies {
1665 &&& (#[trigger] fresh_children[i]) is Some
1666 &&& fresh_children[i]->0.value().is_absent()
1667 &&& fresh_children[i]->0.value().parent_level == (level - 1) as PagingLevel
1668 } by {
1669 assert(new_node_owner.has_child(i));
1670 };
1671 assert forall|i: int, j: int|
1672 0 <= i < NR_ENTRIES && 0 <= j
1673 < NR_ENTRIES implies !#[trigger] fresh_children[i]->0.has_child(j) by {
1674 assert(!new_node_owner.child(i).has_child(j));
1675 };
1676 }
1677
1678 let paddr = new_page.start_paddr();
1679
1680 let new_pte = {
1681 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1682 #[verus_spec(with Tracked(new_node_value))]
1683 Child::PageTable(new_page).into_pte()
1684 };
1685
1686 let tracked new_node_value = new_node_owner.tracked_borrow_value();
1687 let tracked new_node = new_node_value.tracked_borrow_node();
1688 let tracked slot_perm = *regions.slots.tracked_borrow(new_node.slot_index);
1689 let pt_ref = unsafe {
1690 #[verus_spec(with Tracked(slot_perm), Tracked(&new_node.frame_permission))]
1691 PageTableNodeRef::borrow_paddr(paddr)
1692 };
1693
1694 let pt_lock_guard = {
1695 let tracked new_node_value = new_node_owner.tracked_borrow_value();
1696 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
1697 pt_ref.lock(guard)
1698 };
1699
1700 unsafe {
1701 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1702 self.write_pte(idx, new_pte)
1703 };
1704
1705 #[verus_spec(with
1706 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
1707 &parent_owner.frame_permission,
1708 )),
1709 Ghost(parent_owner.meta_own.nr_children.id())
1710 )]
1711 let nr_children = self.nr_children_mut();
1712 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1713 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1714
1715 proof {
1716 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1717 cp0,
1718 NR_ENTRIES as int,
1719 idx as int,
1720 new_pte,
1721 );
1722 {
1723 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1724 new_node_value.parent_level = level as PagingLevel;
1725 new_node_value.path = old_path;
1726 }
1727 *owner = new_node_owner;
1728 crate::specs::mm::page_table::tracked_rebase_freshly_allocated_children(
1729 owner,
1730 old_path,
1731 );
1732
1733 let new_paddr = owner.value().meta_slot_paddr().unwrap();
1734 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
1735 new_meta_slot.paths_in_pt = set![owner.value().path];
1736
1737 let ghost new_node_addr = owner.value().node().slot_vaddr();
1738 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
1739 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
1740 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
1741 Entry::<C>::lemma_allocated_node_preserves_disjoint_entries(
1742 old_owner_val,
1743 owner.value(),
1744 *old(regions),
1745 *regions,
1746 );
1747
1748 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
1749 *owner,
1750 owner.value().path,
1751 f_nu,
1752 );
1753 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
1754 *owner,
1755 owner.value().path,
1756 f_ms,
1757 );
1758 crate::specs::mm::page_table::lemma_fresh_node_subtree_satisfies(
1759 *owner,
1760 owner.value().path,
1761 f_pt,
1762 );
1763 let pt = PageTableOwner(*owner);
1764 assert forall|m: crate::specs::mm::page_table::Mapping|
1765 pt.view_rec(old_path).contains(m) implies false by {
1766 let i = pt.view_rec_contains_choose(old_path, m);
1767 };
1768 }
1769
1770 pt_lock_guard
1771 }
1772
1773 #[verifier::spinoff_prover]
1774 #[verus_spec(
1775 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
1776 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1777 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1778 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1779 requires
1780 old(owner).inv(),
1781 old(owner).is_absent(),
1782 old(owner).metaregion_sound(*old(regions)),
1783 old(parent_owner).inv(),
1784 old(parent_owner).relate_guard(*old(self)),
1785 old(parent_owner).level() == old(owner).parent_level,
1786 idx < NR_ENTRIES,
1787 old(owner).match_pte(
1788 old(parent_owner).children_perm.value()[idx as int],
1789 old(owner).parent_level,
1790 ),
1791 old(regions).inv(),
1792 old(regions).slots.contains_key(old(parent_owner).slot_index),
1793 old(parent_owner).metaregion_sound_node(*old(regions)),
1794 Child::<C>::Frame(paddr, level, prop).invariants(*old(new_owner), *old(regions)),
1795 old(owner).path == old(new_owner).path,
1796 old(owner).parent_level == old(new_owner).parent_level,
1797 ensures
1798 final(new_owner).inv(),
1799 final(parent_owner).inv(),
1800 *final(owner) == old(owner).from_pte_owner_spec(),
1801 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1802 final(new_owner).pte_invariants(
1803 final(parent_owner).children_perm.value()[idx as int],
1804 *final(regions),
1805 ),
1806 forall|i: int|
1807 0 <= i < NR_ENTRIES && i != idx ==> #[trigger] old(parent_owner).children_perm.value()[i]
1808 == final(parent_owner).children_perm.value()[i],
1809 final(parent_owner).slot_index == old(parent_owner).slot_index,
1810 final(parent_owner).level() == old(parent_owner).level(),
1811 final(parent_owner).tree_level == old(parent_owner).tree_level,
1812 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1813 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1814 final(parent_owner).relate_guard(*final(self)),
1815 final(parent_owner).metaregion_sound_node(*final(regions)),
1816 *final(regions) == *old(regions),
1817 *final(self) == *old(self),
1818 )]
1819 pub(in crate::mm) fn replace_absent_with_frame(
1820 &mut self,
1821 idx: usize,
1822 paddr: Paddr,
1823 level: PagingLevel,
1824 prop: PageProperty,
1825 ) {
1826 let ghost cp0 = parent_owner.children_perm.value();
1827 #[verus_spec(with
1828 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
1829 &parent_owner.frame_permission,
1830 )),
1831 Ghost(parent_owner.meta_own.nr_children.id())
1832 )]
1833 let nr_children = self.nr_children_mut();
1834 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1835 proof {
1836 parent_owner.lemma_nr_children_absent_slot_bound(idx);
1837 }
1838 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1839
1840 #[verus_spec(with Tracked(new_owner))]
1841 let new_pte = Child::<C>::Frame(paddr, level, prop).into_pte();
1842
1843 unsafe {
1844 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1845 self.write_pte(idx, new_pte)
1846 };
1847
1848 proof {
1849 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1850 cp0,
1851 NR_ENTRIES as int,
1852 idx as int,
1853 new_pte,
1854 );
1855 }
1856 }
1857}
1858
1859}