1use vstd::prelude::*;
4
5use vstd_extra::cast_ptr;
6use vstd_extra::drop_tracking::ManuallyDrop;
7use vstd_extra::ghost_tree::*;
8use vstd_extra::ownership::*;
9
10use crate::mm::frame::meta::mapping::{frame_to_index, frame_to_meta, meta_to_frame};
11use crate::mm::frame::{Frame, FrameRef};
12use crate::mm::page_table::*;
13use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
14use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
15use crate::specs::arch::paging_consts::PagingConsts;
16use crate::specs::mm::frame::meta_owners::{MetaSlotOwner, REF_COUNT_UNUSED};
17use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
18use crate::specs::mm::page_table::{INC_LEVELS, PageTableOwner};
19use crate::specs::task::InAtomicMode;
20
21use core::marker::PhantomData;
22use core::ops::Deref;
23
24use crate::{
25 mm::{nr_subpage_per_huge, page_prop::PageProperty},
26 };
29
30use super::*;
31
32verus! {
33
34pub type PageTableNodeRef<'a, C> = FrameRef<'a, PageTablePageMeta<C>>;
36
37pub struct PageTableGuard<'rcu, C: PageTableConfig> {
39 pub inner: PageTableNodeRef<'rcu, C>,
40}
41
42impl<'rcu, C: PageTableConfig> Deref for PageTableGuard<'rcu, C> {
43 type Target = PageTableNodeRef<'rcu, C>;
44
45 #[verus_spec(ensures returns self.inner)]
46 fn deref(&self) -> &Self::Target {
47 &self.inner
48 }
49}
50
51pub struct Entry<'a, 'rcu, C: PageTableConfig> {
52 pub pte: C::E,
71 pub idx: usize,
73 pub node: &'a mut PageTableGuard<'rcu, C>,
75}
76
77impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
78 pub open spec fn new_spec(
79 pte: C::E,
80 idx: usize,
81 node: &'a mut PageTableGuard<'rcu, C>,
82 ) -> Self {
83 Self { pte, idx, node }
84 }
85
86 #[verifier::external_body]
87 pub fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> (res: Self)
88 ensures
89 res == Self::new_spec(pte, idx, node),
90 *final(node) == *old(node),
94 {
95 Self { pte, idx, node }
96 }
97}
98
99#[verus_verify]
100impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
101 #[verus_spec(r =>
103 with Tracked(owner): Tracked<&EntryOwner<C>>,
104 requires
105 self.wf(*owner),
106 owner.inv(),
107 returns owner.is_absent(),
108 )]
109 pub(in crate::mm) fn is_none(&self) -> bool {
110 !self.pte.is_present()
111 }
112
113 #[verus_spec(
115 with Tracked(owner): Tracked<EntryOwner<C>>,
116 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
117 Tracked(regions): Tracked<&MetaRegionOwners>,
118 )]
119 pub(in crate::mm) fn is_node(&self) -> bool
120 requires
121 owner.inv(),
122 self.wf(owner),
123 parent_owner.relate_guard(*self.node),
124 parent_owner.inv(),
125 parent_owner.level == owner.parent_level,
126 regions.inv(),
127 parent_owner.metaregion_sound_node(*regions),
128 returns
129 owner.is_node(),
130 {
131 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
132 parent_owner.slot_index,
133 );
134 self.pte.is_present() && !self.pte.is_last(
135 #[verus_spec(with Tracked(parent_meta_perm))]
136 self.node.level(),
137 )
138 }
139
140 #[verus_spec(
142 with Tracked(owner): Tracked<&EntryOwner<C>>,
143 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
144 Tracked(regions): Tracked<&mut MetaRegionOwners>,
145 )]
146 pub(in crate::mm) fn to_ref(&self) -> (res: ChildRef<'rcu, C>)
147 requires
148 self.invariants(*owner, *old(regions)),
149 self.node_matching(*owner, *parent_owner, *self.node),
150 !owner.in_scope,
151 parent_owner.metaregion_sound_node(*old(regions)),
152 ensures
153 res.invariants(*owner, *final(regions)),
154 final(regions).slot_owners =~= old(regions).slot_owners,
155 forall|k: usize|
156 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
157 k,
158 ),
159 forall|k: usize|
160 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
161 == #[trigger] final(regions).slots[k],
162 final(regions).inv(),
163 {
164 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
165 parent_owner.slot_index,
166 );
167 #[verus_spec(with Tracked(parent_meta_perm))]
168 let level = self.node.level();
169
170 let res = unsafe {
174 #[verus_spec(with Tracked(regions), Tracked(owner))]
175 ChildRef::from_pte(&self.pte, level)
176 };
177
178 res
179 }
180
181 #[verus_spec(
198 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
199 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
200 Tracked(regions): Tracked<&MetaRegionOwners>,
201 )]
202 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty)
203 requires
204 old(owner).inv(),
205 old(self).wf(*old(owner)),
206 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
207 op.requires((old(self).pte.prop(),)),
208 old(owner).is_frame(),
209 regions.inv(),
210 regions.slots.contains_key(old(parent_owner).slot_index),
211 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
231 #![auto]
232 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
233 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
234 ensures
235 final(owner).inv(),
236 final(self).wf(*final(owner)),
237 final(self).node_matching(*final(owner), *final(parent_owner), *final(self).node),
238 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
239 final(owner).is_frame(),
240 final(owner).frame.unwrap().mapped_pa == old(owner).frame.unwrap().mapped_pa,
241 final(owner).frame.unwrap().is_tracked == old(owner).frame.unwrap().is_tracked,
242 final(owner).path == old(owner).path,
243 final(owner).parent_level == old(owner).parent_level,
244 final(owner).in_scope == old(owner).in_scope,
245 final(self).idx == old(self).idx,
246 old(self).pte.is_present() ==> op.ensures(
247 (old(owner).frame.unwrap().prop,),
248 final(owner).frame.unwrap().prop,
249 ),
250 {
251 let ghost pte0 = self.pte;
252
253 if !self.pte.is_present() {
254 return;
255 }
256 let prop = self.pte.prop();
257 let new_prop = op(prop);
258
259 proof {
264 self.pte.set_prop_properties(new_prop);
265 }
266 self.pte.set_prop(new_prop);
267
268 unsafe {
274 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
275 self.node.write_pte(self.idx, self.pte)
276 };
277
278 proof {
279 let tracked mut frame_owner = owner.frame.tracked_take();
280 frame_owner.prop = new_prop;
281 owner.frame = Some(frame_owner);
282 }
283 assert(owner.match_pte(self.pte, owner.parent_level));
284 }
285
286 #[verus_spec(
307 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
308 Tracked(owner): Tracked<&mut EntryOwner<C>>,
309 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
310 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
311 )]
312 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> (res: Child<C>)
313 requires
314 old(self).invariants(*old(owner), *old(regions)),
315 new_child.invariants(*old(new_owner), *old(regions)),
316 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
317 old(self).new_owner_compatible(new_child, *old(owner), *old(new_owner), *old(regions)),
318 !old(owner).in_scope,
319 old(parent_owner).metaregion_sound_node(*old(regions)),
320 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
321 frame_to_index(meta_to_frame(node.ptr.addr())),
322 ) > 0,
323 ensures
324 final(self).invariants(*final(new_owner), *final(regions)),
325 res.invariants(*final(owner), *final(regions)),
326 final(self).node_matching(*final(new_owner), *final(parent_owner), *final(self).node),
327 final(self).idx == old(self).idx,
328 *final(owner) == old(owner).from_pte_owner_spec(),
329 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
330 Self::metaregion_sound_neq_preserved(
331 *old(owner),
332 *final(new_owner),
333 *old(regions),
334 *final(regions),
335 ),
336 !final(new_owner).is_node() ==> Self::metaregion_sound_neq_old_preserved(
337 *old(owner),
338 *old(regions),
339 *final(regions),
340 ),
341 (!old(owner).is_node() && !final(new_owner).is_node())
342 ==> Self::metaregion_sound_preserved(*old(regions), *final(regions)),
343 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
344 C,
345 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
346 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
347 final(parent_owner).metaregion_sound_node(*final(regions)),
348 forall|idx: usize|
350 #![trigger final(regions).slot_owners[idx].paths_in_pt]
351 (!final(new_owner).is_node() || final(new_owner).is_absent() || idx
352 != frame_to_index(final(new_owner).meta_slot_paddr().unwrap()))
353 ==> final(regions).slot_owners[idx].paths_in_pt == old(
354 regions,
355 ).slot_owners[idx].paths_in_pt,
356 forall|k: usize|
358 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
359 k,
360 ),
361 forall|idx: usize|
367 #![trigger final(regions).slot_owners[idx].inner_perms.ref_count.value()]
368 final(regions).slot_owners[idx].inner_perms.ref_count.value() == old(
369 regions,
370 ).slot_owners[idx].inner_perms.ref_count.value(),
371 forall|idx: usize|
372 #![trigger final(regions).slot_owners[idx].inner_perms]
373 final(regions).slot_owners[idx].inner_perms == old(
374 regions,
375 ).slot_owners[idx].inner_perms,
376 final(regions).slots == old(regions).slots,
377 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
379 &&& final(regions).slots == old(regions).slots
380 &&& forall|i: usize|
381 #![trigger final(regions).slot_owners[i]]
382 final(regions).slot_owners[i] == old(
383 regions,
384 ).slot_owners[i]
385 &&& final(regions).frame_obligations =~= old(regions).frame_obligations
391 },
392 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: usize|
394 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
395 == #[trigger] final(regions).slots[k],
396 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
397 {
398 let ghost new_idx = frame_to_index(new_owner.meta_slot_paddr().unwrap());
399 let ghost old_idx = frame_to_index(owner.meta_slot_paddr().unwrap());
400
401 #[cfg(feature = "allow_panic")]
402 {
403 let guard_level = self.node.level();
404 match &new_child {
405 Child::PageTable(node) => {
406 assert!(node.level() == guard_level - 1);
407 },
408 Child::Frame(_, level, _) => {
409 assert!(*level == guard_level);
410 },
411 Child::None => {},
412 }
413 }
414
415 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
419 parent_owner.slot_index,
420 );
421 #[verus_spec(with Tracked(parent_meta_perm))]
422 let level = self.node.level();
423
424 let old_child = unsafe {
425 #[verus_spec(with Tracked(regions), Tracked(owner))]
426 Child::from_pte(self.pte, level)
427 };
428
429 let ghost regions_after_from = *regions;
430
431 assert(new_owner.is_node() ==> regions.slots.contains_key(
432 frame_to_index(new_owner.meta_slot_paddr().unwrap()),
433 ));
434
435 if old_child.is_none() && !new_child.is_none() {
436 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
437 parent_owner.slot_index,
438 );
439 #[verus_spec(with Tracked(parent_meta_perm2))]
440 let nr_children = self.node.nr_children_mut();
441 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
442 proof {
443 parent_owner.nr_children_absent_slot_bound(self.idx);
444 }
445 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
446 } else if !old_child.is_none() && new_child.is_none() {
447 let tracked parent_meta_perm3 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
448 parent_owner.slot_index,
449 );
450 #[verus_spec(with Tracked(parent_meta_perm3))]
451 let nr_children = self.node.nr_children_mut();
452 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
453 proof {
454 parent_owner.nr_children_present_slot_bound(self.idx);
455 }
456 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
457 }
458 proof {
459 assert(owner.metaregion_sound(*regions));
460 }
461
462 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
463 let new_pte = new_child.into_pte();
464
465 let ghost regions_after_into = *regions;
466
467 proof {
468 assert(owner.metaregion_sound(*regions));
469 }
470
471 unsafe {
476 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
477 self.node.write_pte(self.idx, new_pte)
478 };
479
480 self.pte = new_pte;
481
482 proof {
483 if new_owner.is_node() {
490 let paddr = new_owner.meta_slot_paddr().unwrap();
491 regions.inv_implies_correct_addr(paddr);
492
493 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
494 new_meta_slot.paths_in_pt = set![new_owner.path];
495 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
496 }
497 owner.in_scope = true;
498 }
499
500 assert(Self::metaregion_sound_neq_preserved(
501 *old(owner),
502 *new_owner,
503 *old(regions),
504 *regions,
505 ));
506
507 proof {
508 if !old(owner).is_node() && !new_owner.is_node() {
511 }
513 }
514
515 proof {
516 if new_owner.is_node() || new_owner.is_frame() {
517 let paddr = new_owner.meta_slot_paddr().unwrap();
518 regions.inv_implies_correct_addr(paddr);
519 }
520 if new_owner.is_frame() && new_owner.parent_level > 1 {
525 assert(new_owner.frame_sub_pages_valid(*regions));
526 }
527 if owner.is_frame() && owner.parent_level > 1 {
528 assert(owner.frame_sub_pages_valid(*regions));
529 }
530 }
531
532 old_child
533 }
534
535 #[verus_spec(res =>
552 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
553 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
554 Tracked(regions): Tracked<&mut MetaRegionOwners>,
555 Tracked(guards): Tracked<&mut Guards<'rcu>>,
556 requires
557 old(self).invariants(old(owner).value, *old(regions)),
558 old(owner).inv(),
559 old(self).node_matching(old(owner).value, *old(parent_owner), *old(self).node),
560 old(owner).level < INC_LEVELS - 1,
561 old(parent_owner).metaregion_sound_node(*old(regions)),
562 ensures
563 final(self).invariants(final(owner).value, *final(regions)),
564 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
565 final(self).idx == old(self).idx,
566 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
567 &&& final(self).node_matching(final(owner).value, *final(parent_owner), *final(self).node)
569 &&& final(owner).inv()
571 &&& !final(owner).value.in_scope
573 },
574 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
575 &&& res is Some
576 &&& final(owner).value.is_node()
577 &&& final(owner).level == old(owner).level
578 &&& final(owner).value.parent_level == old(owner).value.parent_level
579 &&& final(guards).lock_held(final(owner).value.node.unwrap().meta_addr_self())
580 &&& final(owner).value.node.unwrap().relate_guard(res.unwrap())
581 &&& final(owner).value.path == old(owner).value.path
582 &&& final(owner).value.metaregion_sound(*final(regions))
583 &&& OwnerSubtree::implies(
584 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
585 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node.unwrap().meta_addr_self()))
586 &&& Self::metaregion_sound_neq_preserved(old(owner).value, final(owner).value, *old(regions), *final(regions))
587 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
588 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value.meta_slot_paddr().unwrap()))
589 &&& final(owner).tree_predicate_map(final(owner).value.path,
590 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node.unwrap().meta_addr_self()))
591 &&& final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
592 &&& final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
593 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value.path) =~= set![]
594 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
596 #[trigger] final(owner).children[i] is Some && final(owner).children[i].unwrap().value.is_absent()
597 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
604 (#[trigger] final(owner).children[i]).unwrap().value.path
605 == final(owner).value.path.push_tail(i as usize)
606 &&& crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner))
610 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
612 (#[trigger] final(owner).children[i]).unwrap().value.parent_level
613 == final(owner).value.node.unwrap().level
614 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
615 (#[trigger] final(owner).children[i]).unwrap().value.match_pte(
616 final(owner).value.node.unwrap().children_perm.value()[i],
617 final(owner).children[i].unwrap().value.parent_level)
618 &&& forall|i: usize| i != frame_to_index(final(owner).value.meta_slot_paddr().unwrap()) ==>
620 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
621 &&& forall|i: usize| old(regions).slots.contains_key(i)
623 ==> (#[trigger] final(regions).slots.contains_key(i))
624 &&& forall|i: usize| #![trigger final(regions).slots[i]]
625 i != frame_to_index(final(owner).value.meta_slot_paddr().unwrap())
626 && old(regions).slots.contains_key(i)
627 ==> final(regions).slots[i] == old(regions).slots[i]
628 &&& final(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr().unwrap())]
630 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
631 &&& old(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr().unwrap())]
633 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
634 &&& !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
636 final(owner).value.meta_slot_paddr().unwrap())
637 },
638 !old(owner).value.is_absent() ==> {
639 &&& res is None
640 &&& *final(owner) == *old(owner)
641 },
642 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
643 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value.node.unwrap().meta_addr_self() ==> final(guards).unlocked(i),
644 )]
645 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A) -> (res: Option<
646 PageTableGuard<'rcu, C>,
647 >) {
648 let entry_is_present = self.pte.is_present();
649
650 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
651 parent_owner.slot_index,
652 );
653 #[verus_spec(with Tracked(parent_meta_perm))]
654 let level = self.node.level();
655
656 if entry_is_present || level <= 1 {
657 None
658 } else {
659 let tracked old_path = owner.value.get_path();
660
661 proof_decl! {
662 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
663 }
664
665 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
666 let new_page = PageTableNode::<C>::alloc(level - 1);
667
668 proof {
669 let pte = C::E::new_pt_spec(
670 meta_to_frame(new_node_owner.value.node.unwrap().meta_addr_self()),
671 );
672 old(parent_owner).set_children_perm_axiom(self.idx, pte);
673 C::E::new_properties();
674 assert(!pte.is_last_spec(level as PagingLevel));
675 }
676
677 let ghost new_node_slot_idx = new_node_owner.value.node.unwrap().slot_index;
678 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
679 #[verus_spec(with Tracked(new_node_slot_perm))]
680 let paddr = new_page.start_paddr();
681
682 assert(new_node_owner.value.metaregion_sound(*regions));
683
684 proof {
685 assert(regions.frame_obligations.count(
690 frame_to_index(meta_to_frame(new_page.ptr.addr())),
691 ) > 0);
692 }
693
694 #[verus_spec(with Tracked(&mut new_node_owner.value), Tracked(regions))]
695 let new_pte = Child::PageTable(new_page).into_pte();
696 self.pte = new_pte;
697
698 proof {
699 assert(new_node_owner.value.pte_invariants(self.pte, *regions));
700 assert(new_node_owner.value.match_pte(self.pte, new_node_owner.value.parent_level));
701 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
702
703 assert(new_node_owner.value.metaregion_sound(*regions));
704 assert(new_node_owner.value.meta_slot_paddr().unwrap() == paddr);
705 }
706
707 let pt_ref = unsafe {
708 #[verus_spec(with Tracked(regions))]
709 PageTableNodeRef::borrow_paddr(paddr)
710 };
711
712 #[verus_spec(with Tracked(&new_node_owner.value.node.tracked_borrow()), Tracked(guards))]
714 let mut pt_lock_guard = pt_ref.lock(guard);
715
716 proof {
717 parent_owner.nr_children_absent_slot_bound(self.idx);
718 }
719
720 unsafe {
725 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
726 self.node.write_pte(self.idx, self.pte)
727 };
728
729 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
730 parent_owner.slot_index,
731 );
732 #[verus_spec(with Tracked(parent_meta_perm2))]
733 let nr_children = self.node.nr_children_mut();
734 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
735 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
736
737 proof {
738 owner.value = new_node_owner.value;
739 owner.value.parent_level = level as PagingLevel;
740 owner.value.path = old_path;
741 owner.children = new_node_owner.children;
742 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
746 assert(forall|i: int|
748 0 <= i < NR_ENTRIES ==> (#[trigger] owner.children[i]) is Some
749 && owner.children[i].unwrap().value.is_absent());
750
751 let new_paddr = owner.value.meta_slot_paddr().unwrap();
752 assert(old(regions).slots.contains_key(frame_to_index(new_paddr)));
753 regions.inv_implies_correct_addr(new_paddr);
754 let new_idx = frame_to_index(new_paddr);
755 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
756 new_meta_slot.paths_in_pt = set![owner.value.path];
757 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
758 }
759
760 Some(pt_lock_guard)
761 }
762 }
763
764 #[verifier::spinoff_prover]
780 #[verifier::rlimit(80)]
781 #[verus_spec(res =>
782 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
783 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
784 Tracked(regions): Tracked<&mut MetaRegionOwners>,
785 Tracked(guards): Tracked<&mut Guards<'rcu>>
786 requires
787 old(regions).inv(),
788 old(owner).inv(),
789 old(self).wf(old(owner).value),
790 old(parent_owner).relate_guard(*old(self).node),
791 old(parent_owner).inv(),
792 old(parent_owner).level == old(owner).value.parent_level,
793 old(parent_owner).level < NR_LEVELS,
794 old(parent_owner).metaregion_sound_node(*old(regions)),
795 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
801 old(owner).value.metaregion_sound(*old(regions)),
802 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
806 forall |j: usize| #![trigger frame_to_index(
807 (old(owner).value.frame.unwrap().mapped_pa
808 + j * PAGE_SIZE) as usize)]
809 0 < j < page_size(old(parent_owner).level) / PAGE_SIZE ==> {
810 let sub_idx = frame_to_index(
811 (old(owner).value.frame.unwrap().mapped_pa
812 + j * PAGE_SIZE) as usize);
813 &&& old(regions).slots.contains_key(sub_idx)
814 &&& old(regions).slot_owners[sub_idx].usage
815 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==>
816 old(regions).slot_owners[sub_idx].inner_perms.ref_count.value()
817 != REF_COUNT_UNUSED
818 },
819 ensures
820 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
821 &&& res is Some
822 &&& final(owner).value.is_node()
823 &&& final(owner).level == old(owner).level
824 &&& final(parent_owner).relate_guard(*final(self).node)
825 &&& final(owner).value.node.unwrap().relate_guard(res.unwrap())
826 &&& final(owner).value.node.unwrap().meta_addr_self() == res.unwrap().inner.inner@.ptr.addr()
827 &&& final(guards).lock_held(res.unwrap().inner.inner@.ptr.addr())
828 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
830 (#[trigger] final(owner).children[j]).unwrap().value.is_frame()
831 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
832 (#[trigger] final(owner).children[j]).unwrap().value.frame.unwrap().prop
833 == old(owner).value.frame.unwrap().prop
834 &&& final(owner).value.path == old(owner).value.path
835 &&& final(owner).value.metaregion_sound(*final(regions))
836 &&& OwnerSubtree::implies(
837 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
838 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
839 &&& OwnerSubtree::implies(
840 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
841 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
842 &&& final(owner).tree_predicate_map(final(owner).value.path,
843 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
844 &&& final(owner).tree_predicate_map(final(owner).value.path,
845 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
846 },
847 !old(owner).value.is_frame() || old(parent_owner).level <= 1 ==> {
848 &&& res is None
849 &&& *final(owner) == *old(owner)
850 },
851 final(owner).inv(),
852 final(owner).value.parent_level == old(owner).value.parent_level,
853 final(self).idx == old(self).idx,
854 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> !final(owner).value.in_scope,
855 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
856 final(self).node_matching(final(owner).value, *final(parent_owner), *final(self).node),
857 final(regions).inv(),
858 final(parent_owner).inv(),
859 final(parent_owner).level == old(parent_owner).level,
860 final(self).node.inner.inner@.ptr.addr() == old(self).node.inner.inner@.ptr.addr(),
861 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
862 forall |i: usize| old(guards).unlocked(i) ==> final(guards).unlocked(i),
863 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
865 &&& forall|i: usize| i != frame_to_index(meta_to_frame(final(owner).value.node.unwrap().meta_addr_self())) ==>
866 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
867 &&& forall|i: usize| old(regions).slots.contains_key(i)
869 ==> (#[trigger] final(regions).slots.contains_key(i))
870 &&& final(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value.node.unwrap().meta_addr_self()))]
872 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
873 &&& old(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value.node.unwrap().meta_addr_self()))]
875 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
876 },
877 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
882 forall|j: int| 0 <= j < NR_ENTRIES && j != old(self).idx as int ==>
883 #[trigger] final(parent_owner).children_perm.value()[j]
884 == old(parent_owner).children_perm.value()[j],
885 )]
886 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A) -> (res:
887 Option<PageTableGuard<'rcu, C>>) {
888 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
889 parent_owner.slot_index,
890 );
891 #[verus_spec(with Tracked(parent_meta_perm))]
892 let level = self.node.level();
893
894 if !(self.pte.is_last(level) && level > 1) {
895 return None;
896 }
897 let pa = self.pte.paddr();
898 let prop = self.pte.prop();
899
900 proof {
901 EntryOwner::last_pte_implies_frame_match(owner.value, self.pte, level);
902 }
903
904 proof_decl!{
905 let tracked mut new_owner: OwnerSubtree<C>;
906 }
907
908 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
911 let new_page = PageTableNode::<C>::alloc(level - 1);
912
913 let ghost new_owner_slot_idx = new_owner.value.node.unwrap().slot_index;
914 let tracked new_owner_slot_perm = regions.slots.tracked_borrow(new_owner_slot_idx);
915 #[verus_spec(with Tracked(new_owner_slot_perm))]
916 let paddr = new_page.start_paddr();
917
918 proof {
919 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
920
921 assert(new_owner.value.metaregion_sound(*regions));
922 assert(new_owner.value.meta_slot_paddr().unwrap() == paddr);
923 }
924
925 let pt_ref = unsafe {
926 #[verus_spec(with Tracked(regions))]
927 PageTableNodeRef::borrow_paddr(paddr)
928 };
929
930 #[verus_spec(with Tracked(&new_owner.value.node.tracked_borrow()), Tracked(guards))]
932 let mut pt_lock_guard = pt_ref.lock(guard);
933
934 let ghost children_perm = new_owner.value.node.unwrap().children_perm;
935 let ghost new_owner_path = new_owner.value.path;
936 let ghost new_owner_meta_addr = new_owner.value.node.unwrap().meta_addr_self();
937
938 for i in 0..nr_subpage_per_huge::<C>()
939 invariant
940 1 < level < NR_LEVELS,
941 owner.inv(),
942 owner.value.is_frame(),
943 owner.value.parent_level == level,
944 owner.value.frame.unwrap().mapped_pa == pa,
945 owner.value.frame.unwrap().prop == prop,
946 pa == old(owner).value.frame.unwrap().mapped_pa,
947 level == old(parent_owner).level,
948 pa % page_size(level) == 0,
949 pa + page_size(level) <= MAX_PADDR,
950 regions.inv(),
951 regions.frame_obligations.count(frame_to_index(meta_to_frame(new_owner_meta_addr)))
956 > 0,
957 parent_owner.inv(),
958 new_owner.value.is_node(),
959 new_owner.inv(),
960 new_owner.value.path == new_owner_path,
961 new_owner.value.node.unwrap().meta_addr_self() == new_owner_meta_addr,
962 new_owner.value.node.unwrap().relate_guard(pt_lock_guard),
963 guards.lock_held(new_owner_meta_addr),
964 new_owner.value.node.unwrap().level == (level - 1) as PagingLevel,
965 forall|j: int|
966 #![auto]
967 0 <= j < NR_ENTRIES ==> {
968 &&& new_owner.children[j] is Some
969 &&& new_owner.children[j].unwrap().value.match_pte(
970 new_owner.value.node.unwrap().children_perm.value()[j],
971 new_owner.value.node.unwrap().level,
972 )
973 &&& new_owner.children[j].unwrap().value.parent_level
974 == new_owner.value.node.unwrap().level
975 &&& new_owner.children[j].unwrap().value.inv()
976 &&& new_owner.children[j].unwrap().value.path == new_owner_path.push_tail(
977 j as usize,
978 )
979 },
980 forall|j: int|
981 #![auto]
982 i <= j < NR_ENTRIES ==> {
983 &&& new_owner.children[j].unwrap().value.is_absent()
984 &&& !new_owner.children[j].unwrap().value.in_scope
985 &&& new_owner.value.node.unwrap().children_perm.value()[j]
986 == C::E::new_absent_spec()
987 },
988 forall|j: int|
990 #![auto]
991 0 <= j < i ==> { new_owner.children[j].unwrap().value.is_frame() },
992 forall|j: usize|
996 #![trigger frame_to_index(
997 (pa + j * PAGE_SIZE) as usize)]
998 0 < j < page_size(level) / PAGE_SIZE ==> {
999 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1000 &&& regions.slots.contains_key(sub_idx)
1001 &&& regions.slot_owners[sub_idx].usage
1002 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
1003 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1004 != REF_COUNT_UNUSED
1005 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1006 }
1007 },
1008 regions.slots.contains_key(frame_to_index(pa)),
1010 regions.slot_owners[frame_to_index(pa)].usage
1011 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
1012 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
1013 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1014 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value() > 0
1015 },
1016 new_page.ptr.addr() == new_owner_meta_addr,
1017 new_owner.value.node.unwrap().metaregion_sound_node(*regions),
1018 {
1019 proof {
1020 C::axiom_nr_subpage_per_huge_eq_nr_entries();
1021 }
1022 assert(i < NR_ENTRIES);
1023
1024 proof {
1025 let ghost the_node = new_owner.value.node.unwrap();
1027 assert(0 <= i < NR_ENTRIES);
1028 assert(new_owner.children[i as int].unwrap().value.match_pte(
1029 the_node.children_perm.value()[i as int],
1030 new_owner.children[i as int].unwrap().value.parent_level,
1031 ));
1032 assert(the_node.relate_guard(pt_lock_guard));
1033 assert(new_owner.children[i as int].unwrap().value.parent_level == the_node.level);
1034 assert(!new_owner.children[i as int].unwrap().value.in_scope);
1035
1036 OwnerSubtree::child_some_properties(new_owner, i as usize);
1037 }
1038
1039 let tracked mut new_owner_node = new_owner.value.node.tracked_take();
1040
1041 proof {
1042 let ghost old_children_perm = new_owner_node.children_perm;
1043 }
1044
1045 proof {
1046 EntryOwner::huge_frame_split_child_at(owner.value, *regions, i as usize);
1047 }
1048
1049 let small_pa = pa + i * page_size(level - 1);
1050
1051 assert(small_pa % PAGE_SIZE == 0);
1052
1053 let tracked child_owner = EntryOwner::tracked_new_frame(
1054 small_pa,
1055 new_owner.value.path.push_tail(i as usize),
1056 (level - 1) as PagingLevel,
1057 prop,
1058 owner.value.frame.unwrap().is_tracked,
1060 );
1061
1062 proof {
1063 assert(regions.slots.contains_key(new_owner_node.slot_index));
1064 }
1065 #[verus_spec(with Tracked(&new_owner_node), Tracked(&new_owner.children.tracked_borrow(i as int).tracked_borrow().value), Tracked(&*regions))]
1066 let mut entry = pt_lock_guard.entry(i);
1067
1068 proof {
1069 assert(entry.idx == i as usize);
1070 let ghost child_before_remove = new_owner.child(i as usize).unwrap();
1071 assert(child_before_remove.inv());
1072 }
1073 let tracked mut new_owner_child = new_owner.children.tracked_remove(
1074 i as int,
1075 ).tracked_unwrap();
1076
1077 proof {
1078 assert(new_owner_child.value.match_pte(
1079 new_owner_node.children_perm.value()[i as int],
1080 new_owner_child.value.parent_level,
1081 ));
1082
1083 let idx = frame_to_index(small_pa);
1084 assert(idx == frame_to_index(
1085 (pa + i * page_size((level - 1) as PagingLevel)) as usize,
1086 ));
1087 if i != 0 {
1088 let ghost big_j =
1089 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1090 pa, level, i);
1091 assert(small_pa == (pa + big_j * PAGE_SIZE) as usize);
1092 }
1093 assert(entry.node_matching(new_owner_child.value, new_owner_node, *entry.node)) by {
1094 let pte = new_owner_node.children_perm.value()[i as int];
1095 assert(pte == C::E::new_absent_spec());
1096 crate::specs::arch::PageTableEntry::absent_pte_paddr_ok();
1097 EntryOwner::absent_match_pte(
1098 new_owner_child.value,
1099 pte,
1100 new_owner_child.value.parent_level,
1101 );
1102 };
1103
1104 if level - 1 > 1 {
1105 let nr_subpages = page_size((level - 1) as PagingLevel) / PAGE_SIZE;
1106 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1107 (level - 1) as PagingLevel);
1108 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1109 level);
1110 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
1111 level);
1112 assert forall|j_prime: usize|
1113 #![trigger frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize)]
1114 0 < j_prime < nr_subpages implies {
1115 let sub_idx = frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize);
1116 &&& regions.slots.contains_key(sub_idx)
1117 &&& regions.slot_owners[sub_idx].usage
1118 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
1119 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1120 != REF_COUNT_UNUSED
1121 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1122 }
1123 } by {
1124 let sub_pages_per_subframe = page_size((level - 1) as PagingLevel)
1125 / PAGE_SIZE;
1126 let big_j_int: int = i as int * sub_pages_per_subframe as int
1127 + j_prime as int;
1128 vstd::arithmetic::mul::lemma_mul_nonnegative(
1129 i as int,
1130 sub_pages_per_subframe as int,
1131 );
1132 vstd::arithmetic::mul::lemma_mul_inequality(
1133 (i + 1) as int,
1134 NR_ENTRIES as int,
1135 sub_pages_per_subframe as int,
1136 );
1137 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1138 sub_pages_per_subframe as int,
1139 i as int,
1140 1int,
1141 );
1142 vstd::arithmetic::mul::lemma_mul_is_associative(
1143 NR_ENTRIES as int,
1144 sub_pages_per_subframe as int,
1145 PAGE_SIZE as int,
1146 );
1147 vstd::arithmetic::div_mod::lemma_div_by_multiple(
1148 NR_ENTRIES as int * sub_pages_per_subframe as int,
1149 PAGE_SIZE as int,
1150 );
1151 let big_j: usize = big_j_int as usize;
1152 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1153 PAGE_SIZE as int,
1154 i as int * sub_pages_per_subframe as int,
1155 j_prime as int,
1156 );
1157 vstd::arithmetic::mul::lemma_mul_is_associative(
1158 i as int,
1159 sub_pages_per_subframe as int,
1160 PAGE_SIZE as int,
1161 );
1162 assert((small_pa + j_prime * PAGE_SIZE) as usize == (pa + big_j
1163 * PAGE_SIZE) as usize);
1164 }
1165 assert(child_owner.frame_sub_pages_valid(*regions));
1166 }
1167 let small_idx = frame_to_index(small_pa);
1168
1169 if i == 0 {
1174 assert(i as int * page_size((level - 1) as PagingLevel) as int == 0) by {
1176 vstd::arithmetic::mul::lemma_mul_by_zero_is_zero(
1177 page_size((level - 1) as PagingLevel) as int,
1178 );
1179 }
1180 assert(small_pa == pa);
1181 } else {
1182 let ghost big_j =
1183 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1184 pa, level, i);
1185 assert(small_pa == (pa + big_j * PAGE_SIZE) as usize);
1186 assert(regions.slots.contains_key(
1188 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1189 ));
1190 }
1191 assert(regions.slots.contains_key(small_idx));
1192
1193 let ghost orig_inner_perms = regions.slot_owners[small_idx].inner_perms;
1196
1197 regions.inv_implies_correct_addr(small_pa);
1198 let tracked mut small_slot = regions.slot_owners.tracked_remove(small_idx);
1199 small_slot.paths_in_pt = small_slot.paths_in_pt.insert(child_owner.path);
1200 regions.slot_owners.tracked_insert(small_idx, small_slot);
1201
1202 assert(regions.slot_owners[small_idx].inner_perms == orig_inner_perms);
1204 assert(regions.slots.contains_key(small_idx));
1205
1206 if (level - 1) > 1 {
1207 assert(child_owner.frame_sub_pages_valid(*regions));
1208 }
1209 let ghost target_idx = frame_to_index(small_pa);
1210 assert(target_idx == small_idx);
1211 if i != 0 {
1212 let ghost big_j =
1213 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1214 pa, level, i);
1215 assert(small_pa == (pa + big_j * PAGE_SIZE) as usize);
1216 assert(target_idx == frame_to_index((pa + big_j * PAGE_SIZE) as usize));
1217 assert(regions.slots.contains_key(target_idx));
1218 assert(regions.slot_owners[target_idx].usage
1219 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
1220 &&& regions.slot_owners[target_idx].inner_perms.ref_count.value()
1221 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
1222 &&& regions.slot_owners[target_idx].inner_perms.ref_count.value() > 0
1223 });
1224 } else {
1225 assert(0 * page_size((level - 1) as PagingLevel) == 0) by (nonlinear_arith);
1226 assert(small_pa as int == pa as int);
1227 assert(target_idx == frame_to_index(pa));
1228 }
1229 assert(child_owner.metaregion_sound(*regions));
1230 assert(Child::<C>::Frame(small_pa, (level - 1) as PagingLevel, prop).invariants(
1231 child_owner,
1232 *regions,
1233 ));
1234 }
1235
1236 proof {
1237 assert(new_owner_node.metaregion_sound_node(*regions));
1238 }
1239 #[verus_spec(with Tracked(regions),
1240 Tracked(&mut new_owner_child.value),
1241 Tracked(&mut child_owner),
1242 Tracked(&mut new_owner_node))]
1243 let old = entry.replace(Child::Frame(small_pa, level - 1, prop));
1244
1245 proof {
1246 new_owner.value.node = Some(new_owner_node);
1247 new_owner_child.value.in_scope = false;
1248 child_owner.in_scope = false;
1249 OwnerSubtree::set_value_property(new_owner_child, child_owner);
1250 new_owner_child.value = child_owner;
1251 new_owner.children.tracked_insert(i as int, Some(new_owner_child));
1252
1253 TreePath::push_tail_property_len(new_owner_path, i as usize);
1254 OwnerSubtree::insert_preserves_inv(new_owner, i as usize, new_owner_child);
1255 }
1256 }
1257
1258 proof {
1259 assert(new_page.ptr.addr() == new_owner_meta_addr);
1264 assert(regions.frame_obligations.count(
1265 frame_to_index(meta_to_frame(new_page.ptr.addr())),
1266 ) > 0);
1267 }
1268 self.pte = (#[verus_spec(with Tracked(&mut new_owner.value), Tracked(regions))]
1269 Child::PageTable(new_page).into_pte());
1270
1271 proof {
1272 new_owner.level = owner.level;
1273 *owner = new_owner;
1274 }
1275
1276 let tracked mut node_owner = owner.value.node.tracked_take();
1277
1278 unsafe {
1283 #[verus_spec(with Tracked(&mut node_owner), Tracked(&*regions))]
1284 self.node.write_pte(self.idx, self.pte)
1285 };
1286
1287 proof {
1288 owner.value.node = Some(node_owner);
1289 }
1290
1291 Some(pt_lock_guard)
1292 }
1293
1294 #[verus_spec(
1310 with Tracked(owner): Tracked<&EntryOwner<C>>,
1311 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1312 Tracked(regions): Tracked<&MetaRegionOwners>,
1313 )]
1314 pub(in crate::mm) unsafe fn new_at(guard: &'a mut PageTableGuard<'rcu, C>, idx: usize) -> (res:
1315 Self)
1316 requires
1317 owner.inv(),
1318 !owner.in_scope,
1319 parent_owner.inv(),
1320 parent_owner.relate_guard(*guard),
1321 idx < NR_ENTRIES,
1322 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1323 regions.inv(),
1324 regions.slots.contains_key(parent_owner.slot_index),
1325 ensures
1326 res.wf(*owner),
1327 res.idx == idx,
1328 parent_owner.relate_guard(*res.node),
1329 *res.node == *old(guard),
1332 *final(guard) == *old(guard),
1335 {
1336 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1340 let pte = guard.read_pte(idx);
1341 Self::new(pte, idx, guard)
1342 }
1343}
1344
1345}