1use vstd::prelude::*;
4use vstd_extra::{ghost_tree::*, ownership::*};
5
6use crate::specs::{
7 arch::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE},
8 mm::{
9 frame::{
10 mapping::{frame_to_index, group_page_meta, 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::{
22 Frame, FrameRef,
23 meta::{REF_COUNT_MAX, REF_COUNT_UNUSED},
24};
25use crate::mm::page_table::*;
26use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
27use crate::{
28 mm::{nr_subpage_per_huge, nr_subpage_per_huge_spec, page_prop::PageProperty},
29 };
32use core::marker::PhantomData;
33use core::ops::Deref;
34
35verus! {
36
37broadcast use group_ghost_tree_lemmas;
38
39pub type PageTableNodeRef<'a, C> = FrameRef<'a, PageTablePageMeta<C>>;
41
42pub struct PageTableGuard<'rcu, C: PageTableConfig> {
44 pub inner: PageTableNodeRef<'rcu, C>,
45}
46
47impl<'rcu, C: PageTableConfig> Deref for PageTableGuard<'rcu, C> {
48 type Target = PageTableNodeRef<'rcu, C>;
49
50 #[verus_spec(ensures returns self.inner)]
51 fn deref(&self) -> &Self::Target {
52 &self.inner
53 }
54}
55
56pub struct Entry<'a, 'rcu, C: PageTableConfig> {
57 pub pte: C::E,
76 pub idx: usize,
78 pub node: &'a mut PageTableGuard<'rcu, C>,
80}
81
82#[verus_verify]
83impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
84 pub open spec fn new_spec(
85 pte: C::E,
86 idx: usize,
87 node: &'a mut PageTableGuard<'rcu, C>,
88 ) -> Self {
89 Self { pte, idx, node }
90 }
91
92 #[verus_spec(res =>
93 ensures
94 res.pte == pte,
95 res.idx == idx,
96 *res.node == *old(node),
97 *final(node) == *final(res.node),
98 )]
99 pub fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> Self {
100 Self { pte, idx, node }
101 }
102}
103
104#[verus_verify]
105impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
106 #[verus_spec(r =>
108 with Tracked(owner): Tracked<&EntryOwner<C>>,
109 requires
110 self.wf(*owner),
111 owner.inv(),
112 returns owner.is_absent(),
113 )]
114 pub(in crate::mm) fn is_none(&self) -> bool {
115 !self.pte.is_present()
116 }
117
118 #[verus_spec(
120 with Tracked(owner): Tracked<EntryOwner<C>>,
121 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
122 requires
123 owner.inv(),
124 self.wf(owner),
125 parent_owner.relate_guard(*self.node),
126 parent_owner.inv(),
127 parent_owner.level() == owner.parent_level,
128 returns
129 owner.is_node(),
130 )]
131 pub(in crate::mm) fn is_node(&self) -> bool {
132 self.pte.is_present() && !self.pte.is_last(
133 #[verus_spec(with Tracked(&*parent_owner))]
134 self.node.level(),
135 )
136 }
137
138 #[verus_spec(res =>
140 with Tracked(owner): Tracked<&EntryOwner<C>>,
141 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
142 Tracked(regions): Tracked<&mut MetaRegionOwners>,
143 requires
144 self.invariants(*owner, *old(regions)),
145 self.node_matching(*owner, *parent_owner, *self.node),
146 parent_owner.metaregion_sound_node(*old(regions)),
147 ensures
148 res.invariants(*owner, *final(regions)),
149 final(regions).slot_owners == old(regions).slot_owners,
150 forall|k: int|
151 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
152 k,
153 ),
154 forall|k: int|
155 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
156 == #[trigger] final(regions).slots[k],
157 final(regions).inv(),
158 )]
159 pub(in crate::mm) fn to_ref(&self) -> ChildRef<'rcu, C> {
160 #[verus_spec(with Tracked(&*parent_owner))]
161 let level = self.node.level();
162
163 let res = unsafe {
167 #[verus_spec(with Tracked(regions), Tracked(owner))]
168 ChildRef::from_pte(&self.pte, level)
169 };
170
171 res
172 }
173
174 #[verus_spec(
191 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
192 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
193 Tracked(regions): Tracked<&MetaRegionOwners>,
194 requires
195 old(owner).inv(),
196 old(self).wf(*old(owner)),
197 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
198 op.requires((old(self).pte.prop(),)),
199 old(owner).is_frame(),
200 regions.inv(),
201 regions.slots.contains_key(old(parent_owner).slot_index),
202 old(parent_owner).metaregion_sound_node(*regions),
203 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty,
209 perm: Tracked<Option<C::Perm>>|
210 #![auto]
211 op.ensures((p_in,), p_out) ==> (
212 C::item_into_raw(C::item_from_raw(pa, level, p_out, perm)).3@
213 is Some
214 ) == (perm@ is Some),
215 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
216 #![auto]
217 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
218 ==> C::E::new_page_req(pa, level, p_out),
219 ensures
220 final(owner).inv(),
221 final(self).wf(*final(owner)),
222 final(self).node_matching(*final(owner), *final(parent_owner), *final(self).node),
223 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
224 final(owner).is_frame(),
225 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
226 final(owner).frame_permission() == old(owner).frame_permission(),
227 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
228 final(owner).path == old(owner).path,
229 final(owner).parent_level == old(owner).parent_level,
230 final(self).idx == old(self).idx,
231 *final(self).node == *old(self).node,
232 old(self).pte.is_present() ==> op.ensures(
233 (old(owner).frame().prop,),
234 final(owner).frame().prop,
235 ),
236 crate::specs::mm::page_table::node::owners::count_present(
241 final(parent_owner).children_perm.value(),
242 ) == crate::specs::mm::page_table::node::owners::count_present(
243 old(parent_owner).children_perm.value(),
244 ),
245 final(parent_owner).meta_own.nr_children.value() == old(
246 parent_owner,
247 ).meta_own.nr_children.value(),
248 )]
249 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty) {
250 #[verus_spec(with Tracked(owner), Tracked(parent_owner), Tracked(regions))]
251 let pte = self.node.protect_child(self.idx, op);
252 self.pte = pte;
253 }
254
255 #[verus_spec(res =>
276 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
277 Tracked(owner): Tracked<&mut EntryOwner<C>>,
278 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
279 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
280 requires
281 old(self).invariants(*old(owner), *old(regions)),
282 new_child.invariants(*old(new_owner), *old(regions)),
283 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
284 old(self).new_owner_compatible(new_child, *old(owner), *old(new_owner), *old(regions)),
285 old(parent_owner).metaregion_sound_node(*old(regions)),
286 ensures
287 final(self).invariants(*final(new_owner), *final(regions)),
288 res.invariants(*final(owner), *final(regions)),
289 final(self).node_matching(*final(new_owner), *final(parent_owner), *final(self).node),
290 final(self).idx == old(self).idx,
291 *final(self).node == *old(self).node,
292 *final(owner) == old(owner).from_pte_owner_spec(),
293 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
294 Self::metaregion_sound_neq_preserved(
295 *old(owner),
296 *final(new_owner),
297 *old(regions),
298 *final(regions),
299 ),
300 !final(new_owner).is_node() ==> Self::metaregion_sound_neq_old_preserved(
301 *old(owner),
302 *old(regions),
303 *final(regions),
304 ),
305 (!old(owner).is_node() && !final(new_owner).is_node())
306 ==> Self::metaregion_sound_preserved(*old(regions), *final(regions)),
307 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
308 C,
309 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
310 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
311 final(parent_owner).metaregion_sound_node(*final(regions)),
312 forall|idx: int|
313 #![trigger final(regions).slot_owners[idx].paths_in_pt]
314 (!final(new_owner).is_node() || final(new_owner).is_absent() || idx
315 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
316 ==> final(regions).slot_owners[idx].paths_in_pt == old(
317 regions,
318 ).slot_owners[idx].paths_in_pt,
319 forall|k: int|
320 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
321 k,
322 ),
323 forall|idx: int|
324 #![trigger final(regions).slot_owners[idx].ref_count()]
325 final(regions).ref_count(idx) == old(
326 regions,
327 ).ref_count(idx),
328 forall|idx: int|
329 #![trigger final(regions).slot_owners[idx].ref_count_perm]
330 final(regions).slot_owners[idx].same_permissions(
331 old(regions).slot_owners[idx],
332 ),
333 final(regions).slots == old(regions).slots,
334 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
336 &&& final(regions).slots == old(regions).slots
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 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
345 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
346 == #[trigger] final(regions).slots[k],
347 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
348 )]
349 #[verifier::spinoff_prover]
350 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> Child<C> {
351 let ghost cp0 = parent_owner.children_perm.value();
352 let ghost initial_regions = *regions;
353 let ghost initial_owner = *owner;
354 let ghost initial_new_owner = *new_owner;
355
356 #[cfg(feature = "allow_panic")]
357 {
358 let guard_level = self.node.level();
359 match &new_child {
360 Child::PageTable(node) => {
361 assert!(node.level() == guard_level - 1);
362 },
363 Child::Frame(_, level, _) => {
364 assert!(*level == guard_level);
365 },
366 Child::None => {},
367 }
368 }
369
370 #[verus_spec(with Tracked(&*parent_owner))]
374 let level = self.node.level();
375
376 let old_child = unsafe {
377 #[verus_spec(with Tracked(regions), Tracked(owner))]
378 Child::from_pte(self.pte, level)
379 };
380
381 if old_child.is_none() && !new_child.is_none() {
382 #[verus_spec(with
383 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
384 &parent_owner.frame_permission,
385 )),
386 Ghost(parent_owner.meta_own.nr_children.id())
387 )]
388 let nr_children = self.node.nr_children_mut();
389 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
390 proof {
391 parent_owner.nr_children_absent_slot_bound(self.idx);
392 }
393 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
394 } else if !old_child.is_none() && new_child.is_none() {
395 #[verus_spec(with
396 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
397 &parent_owner.frame_permission,
398 )),
399 Ghost(parent_owner.meta_own.nr_children.id())
400 )]
401 let nr_children = self.node.nr_children_mut();
402 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
403 proof {
404 parent_owner.nr_children_present_slot_bound(self.idx);
405 }
406 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
407 }
408 #[verus_spec(with Tracked(new_owner))]
409 let new_pte = new_child.into_pte();
410
411 unsafe {
416 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
417 self.node.write_pte(self.idx, new_pte)
418 };
419
420 self.pte = new_pte;
421
422 proof {
423 if new_owner.is_node() {
430 let paddr = new_owner.meta_slot_paddr().unwrap();
431 regions.lemma_contains_valid_frame_paddr(paddr);
432
433 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
434 new_meta_slot.paths_in_pt = set![new_owner.path];
435 }
436 }
437
438 proof {
439 if new_owner.is_node() || new_owner.is_frame() {
440 let paddr = new_owner.meta_slot_paddr().unwrap();
441 regions.lemma_contains_valid_frame_paddr(paddr);
442 }
443 if owner.is_frame() {
444 let paddr = owner.frame().mapped_pa;
445 let slot = frame_to_index(paddr);
446 C::lemma_perm_well_formed_with_region_preserved(
447 paddr,
448 Tracked(owner.frame_permission()),
449 initial_regions,
450 *regions,
451 );
452 }
453 if new_owner.is_frame() {
454 let paddr = new_owner.frame().mapped_pa;
455 let slot = frame_to_index(paddr);
456 assert(initial_regions.slots[slot] == regions.slots[slot]);
457 assert(initial_regions.slot_owners[slot].metadata_perm.id()
458 == regions.slot_owners[slot].metadata_perm.id());
459 C::lemma_perm_well_formed_with_region_preserved(
460 paddr,
461 Tracked(new_owner.frame_permission()),
462 initial_regions,
463 *regions,
464 );
465 }
466 assert(Self::metaregion_sound_neq_preserved(
467 initial_owner,
468 *new_owner,
469 initial_regions,
470 *regions,
471 )) by {
472 let f = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
473 entry.meta_slot_paddr_neq(initial_owner) && entry.meta_slot_paddr_neq(
474 *new_owner,
475 ) && entry.metaregion_sound(initial_regions);
476 let g = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
477 entry.metaregion_sound(*regions);
478 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
479 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
480 if entry.is_frame() {
481 let paddr = entry.frame().mapped_pa;
482 C::lemma_perm_well_formed_with_region_preserved(
483 paddr,
484 Tracked(entry.frame_permission()),
485 initial_regions,
486 *regions,
487 );
488 }
489 };
490 };
491 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
492 cp0,
493 NR_ENTRIES as int,
494 self.idx as int,
495 new_pte,
496 );
497 }
498
499 old_child
500 }
501
502 #[verus_spec(res =>
519 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
520 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
521 Tracked(regions): Tracked<&mut MetaRegionOwners>,
522 Tracked(guards): Tracked<&mut Guards>,
523 requires
524 old(self).invariants(old(owner).value(), *old(regions)),
525 old(owner).inv(),
526 old(self).node_matching(old(owner).value(), *old(parent_owner), *old(self).node),
527 old(owner).level() < INC_LEVELS - 1,
528 old(owner).level() + old(parent_owner).level() == INC_LEVELS,
533 old(parent_owner).metaregion_sound_node(*old(regions)),
534 ensures
535 final(self).invariants(final(owner).value(), *final(regions)),
536 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
537 final(self).idx == old(self).idx,
538 final(parent_owner).count_consistent(),
539 *final(self).node == *old(self).node,
540 old(owner).value().is_absent() && old(parent_owner).level() > 1 ==> {
541 &&& final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node)
542 &&& final(owner).inv()
543 },
544 old(owner).value().is_absent() && old(parent_owner).level() > 1 ==> {
545 &&& res is Some
546 &&& final(owner).value().is_node()
547 &&& final(owner).level() == old(owner).level()
548 &&& final(owner).value().parent_level == old(owner).value().parent_level
549 &&& final(guards).lock_held(final(owner).value().node().slot_vaddr())
550 &&& final(owner).value().node().relate_guard(res->0)
551 &&& final(owner).value().path == old(owner).value().path
552 &&& final(owner).value().metaregion_sound(*final(regions))
553 &&& OwnerSubtree::implies(
554 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
555 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr()))
556 &&& Self::metaregion_sound_neq_preserved(old(owner).value(), final(owner).value(), *old(regions), *final(regions))
557 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
558 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0))
559 &&& final(owner).subtree_satisfies(final(owner).value().path,
560 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr()))
561 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
562 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
563 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![]
564 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
566 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent()
567 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
574 (#[trigger] final(owner).children()[i])->0.value().path
575 == final(owner).value().path.push_tail(i)
576 &&& crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner))
580 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
582 (#[trigger] final(owner).child(i)).value().parent_level
583 == final(owner).value().node().level()
584 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
585 (#[trigger] final(owner).child(i)).value().match_pte(
586 final(owner).value().node().children_perm.value()[i],
587 final(owner).child(i).value().parent_level)
588 &&& forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
590 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
591 &&& forall|i: int| old(regions).slots.contains_key(i)
593 ==> (#[trigger] final(regions).slots.contains_key(i))
594 &&& forall|i: int| #![trigger final(regions).slots[i]]
595 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
596 && old(regions).slots.contains_key(i)
597 ==> final(regions).slots[i] == old(regions).slots[i]
598 &&& final(regions).slot_owner(final(owner).value().meta_slot_paddr()->0)
600 .ref_count() != REF_COUNT_UNUSED
601 &&& old(regions).slot_owner(final(owner).value().meta_slot_paddr().unwrap())
603 .ref_count() == REF_COUNT_UNUSED
604 &&& !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
606 final(owner).value().meta_slot_paddr().unwrap())
607 },
608 !old(owner).value().is_absent() ==> {
609 &&& res is None
610 &&& *final(owner) == *old(owner)
611 },
612 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
613 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().slot_vaddr() ==> final(guards).unlocked(i),
614 )]
615 #[verifier::spinoff_prover]
616 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
617 PageTableGuard<'rcu, C>,
618 > {
619 let entry_is_present = self.pte.is_present();
620 let ghost cp0 = parent_owner.children_perm.value();
622
623 #[verus_spec(with Tracked(&*parent_owner))]
624 let level = self.node.level();
625
626 if entry_is_present || level <= 1 {
627 None
628 } else {
629 let ghost old_path = owner.value().path;
630 let ghost old_owner_val = owner.value();
631
632 proof {
633 parent_owner.nr_children_absent_slot_bound(self.idx);
634 }
635
636 proof_decl! {
637 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
638 }
639
640 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
641 let new_page = PageTableNode::<C>::alloc(level - 1);
642 let ghost fresh_children = new_node_owner.children();
643 proof {
644 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
645 #[trigger] fresh_children[i]) is Some by {
646 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
647 new_node_owner,
648 (level - 1) as PagingLevel,
649 ));
650 assert(new_node_owner.has_child(i));
651 };
652 }
653
654 proof {
655 let pte = C::E::new_pt_spec(
656 meta_to_frame(new_node_owner.value().node().slot_vaddr()),
657 );
658 C::E::lemma_page_table_entry_properties();
659 }
660
661 let paddr = new_page.start_paddr();
662
663 let new_pte = {
664 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
665 #[verus_spec(with Tracked(new_node_value))]
666 Child::PageTable(new_page).into_pte()
667 };
668 self.pte = new_pte;
669
670 let tracked new_node_value = new_node_owner.tracked_borrow_value();
671 let tracked new_node = new_node_value.tracked_borrow_node();
672 let tracked slot_perm = *regions.slots.tracked_borrow(new_node.slot_index);
673 let pt_ref = unsafe {
674 #[verus_spec(with Tracked(slot_perm), Tracked(&new_node.frame_permission))]
675 PageTableNodeRef::borrow_paddr(paddr)
676 };
677
678 let mut pt_lock_guard = {
680 let tracked new_node_value = new_node_owner.tracked_borrow_value();
681 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
682 pt_ref.lock(guard)
683 };
684
685 unsafe {
690 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
691 self.node.write_pte(self.idx, self.pte)
692 };
693
694 #[verus_spec(with
695 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
696 &parent_owner.frame_permission,
697 )),
698 Ghost(parent_owner.meta_own.nr_children.id())
699 )]
700 let nr_children = self.node.nr_children_mut();
701 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
702 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
703
704 proof {
705 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
712 new_node_value.parent_level = level as PagingLevel;
713 new_node_value.path = old_path;
714 *owner = new_node_owner;
715 assert(owner.children() == fresh_children);
719 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
720 #[trigger] owner.children()[i]) is Some by {};
721 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
722
723 let new_paddr = owner.value().meta_slot_paddr().unwrap();
724 regions.lemma_contains_valid_frame_paddr(new_paddr);
725 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
726 new_meta_slot.paths_in_pt = set![owner.value().path];
727
728 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
732 cp0,
733 NR_ENTRIES as int,
734 self.idx as int,
735 self.pte,
736 );
737
738 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
742 let ghost new_node_addr = owner.value().node().slot_vaddr();
748 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
749 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
750 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
751
752 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
753 *owner,
754 owner.value().path,
755 f_nu,
756 );
757 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
758 *owner,
759 owner.value().path,
760 f_ms,
761 );
762 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
763 *owner,
764 owner.value().path,
765 f_pt,
766 );
767 }
768
769 Some(pt_lock_guard)
770 }
771 }
772
773 #[verifier::spinoff_prover]
789 #[verifier::rlimit(200)]
790 #[verus_spec(res =>
791 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
792 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
793 Tracked(regions): Tracked<&mut MetaRegionOwners>,
794 Tracked(guards): Tracked<&mut Guards>
795 requires
796 old(regions).inv(),
797 old(owner).inv(),
798 old(self).wf(old(owner).value()),
799 old(parent_owner).relate_guard(*old(self).node),
800 old(parent_owner).inv(),
801 old(parent_owner).level() == old(owner).value().parent_level,
802 old(parent_owner).level() < NR_LEVELS,
803 old(parent_owner).metaregion_sound_node(*old(regions)),
804 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==>
810 old(owner).value().metaregion_sound(*old(regions)),
811 ensures
812 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==> {
813 &&& res is Some
814 &&& final(owner).value().is_node()
815 &&& final(owner).level() == old(owner).level()
816 &&& final(parent_owner).relate_guard(*final(self).node)
817 &&& final(owner).value().node().relate_guard(res->0)
818 &&& final(owner).value().node().slot_vaddr() == res->0.inner.inner@.ptr.addr()
819 &&& final(guards).lock_held(res->0.inner.inner@.ptr.addr())
820 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
822 (#[trigger] final(owner).children()[j])->0.value().is_frame()
823 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
824 (#[trigger] final(owner).children()[j])->0.value().frame().prop
825 == old(owner).value().frame().prop
826 &&& final(owner).value().path == old(owner).value().path
827 &&& final(owner).value().metaregion_sound(*final(regions))
828 &&& OwnerSubtree::implies(
829 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
830 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
831 &&& OwnerSubtree::implies(
832 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
833 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
834 &&& final(owner).subtree_satisfies(final(owner).value().path,
835 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
836 &&& final(owner).subtree_satisfies(final(owner).value().path,
837 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
838 },
839 !old(owner).value().is_frame() || old(parent_owner).level() <= 1 ==> {
840 &&& res is None
841 &&& *final(owner) == *old(owner)
842 },
843 final(owner).inv(),
844 final(owner).value().parent_level == old(owner).value().parent_level,
845 final(self).idx == old(self).idx,
846 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==>
847 final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node),
848 final(regions).inv(),
849 final(parent_owner).inv(),
850 final(parent_owner).level() == old(parent_owner).level(),
851 final(self).node.inner.inner@.ptr.addr() == old(self).node.inner.inner@.ptr.addr(),
852 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
853 forall |i: usize| old(guards).unlocked(i) ==> final(guards).unlocked(i),
854 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==> {
856 &&& forall|i: int| i != meta_to_index(final(owner).value().node().slot_vaddr()) ==>
857 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
858 &&& forall|i: int| old(regions).slots.contains_key(i)
860 ==> (#[trigger] final(regions).slots.contains_key(i))
861 &&& final(regions).slot_owners[meta_to_index(final(owner).value().node().slot_vaddr())]
863 .ref_count() != REF_COUNT_UNUSED
864 &&& old(regions).slot_owners[meta_to_index(final(owner).value().node().slot_vaddr())]
866 .ref_count() == REF_COUNT_UNUSED
867 },
868 old(owner).value().is_frame() && old(parent_owner).level() > 1 ==>
873 forall|j: int| 0 <= j < NR_ENTRIES && j != old(self).idx ==>
874 #[trigger] final(parent_owner).children_perm.value()[j]
875 == old(parent_owner).children_perm.value()[j],
876 )]
877 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
878 PageTableGuard<'rcu, C>,
879 > {
880 #[verus_spec(with Tracked(&*parent_owner))]
881 let level = self.node.level();
882
883 if !(self.pte.is_last(level) && level > 1) {
884 return None;
885 }
886 let pa = self.pte.paddr();
887 let prop = self.pte.prop();
888
889 proof {
890 EntryOwner::last_pte_implies_frame_match(owner.value(), self.pte, level);
891 C::lemma_huge_raw_item_untracked(
892 pa,
893 level,
894 prop,
895 Tracked(owner.value().frame_permission()),
896 );
897 }
898
899 proof_decl!{
900 let tracked mut new_owner: OwnerSubtree<C>;
901 }
902
903 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
906 let new_page = PageTableNode::<C>::alloc(level - 1);
907 proof {
908 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
909 #[trigger] new_owner.children()[i]) is Some by {
910 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
911 new_owner,
912 (level - 1) as PagingLevel,
913 ));
914 assert(new_owner.has_child(i));
915 };
916 }
917
918 let paddr = new_page.start_paddr();
919
920 proof {
921 broadcast use group_page_meta;
922
923 }
924
925 let tracked new_owner_value = new_owner.tracked_borrow_value();
926 let tracked new_node = new_owner_value.tracked_borrow_node();
927 let tracked slot_perm = *regions.slots.tracked_borrow(new_node.slot_index);
928 let pt_ref = unsafe {
929 #[verus_spec(with Tracked(slot_perm), Tracked(&new_node.frame_permission))]
930 PageTableNodeRef::borrow_paddr(paddr)
931 };
932
933 let mut pt_lock_guard = {
935 let tracked new_owner_value = new_owner.tracked_borrow_value();
936 #[verus_spec(with Tracked(new_owner_value.tracked_borrow_node()), Tracked(guards))]
937 pt_ref.lock(guard)
938 };
939
940 let ghost children_perm = new_owner.value().node().children_perm;
941 let ghost new_owner_path = new_owner.value().path;
942 let ghost new_owner_meta_addr = new_owner.value().node().slot_vaddr();
943
944 proof {
945 broadcast use crate::specs::mm::frame::mapping::lemma_frame_to_index_injective;
946 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
947 broadcast use group_page_meta;
948
949 let new_idx = meta_to_index(new_owner_meta_addr);
950 let new_paddr = meta_to_frame(new_owner_meta_addr);
951 let nr_pages = page_size::<PagingConsts>(level) / PAGE_SIZE;
952
953 let pa_idx = frame_to_index(pa);
957 assert(pa_idx != new_idx) by {
958 if old(regions).slot_owners[pa_idx].usage
959 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
960 old(regions).lemma_contains_valid_frame_paddr(pa);
961 } else {
962 }
964 };
965
966 assert forall|j: usize|
968 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
969 0 < j < nr_pages implies {
970 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
971 &&& regions.slots.contains_key(sub_idx)
972 &&& regions.slot_owners[sub_idx].usage
973 != crate::specs::mm::frame::meta_owners::PageUsage::PageTable
974 &&& regions.slot_owners[sub_idx].usage
975 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
976 &&& regions.ref_count(sub_idx) != REF_COUNT_UNUSED
977 &&& regions.ref_count(sub_idx) > 0
978 &&& regions.ref_count(sub_idx) <= REF_COUNT_MAX
979 }
980 } by {
981 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
982 assert(sub_idx != new_idx) by {
983 if old(regions).slot_owners[sub_idx].usage
984 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
985 old(regions).lemma_contains_valid_frame_paddr(
986 (pa + j * PAGE_SIZE) as usize,
987 );
988 } else {
989 }
990 };
991 };
992 }
993
994 proof {
995 C::lemma_paging_consts_properties();
996 assert(nr_subpage_per_huge_spec::<C>() == NR_ENTRIES);
997 }
998
999 for i in 0..nr_subpage_per_huge::<C>()
1000 invariant
1001 nr_subpage_per_huge_spec::<C>() == NR_ENTRIES,
1002 1 < level < NR_LEVELS,
1003 owner.inv(),
1004 owner.value().is_frame(),
1005 owner.value().parent_level == level,
1006 owner.value().frame().mapped_pa == pa,
1007 owner.value().frame().prop == prop,
1008 !owner.value().frame_is_tracked(),
1009 owner.value().frame_permission() is None,
1010 pa == old(owner).value().frame().mapped_pa,
1011 level == old(parent_owner).level(),
1012 pa % page_size::<PagingConsts>(level) == 0,
1013 pa + page_size::<PagingConsts>(level) <= MAX_PADDR,
1014 regions.inv(),
1015 parent_owner.inv(),
1020 new_owner.value().is_node(),
1021 new_owner.inv(),
1022 new_owner.value().path == new_owner_path,
1023 new_owner.value().node().slot_vaddr() == new_owner_meta_addr,
1024 new_owner.value().node().relate_guard(pt_lock_guard),
1025 guards.lock_held(new_owner_meta_addr),
1026 new_owner.value().node().level() == (level - 1) as PagingLevel,
1027 forall|j: int| 0 <= j < NR_ENTRIES ==> (#[trigger] new_owner.children()[j]) is Some,
1028 forall|j: int|
1029 0 <= j < NR_ENTRIES ==> {
1030 &&& (#[trigger] new_owner.children()[j]) is Some
1031 &&& new_owner.children()[j].unwrap().value().match_pte(
1032 new_owner.value().node().children_perm.value()[j],
1033 new_owner.value().node().level(),
1034 )
1035 &&& new_owner.children()[j].unwrap().value().parent_level
1036 == new_owner.value().node().level()
1037 &&& new_owner.children()[j].unwrap().value().inv()
1038 &&& new_owner.children()[j].unwrap().value().path
1039 == new_owner_path.push_tail(j)
1040 },
1041 forall|j: int|
1042 i <= j < NR_ENTRIES ==> {
1043 &&& (#[trigger] new_owner.children()[j]) is Some
1044 &&& new_owner.children()[j].unwrap().value().is_absent()
1045 &&& new_owner.value().node().children_perm.value()[j]
1046 == C::E::new_absent_spec()
1047 },
1048 forall|j: int|
1050 0 <= j < i ==> {
1051 &&& (#[trigger] new_owner.children()[j]) is Some
1052 &&& new_owner.children()[j].unwrap().value().is_frame()
1053 },
1054 forall|j: usize|
1058 #![trigger frame_to_index(
1059 (pa + j * PAGE_SIZE) as usize)]
1060 0 < j < page_size::<PagingConsts>(level) / PAGE_SIZE ==> {
1061 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1062 &&& regions.slots.contains_key(sub_idx)
1063 &&& regions.slot_owners[sub_idx].usage !is PageTable
1064 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1065 &&& regions.ref_count(sub_idx) != REF_COUNT_UNUSED
1066 &&& regions.ref_count(sub_idx) > 0
1067 &&& regions.ref_count(sub_idx) <= REF_COUNT_MAX
1068 }
1069 },
1070 regions.slots.contains_key(frame_to_index(pa)),
1071 regions.slot_owner(pa).usage !is PageTable,
1072 regions.slot_owner(pa).usage !is MMIO ==> {
1073 &&& regions.slot_owner(pa).ref_count() != REF_COUNT_UNUSED
1074 &&& 0 < regions.slot_owner(pa).ref_count() <= REF_COUNT_MAX
1075 },
1076 new_page.ptr.addr() == new_owner_meta_addr,
1077 new_owner.value().node().metaregion_sound_node(*regions),
1078 regions.slot_owners[meta_to_index(new_owner_meta_addr)].ref_count()
1079 != REF_COUNT_UNUSED,
1080 0 < regions.slot_owners[meta_to_index(new_owner_meta_addr)].ref_count()
1081 <= REF_COUNT_MAX,
1082 regions.slot_owners[meta_to_index(new_owner_meta_addr)].paths_in_pt
1083 == set![new_owner_path],
1084 {
1085 proof {
1086 C::lemma_page_table_config_constant_properties();
1087 C::lemma_paging_consts_properties();
1088 let ghost the_node = new_owner.value().node();
1089
1090 assert(0 <= i < NR_ENTRIES);
1091 assert(new_owner.has_child(i as int));
1092 assert(new_owner.inv_children());
1093 assert(new_owner.child(i as int).inv());
1094 assert(new_owner.child(i as int).level() == new_owner.level() + 1);
1095 EntryOwner::huge_frame_split_child_at(owner.value(), *regions, i as usize);
1096 }
1097
1098 let small_pa = pa + i * page_size::<C>(level - 1);
1099
1100 let tracked mut child_owner = EntryOwner::tracked_new_frame(
1101 small_pa,
1102 new_owner.value().path.push_tail(i as int),
1103 (level - 1) as PagingLevel,
1104 prop,
1105 None,
1106 );
1107
1108 let ghost new_owner_before_update = new_owner;
1109 let tracked mut new_owner_node = {
1110 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1111 new_owner_value.tracked_take_node()
1112 };
1113 let tracked mut new_owner_child = new_owner.tracked_borrow_mut_child(i as int);
1114 let ghost new_owner_child_before_update = *new_owner_child;
1115
1116 proof {
1117 let idx = frame_to_index(small_pa);
1118 if i != 0 {
1119 let ghost big_j =
1120 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1121 pa, level, i);
1122 }
1123 if level - 1 > 1 {
1124 let nr_subpages = page_size::<PagingConsts>((level - 1) as PagingLevel)
1125 / PAGE_SIZE;
1126 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq::<
1127 PagingConsts,
1128 >((level - 1) as PagingLevel);
1129 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq::<
1130 PagingConsts,
1131 >(level);
1132 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_next::<
1133 PagingConsts,
1134 >((level - 1) as PagingLevel);
1135 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
1136 assert forall|j_prime: usize|
1137 #![trigger frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize)]
1138 0 < j_prime < nr_subpages implies {
1139 let sub_idx = frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize);
1140 &&& regions.slots.contains_key(sub_idx)
1141 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1142 &&& regions.ref_count(sub_idx) != REF_COUNT_UNUSED
1143 &&& regions.ref_count(sub_idx) > 0
1144 &&& regions.ref_count(sub_idx) <= REF_COUNT_MAX
1145 }
1146 } by {
1147 let sub_pages_per_subframe = page_size::<PagingConsts>(
1148 (level - 1) as PagingLevel,
1149 ) / PAGE_SIZE;
1150 let big_j_int: int = i * sub_pages_per_subframe + j_prime;
1151 vstd::arithmetic::mul::lemma_mul_nonnegative(
1152 i as int,
1153 sub_pages_per_subframe as int,
1154 );
1155 vstd::arithmetic::mul::lemma_mul_inequality(
1156 i + 1,
1157 NR_ENTRIES as int,
1158 sub_pages_per_subframe as int,
1159 );
1160 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1161 sub_pages_per_subframe as int,
1162 i as int,
1163 1int,
1164 );
1165 vstd::arithmetic::mul::lemma_mul_is_associative(
1166 NR_ENTRIES as int,
1167 sub_pages_per_subframe as int,
1168 PAGE_SIZE as int,
1169 );
1170 vstd::arithmetic::div_mod::lemma_div_by_multiple(
1171 NR_ENTRIES * sub_pages_per_subframe,
1172 PAGE_SIZE as int,
1173 );
1174 let big_j: usize = big_j_int as usize;
1175 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1176 PAGE_SIZE as int,
1177 i * sub_pages_per_subframe,
1178 j_prime as int,
1179 );
1180 vstd::arithmetic::mul::lemma_mul_is_associative(
1181 i as int,
1182 sub_pages_per_subframe as int,
1183 PAGE_SIZE as int,
1184 );
1185 assert((small_pa + j_prime * PAGE_SIZE) as usize == (pa + big_j
1186 * PAGE_SIZE) as usize);
1187 assert(regions.slots.contains_key(
1188 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1189 ));
1190 }
1191 }
1192 if i == 0 {
1193 assert(i * page_size::<PagingConsts>((level - 1) as PagingLevel) == 0) by {
1194 vstd::arithmetic::mul::lemma_mul_by_zero_is_zero(
1195 page_size::<PagingConsts>((level - 1) as PagingLevel) as int,
1196 );
1197 }
1198 } else {
1199 let ghost big_j =
1200 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1201 pa, level, i);
1202 assert(regions.slots.contains_key(
1203 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1204 ));
1205 }
1206
1207 regions.lemma_contains_valid_frame_paddr(small_pa);
1208 let tracked mut small_slot = regions.tracked_borrow_mut_slot_owner(small_pa);
1209 small_slot.paths_in_pt = small_slot.paths_in_pt.insert(child_owner.path);
1210
1211 if (level - 1) > 1 {
1212 }
1213 let ghost target_idx = frame_to_index(small_pa);
1214 if i != 0 {
1215 let ghost _ =
1216 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1217 pa, level, i);
1218
1219 }
1220 C::lemma_raw_item_well_formed_split(
1221 pa,
1222 level,
1223 prop,
1224 small_pa,
1225 i,
1226 Tracked(owner.value().frame_permission()),
1227 );
1228 C::lemma_none_perm_well_formed(small_pa, *regions);
1229 }
1230
1231 let ghost nidx = meta_to_index(new_owner_meta_addr);
1235 proof {
1236 }
1240 let ghost regions_pre_replace = *regions;
1241 {
1242 let tracked new_owner_child_value = new_owner_child.tracked_borrow_mut_value();
1243 #[verus_spec(with Tracked(regions),
1244 Tracked(new_owner_child_value),
1245 Tracked(&mut child_owner),
1246 Tracked(&mut new_owner_node))]
1247 pt_lock_guard.replace_absent_with_frame(i, small_pa, level - 1, prop);
1248
1249 proof {
1250 *new_owner_child_value = child_owner;
1251 }
1252 }
1253
1254 proof {
1255 new_owner_child_before_update.lemma_set_value_observable_fields(child_owner);
1256 OwnerSubtree::lemma_ext_equal(
1257 *new_owner_child,
1258 new_owner_child_before_update.set_value(child_owner),
1259 );
1260 assert(new_owner_child.inv());
1261
1262 {
1263 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1264 new_owner_value.tracked_put_node(new_owner_node);
1265 }
1266
1267 let owner_with_updated_value = new_owner_before_update.set_value(new_owner.value());
1268 vstd::seq_lib::lemma_update_is_remove_insert(
1269 new_owner_before_update.children(),
1270 i as int,
1271 Some(*new_owner_child),
1272 );
1273 assert(new_owner.children() == new_owner_before_update.children().remove(
1274 i as int,
1275 ).insert(i as int, Some(*new_owner_child)));
1276 assert(owner_with_updated_value.insert(i as int, *new_owner_child).children()
1277 == new_owner_before_update.children().update(i as int, Some(*new_owner_child)));
1278 assert(new_owner.children() =~= owner_with_updated_value.insert(
1279 i as int,
1280 *new_owner_child,
1281 ).children());
1282 assert(new_owner.children() == owner_with_updated_value.insert(
1283 i as int,
1284 *new_owner_child,
1285 ).children());
1286 OwnerSubtree::lemma_ext_equal(
1287 new_owner,
1288 owner_with_updated_value.insert(i as int, *new_owner_child),
1289 );
1290 assert forall|j: int| 0 <= j < NR_ENTRIES implies (
1291 #[trigger] new_owner.children()[j]) is Some by {
1292 if j != i {
1293 assert(owner_with_updated_value.insert(
1294 i as int,
1295 *new_owner_child,
1296 ).children()[j] == owner_with_updated_value.children()[j]);
1297 }
1298 };
1299 assert(new_owner.inv());
1300
1301 }
1302 }
1303
1304 self.pte = {
1305 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1306 #[verus_spec(with Tracked(new_owner_value))]
1307 Child::PageTable(new_page).into_pte()
1308 };
1309
1310 proof {
1311 *owner = new_owner;
1312 }
1313
1314 unsafe {
1319 let tracked owner_value = owner.tracked_borrow_mut_value();
1320 #[verus_spec(with Tracked(owner_value.tracked_borrow_mut_node()), Tracked(&*regions))]
1321 self.node.write_pte(self.idx, self.pte)
1322 };
1323
1324 Some(pt_lock_guard)
1325 }
1326
1327 #[verus_spec(res =>
1343 with Tracked(owner): Tracked<&EntryOwner<C>>,
1344 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1345 Tracked(regions): Tracked<&MetaRegionOwners>,
1346 requires
1347 owner.inv(),
1348 parent_owner.inv(),
1349 parent_owner.relate_guard(*guard),
1350 idx < NR_ENTRIES,
1351 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1352 regions.inv(),
1353 regions.slots.contains_key(parent_owner.slot_index),
1354 ensures
1355 res.wf(*owner),
1356 res.idx == idx,
1357 parent_owner.relate_guard(*res.node),
1358 *res.node == *old(guard),
1361 *final(guard) == *final(res.node),
1362 )]
1363 pub(in crate::mm) unsafe fn new_at(guard: &'a mut PageTableGuard<'rcu, C>, idx: usize) -> Self {
1364 let pte = unsafe {
1366 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1367 guard.read_pte(idx)
1368 };
1369 Self::new(pte, idx, guard)
1370 }
1371}
1372
1373#[verus_verify]
1374impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
1375 #[verus_spec(res =>
1376 with Tracked(owner): Tracked<&mut EntryOwner<C>>,
1377 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1378 Tracked(regions): Tracked<&MetaRegionOwners>,
1379 requires
1380 old(owner).inv(),
1381 old(owner).is_frame(),
1382 old(owner).match_pte(
1383 old(parent_owner).children_perm.value()[idx as int],
1384 old(owner).parent_level,
1385 ),
1386 old(parent_owner).inv(),
1387 old(parent_owner).relate_guard(*old(self)),
1388 old(parent_owner).level() == old(owner).parent_level,
1389 old(parent_owner).metaregion_sound_node(*regions),
1390 idx < NR_ENTRIES,
1391 op.requires((old(owner).frame().prop,)),
1392 regions.inv(),
1393 regions.slots.contains_key(old(parent_owner).slot_index),
1394 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty,
1395 perm: Tracked<Option<C::Perm>>|
1396 #![auto]
1397 op.ensures((p_in,), p_out) ==> (
1398 C::item_into_raw(C::item_from_raw(pa, level, p_out, perm)).3@
1399 is Some
1400 ) == (perm@ is Some),
1401 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1402 #![auto]
1403 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
1404 ==> C::E::new_page_req(pa, level, p_out),
1405 ensures
1406 final(owner).inv(),
1407 final(owner).is_frame(),
1408 final(owner).match_pte(res, final(parent_owner).level()),
1409 final(owner).match_pte(
1410 final(parent_owner).children_perm.value()[idx as int],
1411 final(parent_owner).level(),
1412 ),
1413 res == final(parent_owner).children_perm.value()[idx as int],
1414 final(parent_owner).inv(),
1415 final(parent_owner).slot_index == old(parent_owner).slot_index,
1416 final(parent_owner).level() == old(parent_owner).level(),
1417 final(parent_owner).tree_level == old(parent_owner).tree_level,
1418 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1419 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1420 final(parent_owner).relate_guard(*final(self)),
1421 final(parent_owner).metaregion_sound_node(*regions),
1422 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
1423 final(owner).frame_permission() == old(owner).frame_permission(),
1424 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
1425 final(owner).path == old(owner).path,
1426 final(owner).parent_level == old(owner).parent_level,
1427 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1428 #[trigger] final(parent_owner).children_perm.value()[j]
1429 == old(parent_owner).children_perm.value()[j],
1430 crate::specs::mm::page_table::node::owners::count_present(
1431 final(parent_owner).children_perm.value(),
1432 ) == crate::specs::mm::page_table::node::owners::count_present(
1433 old(parent_owner).children_perm.value(),
1434 ),
1435 op.ensures((old(owner).frame().prop,), final(owner).frame().prop),
1436 *final(self) == *old(self),
1437 )]
1438 pub(in crate::mm) fn protect_child(
1439 &mut self,
1440 idx: usize,
1441 op: impl FnOnce(PageProperty) -> PageProperty,
1442 ) -> C::E {
1443 let ghost cp_old = parent_owner.children_perm.value();
1444 let mut pte = unsafe {
1445 #[verus_spec(with Tracked(&*parent_owner), Tracked(regions))]
1446 self.read_pte(idx)
1447 };
1448
1449 let prop = pte.prop();
1450 let new_prop = op(prop);
1451
1452 proof {
1453 assert(owner.frame().prop == prop);
1454 assert(op.ensures((prop,), new_prop));
1455 C::lemma_raw_item_well_formed_preserved(
1456 owner.frame().mapped_pa,
1457 owner.parent_level,
1458 prop,
1459 new_prop,
1460 Tracked(owner.frame_permission()),
1461 );
1462 }
1463
1464 assume(pte.set_prop_req(new_prop));
1465 pte.set_prop(new_prop);
1466
1467 unsafe {
1468 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1469 self.write_pte(idx, pte)
1470 };
1471
1472 proof {
1473 owner.tracked_set_frame_prop(new_prop);
1474 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1478 cp_old,
1479 NR_ENTRIES as int,
1480 idx as int,
1481 pte,
1482 );
1483 }
1484
1485 pte
1486 }
1487
1488 #[verifier::spinoff_prover]
1489 #[verus_spec(res =>
1490 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
1491 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1492 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1493 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1494 requires
1495 old(owner).inv(),
1496 old(owner).metaregion_sound(*old(regions)),
1497 old(owner).match_pte(
1498 old(parent_owner).children_perm.value()[idx as int],
1499 old(owner).parent_level,
1500 ),
1501 old(parent_owner).inv(),
1502 old(parent_owner).relate_guard(*old(self)),
1503 old(parent_owner).level() == old(owner).parent_level,
1504 idx < NR_ENTRIES,
1505 old(regions).inv(),
1506 old(regions).slots.contains_key(old(parent_owner).slot_index),
1507 new_child.invariants(*old(new_owner), *old(regions)),
1508 old(owner).path == old(new_owner).path,
1509 old(owner).parent_level == old(new_owner).parent_level,
1510 old(new_owner).is_node() ==> {
1511 &&& old(regions).slots.contains_key(frame_to_index(old(new_owner).meta_slot_paddr()->0))
1512 &&& old(regions).slot_owner(old(new_owner).meta_slot_paddr()->0).ref_count() != REF_COUNT_UNUSED
1513 },
1514 old(parent_owner).metaregion_sound_node(*old(regions)),
1515 ensures
1516 res.invariants(*final(owner), *final(regions)),
1517 final(new_owner).inv(),
1518 final(new_owner).metaregion_sound(*final(regions)),
1519 final(new_owner).match_pte(
1520 final(parent_owner).children_perm.value()[idx as int],
1521 final(parent_owner).level(),
1522 ),
1523 final(new_owner).path == old(new_owner).path,
1524 final(new_owner).parent_level == old(new_owner).parent_level,
1525 *final(owner) == old(owner).from_pte_owner_spec(),
1526 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1527 Entry::<C>::metaregion_sound_neq_preserved(
1528 *old(owner),
1529 *final(new_owner),
1530 *old(regions),
1531 *final(regions),
1532 ),
1533 !final(new_owner).is_node() ==> Entry::<C>::metaregion_sound_neq_old_preserved(
1534 *old(owner),
1535 *old(regions),
1536 *final(regions),
1537 ),
1538 (!old(owner).is_node() && !final(new_owner).is_node())
1539 ==> Entry::<C>::metaregion_sound_preserved(*old(regions), *final(regions)),
1540 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
1541 C,
1542 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
1543 final(parent_owner).inv(),
1544 final(parent_owner).level() == old(parent_owner).level(),
1545 final(parent_owner).relate_guard(*final(self)),
1546 final(parent_owner).metaregion_sound_node(*final(regions)),
1547 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1548 #[trigger] final(parent_owner).children_perm.value()[j]
1549 == old(parent_owner).children_perm.value()[j],
1550 forall|slot: int|
1551 #![trigger final(regions).slot_owners[slot].paths_in_pt]
1552 (!final(new_owner).is_node() || final(new_owner).is_absent() || slot
1553 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
1554 ==> final(regions).slot_owners[slot].paths_in_pt == old(
1555 regions,
1556 ).slot_owners[slot].paths_in_pt,
1557 forall|k: int|
1558 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(k),
1559 forall|slot: int|
1560 #![trigger final(regions).slot_owners[slot].ref_count()]
1561 final(regions).ref_count(slot) == old(
1562 regions,
1563 ).ref_count(slot),
1564 forall|slot: int|
1565 #![trigger final(regions).slot_owners[slot].ref_count_perm]
1566 final(regions).slot_owners[slot].same_permissions(
1567 old(regions).slot_owners[slot],
1568 ),
1569 final(regions).slots == old(regions).slots,
1570 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
1571 &&& final(regions).slots == old(regions).slots
1572 &&& forall|i: int|
1573 #![trigger final(regions).slot_owners[i]]
1574 final(regions).slot_owners[i] == old(
1575 regions,
1576 ).slot_owners[i]
1577 },
1578 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
1579 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
1580 == #[trigger] final(regions).slots[k],
1581 Entry::<C>::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
1582 *final(self) == *old(self),
1583 )]
1584 #[verifier::spinoff_prover]
1585 pub(in crate::mm) fn replace_child(&mut self, idx: usize, new_child: Child<C>) -> Child<C> {
1586 let ghost initial_regions = *regions;
1587 let ghost initial_owner = *owner;
1588 let ghost initial_new_owner = *new_owner;
1589 #[cfg(feature = "allow_panic")]
1590 {
1591 let guard_level = self.level();
1592 match &new_child {
1593 Child::PageTable(node) => {
1594 assert!(node.level() == guard_level - 1);
1595 },
1596 Child::Frame(_, level, _) => {
1597 assert!(*level == guard_level);
1598 },
1599 Child::None => {},
1600 }
1601 }
1602
1603 let pte = unsafe {
1604 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1605 self.read_pte(idx)
1606 };
1607
1608 #[verus_spec(with Tracked(&*parent_owner))]
1609 let level = self.level();
1610
1611 let old_child = unsafe {
1612 #[verus_spec(with Tracked(regions), Tracked(owner))]
1613 Child::from_pte(pte, level)
1614 };
1615
1616 let ghost cp0 = parent_owner.children_perm.value();
1618
1619 if old_child.is_none() && !new_child.is_none() {
1620 #[verus_spec(with
1621 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
1622 &parent_owner.frame_permission,
1623 )),
1624 Ghost(parent_owner.meta_own.nr_children.id())
1625 )]
1626 let nr_children = self.nr_children_mut();
1627 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1628 proof {
1629 parent_owner.nr_children_absent_slot_bound(idx);
1630 }
1631 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
1632 } else if !old_child.is_none() && new_child.is_none() {
1633 #[verus_spec(with
1634 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
1635 &parent_owner.frame_permission,
1636 )),
1637 Ghost(parent_owner.meta_own.nr_children.id())
1638 )]
1639 let nr_children = self.nr_children_mut();
1640 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1641 proof {
1642 parent_owner.nr_children_present_slot_bound(idx);
1643 }
1644 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
1645 }
1646 #[verus_spec(with Tracked(new_owner))]
1647 let new_pte = new_child.into_pte();
1648
1649 unsafe {
1650 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1651 self.write_pte(idx, new_pte)
1652 };
1653
1654 proof {
1655 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1656 cp0,
1657 NR_ENTRIES as int,
1658 idx as int,
1659 new_pte,
1660 );
1661 }
1662
1663 proof {
1664 if new_owner.is_node() {
1665 let paddr = new_owner.meta_slot_paddr().unwrap();
1666 regions.lemma_contains_valid_frame_paddr(paddr);
1667 let tracked mut new_meta_slot = regions.tracked_borrow_mut_slot_owner(paddr);
1668 new_meta_slot.paths_in_pt = set![new_owner.path];
1669 }
1670 }
1671
1672 proof {
1673 if new_owner.is_node() || new_owner.is_frame() {
1674 let paddr = new_owner.meta_slot_paddr().unwrap();
1675 regions.lemma_contains_valid_frame_paddr(paddr);
1676 }
1677 if owner.is_frame() {
1678 let paddr = owner.frame().mapped_pa;
1679 let slot = frame_to_index(paddr);
1680 assert(initial_regions.slots[slot] == regions.slots[slot]);
1681 assert(initial_regions.slot_owners[slot].metadata_perm.id()
1682 == regions.slot_owners[slot].metadata_perm.id());
1683 C::lemma_perm_well_formed_with_region_preserved(
1684 paddr,
1685 Tracked(owner.frame_permission()),
1686 initial_regions,
1687 *regions,
1688 );
1689 }
1690 if new_owner.is_frame() {
1691 let paddr = new_owner.frame().mapped_pa;
1692 let slot = frame_to_index(paddr);
1693 assert(initial_regions.slots[slot] == regions.slots[slot]);
1694 assert(initial_regions.slot_owners[slot].metadata_perm.id()
1695 == regions.slot_owners[slot].metadata_perm.id());
1696 C::lemma_perm_well_formed_with_region_preserved(
1697 paddr,
1698 Tracked(new_owner.frame_permission()),
1699 initial_regions,
1700 *regions,
1701 );
1702 }
1703 assert(Entry::<C>::metaregion_sound_neq_preserved(
1704 initial_owner,
1705 *new_owner,
1706 initial_regions,
1707 *regions,
1708 )) by {
1709 let f = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1710 entry.meta_slot_paddr_neq(initial_owner) && entry.meta_slot_paddr_neq(
1711 *new_owner,
1712 ) && entry.metaregion_sound(initial_regions);
1713 let g = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1714 entry.metaregion_sound(*regions);
1715 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
1716 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
1717 if entry.is_frame() {
1718 let paddr = entry.frame().mapped_pa;
1719 let slot = frame_to_index(paddr);
1720 assert(initial_regions.slots[slot] == regions.slots[slot]);
1721 assert(initial_regions.slot_owners[slot].metadata_perm.id()
1722 == regions.slot_owners[slot].metadata_perm.id());
1723 C::lemma_perm_well_formed_with_region_preserved(
1724 paddr,
1725 Tracked(entry.frame_permission()),
1726 initial_regions,
1727 *regions,
1728 );
1729 }
1730 };
1731 };
1732 }
1733
1734 old_child
1735 }
1736
1737 #[verifier::spinoff_prover]
1738 #[verus_spec(res =>
1739 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
1740 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1741 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1742 Tracked(guards): Tracked<&mut Guards>,
1743 requires
1744 old(owner).inv(),
1745 old(owner).value().is_absent(),
1746 old(owner).level() < INC_LEVELS - 1,
1747 old(owner).value().metaregion_sound(*old(regions)),
1748 old(parent_owner).inv(),
1749 old(parent_owner).relate_guard(*old(self)),
1750 old(parent_owner).level() == old(owner).value().parent_level,
1751 old(parent_owner).level() > 1,
1752 old(parent_owner).metaregion_sound_node(*old(regions)),
1753 idx < NR_ENTRIES,
1754 old(owner).value().match_pte(
1755 old(parent_owner).children_perm.value()[idx as int],
1756 old(owner).value().parent_level,
1757 ),
1758 old(regions).inv(),
1759 old(regions).slots.contains_key(old(parent_owner).slot_index),
1760 ensures
1761 final(owner).inv(),
1762 final(owner).value().is_node(),
1763 final(owner).level() == old(owner).level(),
1764 final(owner).value().parent_level == old(owner).value().parent_level,
1765 final(owner).value().path == old(owner).value().path,
1766 final(owner).value().metaregion_sound(*final(regions)),
1767 final(owner).value().node().relate_guard(res),
1768 final(owner).value().node().slot_vaddr() == res.inner.inner@.ptr.addr(),
1769 final(owner).value().match_pte(
1770 final(parent_owner).children_perm.value()[idx as int],
1771 final(parent_owner).level(),
1772 ),
1773 final(guards).lock_held(final(owner).value().node().slot_vaddr()),
1774 OwnerSubtree::implies(
1775 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
1776 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr())),
1777 Entry::<C>::metaregion_sound_neq_preserved(
1778 old(owner).value(),
1779 final(owner).value(),
1780 *old(regions),
1781 *final(regions),
1782 ),
1783 Entry::<C>::path_tracked_pred_preserved(*old(regions), *final(regions)),
1784 old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0)),
1785 final(owner).subtree_satisfies(final(owner).value().path,
1786 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().slot_vaddr())),
1787 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions))),
1788 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions))),
1789 PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![],
1790 forall|i: int| 0 <= i < NR_ENTRIES ==>
1791 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent(),
1792 forall|i: int| 0 <= i < NR_ENTRIES ==>
1793 (#[trigger] final(owner).children()[i])->0.value().path
1794 == final(owner).value().path.push_tail(i),
1795 crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner)),
1796 forall|i: int| 0 <= i < NR_ENTRIES ==>
1797 (#[trigger] final(owner).children()[i])->0.value().parent_level
1798 == final(owner).value().node().level(),
1799 forall|i: int| 0 <= i < NR_ENTRIES ==>
1800 (#[trigger] final(owner).children()[i])->0.value().match_pte(
1801 final(owner).value().node().children_perm.value()[i],
1802 final(owner).children()[i]->0.value().parent_level),
1803 forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
1804 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i],
1805 forall|i: int| old(regions).slots.contains_key(i)
1806 ==> (#[trigger] final(regions).slots.contains_key(i)),
1807 forall|i: int| #![trigger final(regions).slots[i]]
1808 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
1809 && old(regions).slots.contains_key(i)
1810 ==> final(regions).slots[i] == old(regions).slots[i],
1811 final(regions).slot_owner(final(owner).value().meta_slot_paddr()->0)
1812 .ref_count() != REF_COUNT_UNUSED,
1813 old(regions).slot_owner(final(owner).value().meta_slot_paddr().unwrap())
1814 .ref_count() == REF_COUNT_UNUSED,
1815 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
1816 final(owner).value().meta_slot_paddr().unwrap()),
1817 final(regions).inv(),
1818 final(parent_owner).inv(),
1819 final(parent_owner).level() == old(parent_owner).level(),
1820 final(parent_owner).relate_guard(*final(self)),
1821 final(parent_owner).metaregion_sound_node(*final(regions)),
1822 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1823 #[trigger] final(parent_owner).children_perm.value()[j]
1824 == old(parent_owner).children_perm.value()[j],
1825 *final(self) == *old(self),
1826 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
1827 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().slot_vaddr() ==> final(guards).unlocked(i),
1828 )]
1829 pub(in crate::mm) fn alloc_absent_child<A: InAtomicMode>(
1830 &mut self,
1831 idx: usize,
1832 guard: &'rcu A,
1833 ) -> PageTableGuard<'rcu, C> {
1834 #[verus_spec(with Tracked(&*parent_owner))]
1835 let level = self.level();
1836
1837 let ghost old_path = owner.value().path;
1838
1839 proof {
1845 parent_owner.nr_children_absent_slot_bound(idx);
1846 }
1847 let ghost regions_pre = *regions;
1848 let ghost cp0 = parent_owner.children_perm.value();
1851 let ghost old_owner_val = owner.value();
1854
1855 proof_decl! {
1856 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
1857 }
1858
1859 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(idx) => Tracked(new_node_owner))]
1860 let new_page = PageTableNode::<C>::alloc(level - 1);
1861 let ghost fresh_children = new_node_owner.children();
1862 proof {
1863 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1864 #[trigger] fresh_children[i]) is Some by {
1865 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
1866 new_node_owner,
1867 (level - 1) as PagingLevel,
1868 ));
1869 assert(new_node_owner.has_child(i));
1870 };
1871 }
1872
1873 proof {
1874 let pte = C::E::new_pt_spec(meta_to_frame(new_node_owner.value().node().slot_vaddr()));
1875 C::E::lemma_page_table_entry_properties();
1876 }
1877
1878 let paddr = new_page.start_paddr();
1879
1880 let new_pte = {
1881 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1882 #[verus_spec(with Tracked(new_node_value))]
1883 Child::PageTable(new_page).into_pte()
1884 };
1885
1886 proof {
1887 broadcast use group_page_meta;
1888
1889 }
1890
1891 let tracked new_node_value = new_node_owner.tracked_borrow_value();
1892 let tracked new_node = new_node_value.tracked_borrow_node();
1893 let tracked slot_perm = *regions.slots.tracked_borrow(new_node.slot_index);
1894 let pt_ref = unsafe {
1895 #[verus_spec(with Tracked(slot_perm), Tracked(&new_node.frame_permission))]
1896 PageTableNodeRef::borrow_paddr(paddr)
1897 };
1898
1899 let pt_lock_guard = {
1900 let tracked new_node_value = new_node_owner.tracked_borrow_value();
1901 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
1902 pt_ref.lock(guard)
1903 };
1904
1905 unsafe {
1906 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1907 self.write_pte(idx, new_pte)
1908 };
1909
1910 #[verus_spec(with
1918 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
1919 &parent_owner.frame_permission,
1920 )),
1921 Ghost(parent_owner.meta_own.nr_children.id())
1922 )]
1923 let nr_children = self.nr_children_mut();
1924 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1925 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1926
1927 proof {
1928 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1933 cp0,
1934 NR_ENTRIES as int,
1935 idx as int,
1936 new_pte,
1937 );
1938 }
1939
1940 proof {
1941 {
1942 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1943 new_node_value.parent_level = level as PagingLevel;
1944 new_node_value.path = old_path;
1945 }
1946 *owner = new_node_owner;
1947 assert(owner.children() == fresh_children);
1948 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
1949
1950 let new_paddr = owner.value().meta_slot_paddr().unwrap();
1951 regions.lemma_contains_valid_frame_paddr(new_paddr);
1952 let tracked new_meta_slot = regions.tracked_borrow_mut_slot_owner(new_paddr);
1953 new_meta_slot.paths_in_pt = set![owner.value().path];
1954 }
1955
1956 proof {
1957 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1958
1959 let ghost new_node_addr = owner.value().node().slot_vaddr();
1960 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
1961 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
1962 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
1963
1964 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1967 *owner,
1968 owner.value().path,
1969 f_nu,
1970 );
1971 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1972 *owner,
1973 owner.value().path,
1974 f_ms,
1975 );
1976 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1977 *owner,
1978 owner.value().path,
1979 f_pt,
1980 );
1981 }
1982
1983 pt_lock_guard
1984 }
1985
1986 #[verifier::spinoff_prover]
1987 #[verus_spec(
1988 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
1989 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1990 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1991 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1992 requires
1993 old(owner).inv(),
1994 old(owner).is_absent(),
1995 old(owner).metaregion_sound(*old(regions)),
1996 old(parent_owner).inv(),
1997 old(parent_owner).relate_guard(*old(self)),
1998 old(parent_owner).level() == old(owner).parent_level,
1999 idx < NR_ENTRIES,
2000 old(owner).match_pte(
2001 old(parent_owner).children_perm.value()[idx as int],
2002 old(owner).parent_level,
2003 ),
2004 old(regions).inv(),
2005 old(regions).slots.contains_key(old(parent_owner).slot_index),
2006 old(parent_owner).metaregion_sound_node(*old(regions)),
2007 Child::<C>::Frame(paddr, level, prop).invariants(*old(new_owner), *old(regions)),
2008 old(owner).path == old(new_owner).path,
2009 old(owner).parent_level == old(new_owner).parent_level,
2010 ensures
2011 final(new_owner).inv(),
2012 final(parent_owner).inv(),
2013 *final(owner) == old(owner).from_pte_owner_spec(),
2014 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
2015 final(new_owner).pte_invariants(
2016 final(parent_owner).children_perm.value()[idx as int],
2017 *final(regions),
2018 ),
2019 forall|i: int|
2020 0 <= i < NR_ENTRIES && i != idx ==> #[trigger] old(parent_owner).children_perm.value()[i]
2021 == final(parent_owner).children_perm.value()[i],
2022 final(parent_owner).slot_index == old(parent_owner).slot_index,
2023 final(parent_owner).level() == old(parent_owner).level(),
2024 final(parent_owner).tree_level == old(parent_owner).tree_level,
2025 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
2026 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
2027 final(parent_owner).relate_guard(*final(self)),
2028 final(parent_owner).metaregion_sound_node(*final(regions)),
2029 *final(regions) == *old(regions),
2030 *final(self) == *old(self),
2031 )]
2032 pub(in crate::mm) fn replace_absent_with_frame(
2033 &mut self,
2034 idx: usize,
2035 paddr: Paddr,
2036 level: PagingLevel,
2037 prop: PageProperty,
2038 ) {
2039 let ghost cp0 = parent_owner.children_perm.value();
2041 #[verus_spec(with
2042 Tracked(NodeOwner::<C>::tracked_borrow_frame_metadata_perm(
2043 &parent_owner.frame_permission,
2044 )),
2045 Ghost(parent_owner.meta_own.nr_children.id())
2046 )]
2047 let nr_children = self.nr_children_mut();
2048 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
2049 proof {
2050 parent_owner.nr_children_absent_slot_bound(idx);
2051 }
2052 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
2053
2054 #[verus_spec(with Tracked(new_owner))]
2055 let new_pte = Child::<C>::Frame(paddr, level, prop).into_pte();
2056
2057 unsafe {
2058 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
2059 self.write_pte(idx, new_pte)
2060 };
2061
2062 proof {
2063 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
2067 cp0,
2068 NR_ENTRIES as int,
2069 idx as int,
2070 new_pte,
2071 );
2072 }
2073 }
2074}
2075
2076}