1use vstd::prelude::*;
4
5use vstd_extra::ghost_tree::*;
6use vstd_extra::ownership::*;
7
8use crate::arch::mm::PagingConsts;
9use crate::mm::frame::meta::mapping::{frame_to_meta, meta_to_frame};
10use crate::mm::frame::{
11 Frame, FrameRef,
12 meta::{REF_COUNT_MAX, REF_COUNT_UNUSED},
13};
14use crate::mm::page_table::*;
15use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
16use crate::specs::arch::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
17use crate::specs::mm::frame::{
18 mapping::{frame_to_index, group_page_meta},
19 meta_region_owners::MetaRegionOwners,
20};
21use crate::specs::mm::page_table::{INC_LEVELS, PageTableOwner};
22use crate::specs::task::InAtomicMode;
23
24use core::marker::PhantomData;
25use core::ops::Deref;
26
27use crate::{
28 mm::{nr_subpage_per_huge, nr_subpage_per_huge_spec, page_prop::PageProperty},
29 };
32
33use super::*;
34
35verus! {
36
37broadcast use group_ghost_tree_lemmas;
38
39pub type PageTableNodeRef<'a, C> = FrameRef<'a, PageTablePageMeta<C>>;
41
42pub struct PageTableGuard<'rcu, C: PageTableConfig> {
44 pub inner: PageTableNodeRef<'rcu, C>,
45}
46
47impl<'rcu, C: PageTableConfig> Deref for PageTableGuard<'rcu, C> {
48 type Target = PageTableNodeRef<'rcu, C>;
49
50 #[verus_spec(ensures returns self.inner)]
51 fn deref(&self) -> &Self::Target {
52 &self.inner
53 }
54}
55
56pub struct Entry<'a, 'rcu, C: PageTableConfig> {
57 pub pte: C::E,
76 pub idx: usize,
78 pub node: &'a mut PageTableGuard<'rcu, C>,
80}
81
82#[verus_verify]
83impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
84 pub open spec fn new_spec(
85 pte: C::E,
86 idx: usize,
87 node: &'a mut PageTableGuard<'rcu, C>,
88 ) -> Self {
89 Self { pte, idx, node }
90 }
91
92 #[verus_spec(res =>
93 ensures
94 res.pte == pte,
95 res.idx == idx,
96 *res.node == *old(node),
97 *final(node) == *final(res.node),
98 )]
99 pub fn new(pte: C::E, idx: usize, node: &'a mut PageTableGuard<'rcu, C>) -> Self {
100 Self { pte, idx, node }
101 }
102}
103
104#[verus_verify]
105impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
106 #[verus_spec(r =>
108 with Tracked(owner): Tracked<&EntryOwner<C>>,
109 requires
110 self.wf(*owner),
111 owner.inv(),
112 returns owner.is_absent(),
113 )]
114 pub(in crate::mm) fn is_none(&self) -> bool {
115 !self.pte.is_present()
116 }
117
118 #[verus_spec(
120 with Tracked(owner): Tracked<EntryOwner<C>>,
121 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
122 Tracked(regions): Tracked<&MetaRegionOwners>,
123 requires
124 owner.inv(),
125 self.wf(owner),
126 parent_owner.relate_guard(*self.node),
127 parent_owner.inv(),
128 parent_owner.level == owner.parent_level,
129 regions.inv(),
130 parent_owner.metaregion_sound_node(*regions),
131 returns
132 owner.is_node(),
133 )]
134 pub(in crate::mm) fn is_node(&self) -> bool {
135 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
136 parent_owner.slot_index,
137 );
138 self.pte.is_present() && !self.pte.is_last(
139 #[verus_spec(with Tracked(parent_meta_perm))]
140 self.node.level(),
141 )
142 }
143
144 #[verus_spec(res =>
146 with Tracked(owner): Tracked<&EntryOwner<C>>,
147 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
148 Tracked(regions): Tracked<&mut MetaRegionOwners>,
149 requires
150 self.invariants(*owner, *old(regions)),
151 self.node_matching(*owner, *parent_owner, *self.node),
152 parent_owner.metaregion_sound_node(*old(regions)),
153 ensures
154 res.invariants(*owner, *final(regions)),
155 final(regions).slot_owners == old(regions).slot_owners,
156 forall|k: int|
157 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
158 k,
159 ),
160 forall|k: int|
161 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
162 == #[trigger] final(regions).slots[k],
163 final(regions).inv(),
164 )]
165 pub(in crate::mm) fn to_ref(&self) -> ChildRef<'rcu, C> {
166 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
167 parent_owner.slot_index,
168 );
169 #[verus_spec(with Tracked(parent_meta_perm))]
170 let level = self.node.level();
171
172 let res = unsafe {
176 #[verus_spec(with Tracked(regions), Tracked(owner))]
177 ChildRef::from_pte(&self.pte, level)
178 };
179
180 res
181 }
182
183 #[verus_spec(
200 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
201 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
202 Tracked(regions): Tracked<&MetaRegionOwners>,
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 old(parent_owner).metaregion_sound_node(*regions),
212 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
218 #![auto]
219 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
220 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
221 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
222 #![auto]
223 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
224 ==> C::E::new_page_req(pa, level, p_out),
225 ensures
226 final(owner).inv(),
227 final(self).wf(*final(owner)),
228 final(self).node_matching(*final(owner), *final(parent_owner), *final(self).node),
229 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
230 final(owner).is_frame(),
231 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
232 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
233 final(owner).path == old(owner).path,
234 final(owner).parent_level == old(owner).parent_level,
235 final(self).idx == old(self).idx,
236 *final(self).node == *old(self).node,
237 old(self).pte.is_present() ==> op.ensures(
238 (old(owner).frame().prop,),
239 final(owner).frame().prop,
240 ),
241 crate::specs::mm::page_table::node::owners::count_present(
246 final(parent_owner).children_perm.value(),
247 ) == crate::specs::mm::page_table::node::owners::count_present(
248 old(parent_owner).children_perm.value(),
249 ),
250 final(parent_owner).meta_own.nr_children.value() == old(
251 parent_owner,
252 ).meta_own.nr_children.value(),
253 )]
254 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty) {
255 #[verus_spec(with Tracked(owner), Tracked(parent_owner), Tracked(regions))]
256 let pte = self.node.protect_child(self.idx, op);
257 self.pte = pte;
258 }
259
260 #[verus_spec(res =>
281 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
282 Tracked(owner): Tracked<&mut EntryOwner<C>>,
283 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
284 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
285 requires
286 old(self).invariants(*old(owner), *old(regions)),
287 new_child.invariants(*old(new_owner), *old(regions)),
288 old(self).node_matching(*old(owner), *old(parent_owner), *old(self).node),
289 old(self).new_owner_compatible(new_child, *old(owner), *old(new_owner), *old(regions)),
290 old(parent_owner).metaregion_sound_node(*old(regions)),
291 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
292 frame_to_index(meta_to_frame(node.ptr.addr())),
293 ) > 0,
294 ensures
295 final(self).invariants(*final(new_owner), *final(regions)),
296 res.invariants(*final(owner), *final(regions)),
297 final(self).node_matching(*final(new_owner), *final(parent_owner), *final(self).node),
298 final(self).idx == old(self).idx,
299 *final(self).node == *old(self).node,
300 *final(owner) == old(owner).from_pte_owner_spec(),
301 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
302 Self::metaregion_sound_neq_preserved(
303 *old(owner),
304 *final(new_owner),
305 *old(regions),
306 *final(regions),
307 ),
308 !final(new_owner).is_node() ==> Self::metaregion_sound_neq_old_preserved(
309 *old(owner),
310 *old(regions),
311 *final(regions),
312 ),
313 (!old(owner).is_node() && !final(new_owner).is_node())
314 ==> Self::metaregion_sound_preserved(*old(regions), *final(regions)),
315 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
316 C,
317 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
318 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
319 final(parent_owner).metaregion_sound_node(*final(regions)),
320 forall|idx: int|
322 #![trigger final(regions).slot_owners[idx].paths_in_pt]
323 (!final(new_owner).is_node() || final(new_owner).is_absent() || idx
324 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
325 ==> final(regions).slot_owners[idx].paths_in_pt == old(
326 regions,
327 ).slot_owners[idx].paths_in_pt,
328 forall|k: int|
330 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
331 k,
332 ),
333 forall|idx: int|
339 #![trigger final(regions).slot_owners[idx].inner_perms.ref_count.value()]
340 final(regions).slot_owners[idx].inner_perms.ref_count.value() == old(
341 regions,
342 ).slot_owners[idx].inner_perms.ref_count.value(),
343 forall|idx: int|
344 #![trigger final(regions).slot_owners[idx].inner_perms]
345 final(regions).slot_owners[idx].inner_perms == old(
346 regions,
347 ).slot_owners[idx].inner_perms,
348 final(regions).slots == old(regions).slots,
349 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
351 &&& final(regions).slots == old(regions).slots
352 &&& forall|i: int|
353 #![trigger final(regions).slot_owners[i]]
354 final(regions).slot_owners[i] == old(
355 regions,
356 ).slot_owners[i]
357 &&& final(regions).frame_obligations == old(regions).frame_obligations
363 },
364 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
366 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
367 == #[trigger] final(regions).slots[k],
368 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
369 )]
370 #[verifier::spinoff_prover]
371 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> Child<C> {
372 let ghost new_idx = frame_to_index(new_owner.meta_slot_paddr().unwrap());
373 let ghost cp0 = parent_owner.children_perm.value();
377
378 #[cfg(feature = "allow_panic")]
379 {
380 let guard_level = self.node.level();
381 match &new_child {
382 Child::PageTable(node) => {
383 assert!(node.level() == guard_level - 1);
384 },
385 Child::Frame(_, level, _) => {
386 assert!(*level == guard_level);
387 },
388 Child::None => {},
389 }
390 }
391
392 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
396 parent_owner.slot_index,
397 );
398 #[verus_spec(with Tracked(parent_meta_perm))]
399 let level = self.node.level();
400
401 let old_child = unsafe {
402 #[verus_spec(with Tracked(regions), Tracked(owner))]
403 Child::from_pte(self.pte, level)
404 };
405
406 if old_child.is_none() && !new_child.is_none() {
407 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
408 parent_owner.slot_index,
409 );
410 #[verus_spec(with Tracked(parent_meta_perm2))]
411 let nr_children = self.node.nr_children_mut();
412 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
413 proof {
414 parent_owner.nr_children_absent_slot_bound(self.idx);
415 }
416 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
417 } else if !old_child.is_none() && new_child.is_none() {
418 let tracked parent_meta_perm3 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
419 parent_owner.slot_index,
420 );
421 #[verus_spec(with Tracked(parent_meta_perm3))]
422 let nr_children = self.node.nr_children_mut();
423 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
424 proof {
425 parent_owner.nr_children_present_slot_bound(self.idx);
426 }
427 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
428 }
429 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
430 let new_pte = new_child.into_pte();
431
432 unsafe {
437 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
438 self.node.write_pte(self.idx, new_pte)
439 };
440
441 self.pte = new_pte;
442
443 proof {
444 if new_owner.is_node() {
451 let paddr = new_owner.meta_slot_paddr().unwrap();
452 regions.inv_implies_correct_addr(paddr);
453
454 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
455 new_meta_slot.paths_in_pt = set![new_owner.path];
456 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
457 }
458 }
459
460 proof {
461 if new_owner.is_node() || new_owner.is_frame() {
462 let paddr = new_owner.meta_slot_paddr().unwrap();
463 regions.inv_implies_correct_addr(paddr);
464 }
465 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
466 cp0,
467 NR_ENTRIES as int,
468 self.idx as int,
469 new_pte,
470 );
471 }
472
473 old_child
474 }
475
476 #[verus_spec(res =>
493 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
494 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
495 Tracked(regions): Tracked<&mut MetaRegionOwners>,
496 Tracked(guards): Tracked<&mut Guards<'rcu>>,
497 requires
498 old(self).invariants(old(owner).value(), *old(regions)),
499 old(owner).inv(),
500 old(self).node_matching(old(owner).value(), *old(parent_owner), *old(self).node),
501 old(owner).level() < INC_LEVELS - 1,
502 old(owner).level() + old(parent_owner).level == INC_LEVELS,
507 old(parent_owner).metaregion_sound_node(*old(regions)),
508 ensures
509 final(self).invariants(final(owner).value(), *final(regions)),
510 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner)),
511 final(self).idx == old(self).idx,
512 final(parent_owner).count_consistent(),
513 *final(self).node == *old(self).node,
514 old(owner).value().is_absent() && old(parent_owner).level > 1 ==> {
515 &&& final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node)
516 &&& final(owner).inv()
517 },
518 old(owner).value().is_absent() && old(parent_owner).level > 1 ==> {
519 &&& res is Some
520 &&& final(owner).value().is_node()
521 &&& final(owner).level() == old(owner).level()
522 &&& final(owner).value().parent_level == old(owner).value().parent_level
523 &&& final(guards).lock_held(final(owner).value().node().meta_vaddr())
524 &&& final(owner).value().node().relate_guard(res->0)
525 &&& final(owner).value().path == old(owner).value().path
526 &&& final(owner).value().metaregion_sound(*final(regions))
527 &&& OwnerSubtree::implies(
528 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
529 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr()))
530 &&& Self::metaregion_sound_neq_preserved(old(owner).value(), final(owner).value(), *old(regions), *final(regions))
531 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
532 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0))
533 &&& final(owner).subtree_satisfies(final(owner).value().path,
534 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr()))
535 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
536 &&& final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
537 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![]
538 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
540 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent()
541 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
548 (#[trigger] final(owner).children()[i])->0.value().path
549 == final(owner).value().path.push_tail(i)
550 &&& crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner))
554 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
556 (#[trigger] final(owner).child(i)).value().parent_level
557 == final(owner).value().node().level
558 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
559 (#[trigger] final(owner).child(i)).value().match_pte(
560 final(owner).value().node().children_perm.value()[i],
561 final(owner).child(i).value().parent_level)
562 &&& forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
564 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
565 &&& forall|i: int| old(regions).slots.contains_key(i)
567 ==> (#[trigger] final(regions).slots.contains_key(i))
568 &&& forall|i: int| #![trigger final(regions).slots[i]]
569 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
570 && old(regions).slots.contains_key(i)
571 ==> final(regions).slots[i] == old(regions).slots[i]
572 &&& final(regions).slot_owners[frame_to_index(final(owner).value().meta_slot_paddr()->0)]
574 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
575 &&& old(regions).slot_owners[frame_to_index(final(owner).value().meta_slot_paddr().unwrap())]
577 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
578 &&& !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
580 final(owner).value().meta_slot_paddr().unwrap())
581 },
582 !old(owner).value().is_absent() ==> {
583 &&& res is None
584 &&& *final(owner) == *old(owner)
585 },
586 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
587 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().meta_vaddr() ==> final(guards).unlocked(i),
588 )]
589 #[verifier::spinoff_prover]
590 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
591 PageTableGuard<'rcu, C>,
592 > {
593 let entry_is_present = self.pte.is_present();
594 let ghost cp0 = parent_owner.children_perm.value();
596
597 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
598 parent_owner.slot_index,
599 );
600 #[verus_spec(with Tracked(parent_meta_perm))]
601 let level = self.node.level();
602
603 if entry_is_present || level <= 1 {
604 None
605 } else {
606 let ghost old_path = owner.value().path;
607 let ghost old_owner_val = owner.value();
608
609 proof {
610 parent_owner.nr_children_absent_slot_bound(self.idx);
611 }
612
613 let ghost regions_pre = *regions;
620 let ghost pre_meta_perm = parent_owner.meta_perm_of(*regions);
621
622 proof_decl! {
623 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
624 }
625
626 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
627 let new_page = PageTableNode::<C>::alloc(level - 1);
628 let ghost fresh_children = new_node_owner.children();
629 proof {
630 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
631 #[trigger] fresh_children[i]) is Some by {
632 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
633 new_node_owner,
634 (level - 1) as PagingLevel,
635 ));
636 assert(new_node_owner.has_child(i));
637 };
638 }
639
640 proof {
641 let pte = C::E::new_pt_spec(
642 meta_to_frame(new_node_owner.value().node().meta_vaddr()),
643 );
644 C::E::lemma_page_table_entry_properties();
645 }
646
647 let ghost new_node_slot_idx = new_node_owner.value().node().slot_index;
648 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
649 #[verus_spec(with Tracked(new_node_slot_perm))]
650 let paddr = new_page.start_paddr();
651
652 let new_pte = {
653 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
654 #[verus_spec(with Tracked(new_node_value), Tracked(regions))]
655 Child::PageTable(new_page).into_pte()
656 };
657 self.pte = new_pte;
658
659 let pt_ref = unsafe {
660 #[verus_spec(with Tracked(regions))]
661 PageTableNodeRef::borrow_paddr(paddr)
662 };
663
664 let mut pt_lock_guard = {
666 let tracked new_node_value = new_node_owner.tracked_borrow_value();
667 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
668 pt_ref.lock(guard)
669 };
670
671 unsafe {
676 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
677 self.node.write_pte(self.idx, self.pte)
678 };
679
680 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
681 parent_owner.slot_index,
682 );
683 #[verus_spec(with Tracked(parent_meta_perm2))]
684 let nr_children = self.node.nr_children_mut();
685 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
686 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
687
688 proof {
689 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
696 new_node_value.parent_level = level as PagingLevel;
697 new_node_value.path = old_path;
698 *owner = new_node_owner;
699 assert(owner.children() == fresh_children);
703 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
704 #[trigger] owner.children()[i]) is Some by {};
705 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
706
707 let new_paddr = owner.value().meta_slot_paddr().unwrap();
708 regions.inv_implies_correct_addr(new_paddr);
709 let new_idx = frame_to_index(new_paddr);
710 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
711 new_meta_slot.paths_in_pt = set![owner.value().path];
712 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
713
714 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
718 cp0,
719 NR_ENTRIES as int,
720 self.idx as int,
721 self.pte,
722 );
723
724 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
728 let ghost new_node_addr = owner.value().node().meta_vaddr();
736 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
737 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
738 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
739
740 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
741 *owner,
742 owner.value().path,
743 f_nu,
744 );
745 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
746 *owner,
747 owner.value().path,
748 f_ms,
749 );
750 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
751 *owner,
752 owner.value().path,
753 f_pt,
754 );
755 }
756
757 Some(pt_lock_guard)
758 }
759 }
760
761 #[verifier::spinoff_prover]
777 #[verifier::rlimit(infinity)]
778 #[verus_spec(res =>
779 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
780 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
781 Tracked(regions): Tracked<&mut MetaRegionOwners>,
782 Tracked(guards): Tracked<&mut Guards<'rcu>>
783 requires
784 old(regions).inv(),
785 old(owner).inv(),
786 old(self).wf(old(owner).value()),
787 old(parent_owner).relate_guard(*old(self).node),
788 old(parent_owner).inv(),
789 old(parent_owner).level == old(owner).value().parent_level,
790 old(parent_owner).level < NR_LEVELS,
791 old(parent_owner).metaregion_sound_node(*old(regions)),
792 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
798 old(owner).value().metaregion_sound(*old(regions)),
799 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
803 forall |j: usize| #![trigger frame_to_index(
804 (old(owner).value().frame().mapped_pa
805 + j * PAGE_SIZE) as usize)]
806 0 < j < page_size(old(parent_owner).level) / PAGE_SIZE ==> {
807 let sub_idx = frame_to_index(
808 (old(owner).value().frame().mapped_pa
809 + j * PAGE_SIZE) as usize);
810 &&& old(regions).slots.contains_key(sub_idx)
811 &&& old(regions).slot_owners[sub_idx].usage !is MMIO ==>
812 old(regions).slot_owners[sub_idx].inner_perms.ref_count.value()
813 != REF_COUNT_UNUSED
814 },
815 ensures
816 old(owner).value().is_frame() && old(parent_owner).level > 1 ==> {
817 &&& res is Some
818 &&& final(owner).value().is_node()
819 &&& final(owner).level() == old(owner).level()
820 &&& final(parent_owner).relate_guard(*final(self).node)
821 &&& final(owner).value().node().relate_guard(res->0)
822 &&& final(owner).value().node().meta_vaddr() == res->0.inner.inner@.ptr.addr()
823 &&& final(guards).lock_held(res->0.inner.inner@.ptr.addr())
824 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
826 (#[trigger] final(owner).children()[j])->0.value().is_frame()
827 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
828 (#[trigger] final(owner).children()[j])->0.value().frame().prop
829 == old(owner).value().frame().prop
830 &&& final(owner).value().path == old(owner).value().path
831 &&& final(owner).value().metaregion_sound(*final(regions))
832 &&& OwnerSubtree::implies(
833 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
834 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
835 &&& OwnerSubtree::implies(
836 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
837 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
838 &&& final(owner).subtree_satisfies(final(owner).value().path,
839 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
840 &&& final(owner).subtree_satisfies(final(owner).value().path,
841 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
842 },
843 !old(owner).value().is_frame() || old(parent_owner).level <= 1 ==> {
844 &&& res is None
845 &&& *final(owner) == *old(owner)
846 },
847 final(owner).inv(),
848 final(owner).value().parent_level == old(owner).value().parent_level,
849 final(self).idx == old(self).idx,
850 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
851 final(self).node_matching(final(owner).value(), *final(parent_owner), *final(self).node),
852 final(regions).inv(),
853 final(parent_owner).inv(),
854 final(parent_owner).level == old(parent_owner).level,
855 final(self).node.inner.inner@.ptr.addr() == old(self).node.inner.inner@.ptr.addr(),
856 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
857 forall |i: usize| old(guards).unlocked(i) ==> final(guards).unlocked(i),
858 old(owner).value().is_frame() && old(parent_owner).level > 1 ==> {
860 &&& forall|i: int| i != frame_to_index(meta_to_frame(final(owner).value().node().meta_vaddr())) ==>
861 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
862 &&& forall|i: int| old(regions).slots.contains_key(i)
864 ==> (#[trigger] final(regions).slots.contains_key(i))
865 &&& final(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value().node().meta_vaddr()))]
867 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
868 &&& old(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value().node().meta_vaddr()))]
870 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
871 },
872 old(owner).value().is_frame() && old(parent_owner).level > 1 ==>
877 forall|j: int| 0 <= j < NR_ENTRIES && j != old(self).idx ==>
878 #[trigger] final(parent_owner).children_perm.value()[j]
879 == old(parent_owner).children_perm.value()[j],
880 )]
881 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A) -> Option<
882 PageTableGuard<'rcu, C>,
883 > {
884 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
885 parent_owner.slot_index,
886 );
887 #[verus_spec(with Tracked(parent_meta_perm))]
888 let level = self.node.level();
889
890 if !(self.pte.is_last(level) && level > 1) {
891 return None;
892 }
893 let pa = self.pte.paddr();
894 let prop = self.pte.prop();
895
896 proof {
897 EntryOwner::last_pte_implies_frame_match(owner.value(), self.pte, level);
898 }
899
900 proof_decl!{
901 let tracked mut new_owner: OwnerSubtree<C>;
902 }
903
904 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
907 let new_page = PageTableNode::<C>::alloc(level - 1);
908 proof {
909 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
910 #[trigger] new_owner.children()[i]) is Some by {
911 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
912 new_owner,
913 (level - 1) as PagingLevel,
914 ));
915 assert(new_owner.has_child(i));
916 };
917 }
918
919 let ghost new_owner_slot_idx = new_owner.value().node().slot_index;
920 let tracked new_owner_slot_perm = regions.slots.tracked_borrow(new_owner_slot_idx);
921 #[verus_spec(with Tracked(new_owner_slot_perm))]
922 let paddr = new_page.start_paddr();
923
924 proof {
925 broadcast use group_page_meta;
926
927 }
928
929 let pt_ref = unsafe {
930 #[verus_spec(with Tracked(regions))]
931 PageTableNodeRef::borrow_paddr(paddr)
932 };
933
934 let mut pt_lock_guard = {
936 let tracked new_owner_value = new_owner.tracked_borrow_value();
937 #[verus_spec(with Tracked(new_owner_value.tracked_borrow_node()), Tracked(guards))]
938 pt_ref.lock(guard)
939 };
940
941 let ghost children_perm = new_owner.value().node().children_perm;
942 let ghost new_owner_path = new_owner.value().path;
943 let ghost new_owner_meta_addr = new_owner.value().node().meta_vaddr();
944
945 proof {
946 broadcast use crate::specs::mm::frame::mapping::lemma_frame_to_index_injective;
958 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
959 broadcast use group_page_meta;
960
961 let new_idx = frame_to_index(meta_to_frame(new_owner_meta_addr));
962 let new_paddr = meta_to_frame(new_owner_meta_addr);
963 let nr_pages = page_size(level) / PAGE_SIZE;
964
965 let pa_idx = frame_to_index(pa);
969 assert(pa_idx != new_idx) by {
970 if old(regions).slot_owners[pa_idx].usage
971 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
972 old(regions).inv_implies_correct_addr(pa);
973 } else {
974 }
976 };
977
978 assert forall|j: usize|
980 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
981 0 < j < nr_pages implies {
982 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
983 &&& regions.slots.contains_key(sub_idx)
984 &&& regions.slot_owners[sub_idx].usage
985 != crate::specs::mm::frame::meta_owners::PageUsage::PageTable
986 &&& regions.slot_owners[sub_idx].usage
987 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
988 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
989 != REF_COUNT_UNUSED
990 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
991 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
992 }
993 } by {
994 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
995 assert(sub_idx != new_idx) by {
996 if old(regions).slot_owners[sub_idx].usage
997 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO {
998 old(regions).inv_implies_correct_addr((pa + j * PAGE_SIZE) as usize);
999 } else {
1000 }
1002 };
1003 };
1004 }
1005
1006 proof {
1007 C::lemma_paging_consts_properties();
1008 assert(nr_subpage_per_huge_spec::<C>() == NR_ENTRIES);
1009 }
1010
1011 for i in 0..nr_subpage_per_huge::<C>()
1012 invariant
1013 nr_subpage_per_huge_spec::<C>() == NR_ENTRIES,
1014 1 < level < NR_LEVELS,
1015 owner.inv(),
1016 owner.value().is_frame(),
1017 owner.value().parent_level == level,
1018 owner.value().frame().mapped_pa == pa,
1019 owner.value().frame().prop == prop,
1020 pa == old(owner).value().frame().mapped_pa,
1021 level == old(parent_owner).level,
1022 pa % page_size(level) == 0,
1023 pa + page_size(level) <= MAX_PADDR,
1024 regions.inv(),
1025 regions.frame_obligations.count(frame_to_index(meta_to_frame(new_owner_meta_addr)))
1030 > 0,
1031 parent_owner.inv(),
1032 new_owner.value().is_node(),
1033 new_owner.inv(),
1034 new_owner.value().path == new_owner_path,
1035 new_owner.value().node().meta_vaddr() == new_owner_meta_addr,
1036 new_owner.value().node().relate_guard(pt_lock_guard),
1037 guards.lock_held(new_owner_meta_addr),
1038 new_owner.value().node().level == (level - 1) as PagingLevel,
1039 forall|j: int| 0 <= j < NR_ENTRIES ==> (#[trigger] new_owner.children()[j]) is Some,
1040 forall|j: int|
1041 0 <= j < NR_ENTRIES ==> {
1042 &&& (#[trigger] new_owner.children()[j]) is Some
1043 &&& new_owner.children()[j].unwrap().value().match_pte(
1044 new_owner.value().node().children_perm.value()[j],
1045 new_owner.value().node().level,
1046 )
1047 &&& new_owner.children()[j].unwrap().value().parent_level
1048 == new_owner.value().node().level
1049 &&& new_owner.children()[j].unwrap().value().inv()
1050 &&& new_owner.children()[j].unwrap().value().path
1051 == new_owner_path.push_tail(j)
1052 },
1053 forall|j: int|
1054 i <= j < NR_ENTRIES ==> {
1055 &&& (#[trigger] new_owner.children()[j]) is Some
1056 &&& new_owner.children()[j].unwrap().value().is_absent()
1057 &&& new_owner.value().node().children_perm.value()[j]
1058 == C::E::new_absent_spec()
1059 },
1060 forall|j: int|
1062 0 <= j < i ==> {
1063 &&& (#[trigger] new_owner.children()[j]) is Some
1064 &&& new_owner.children()[j].unwrap().value().is_frame()
1065 },
1066 forall|j: usize|
1070 #![trigger frame_to_index(
1071 (pa + j * PAGE_SIZE) as usize)]
1072 0 < j < page_size(level) / PAGE_SIZE ==> {
1073 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
1074 &&& regions.slots.contains_key(sub_idx)
1075 &&& regions.slot_owners[sub_idx].usage !is PageTable
1076 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1077 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1078 != REF_COUNT_UNUSED
1079 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1080 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1081 <= REF_COUNT_MAX
1082 }
1083 },
1084 regions.slots.contains_key(frame_to_index(pa)),
1086 regions.slot_owners[frame_to_index(pa)].usage !is PageTable,
1087 regions.slot_owners[frame_to_index(pa)].usage !is MMIO ==> {
1088 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
1089 != REF_COUNT_UNUSED
1090 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value() > 0
1091 &&& regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
1092 <= REF_COUNT_MAX
1093 },
1094 new_page.ptr.addr() == new_owner_meta_addr,
1095 new_owner.value().node().metaregion_sound_node(*regions),
1096 regions.slot_owners[frame_to_index(
1101 meta_to_frame(new_owner_meta_addr),
1102 )].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
1103 0 < regions.slot_owners[frame_to_index(
1104 meta_to_frame(new_owner_meta_addr),
1105 )].inner_perms.ref_count.value() <= REF_COUNT_MAX,
1106 regions.slot_owners[frame_to_index(meta_to_frame(new_owner_meta_addr))].paths_in_pt
1107 == set![new_owner_path],
1108 {
1109 proof {
1110 C::lemma_page_table_config_constant_properties();
1111 C::lemma_paging_consts_properties();
1112 let ghost the_node = new_owner.value().node();
1114
1115 assert(0 <= i < NR_ENTRIES);
1116 assert(new_owner.has_child(i as int));
1117 assert(new_owner.inv_children());
1118 assert(new_owner.child(i as int).inv());
1119 assert(new_owner.child(i as int).level() == new_owner.level() + 1);
1120 EntryOwner::huge_frame_split_child_at(owner.value(), *regions, i as usize);
1121 }
1122
1123 let small_pa = pa + i * page_size(level - 1);
1124
1125 let tracked mut child_owner = EntryOwner::tracked_new_frame(
1126 small_pa,
1127 new_owner.value().path.push_tail(i as int),
1128 (level - 1) as PagingLevel,
1129 prop,
1130 );
1131
1132 let ghost new_owner_before_update = new_owner;
1133 let tracked mut new_owner_node = {
1136 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1137 new_owner_value.tracked_take_node()
1138 };
1139 let tracked mut new_owner_child = new_owner.tracked_borrow_mut_child(i as int);
1140 let ghost new_owner_child_before_update = *new_owner_child;
1141
1142 proof {
1143 let idx = frame_to_index(small_pa);
1144 if i != 0 {
1145 let ghost big_j =
1146 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1147 pa, level, i);
1148 }
1149 if level - 1 > 1 {
1150 let nr_subpages = page_size((level - 1) as PagingLevel) / PAGE_SIZE;
1151 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1152 (level - 1) as PagingLevel);
1153 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
1154 level);
1155 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_nr_entries_times_sub_page_size(
1156 level);
1157 assert forall|j_prime: usize|
1158 #![trigger frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize)]
1159 0 < j_prime < nr_subpages implies {
1160 let sub_idx = frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize);
1161 &&& regions.slots.contains_key(sub_idx)
1162 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
1163 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1164 != REF_COUNT_UNUSED
1165 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
1166 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
1167 <= REF_COUNT_MAX
1168 }
1169 } by {
1170 let sub_pages_per_subframe = page_size((level - 1) as PagingLevel)
1171 / PAGE_SIZE;
1172 let big_j_int: int = i * sub_pages_per_subframe + j_prime;
1173 vstd::arithmetic::mul::lemma_mul_nonnegative(
1174 i as int,
1175 sub_pages_per_subframe as int,
1176 );
1177 vstd::arithmetic::mul::lemma_mul_inequality(
1178 i + 1,
1179 NR_ENTRIES as int,
1180 sub_pages_per_subframe as int,
1181 );
1182 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1183 sub_pages_per_subframe as int,
1184 i as int,
1185 1int,
1186 );
1187 vstd::arithmetic::mul::lemma_mul_is_associative(
1188 NR_ENTRIES as int,
1189 sub_pages_per_subframe as int,
1190 PAGE_SIZE as int,
1191 );
1192 vstd::arithmetic::div_mod::lemma_div_by_multiple(
1193 NR_ENTRIES * sub_pages_per_subframe,
1194 PAGE_SIZE as int,
1195 );
1196 let big_j: usize = big_j_int as usize;
1197 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
1198 PAGE_SIZE as int,
1199 i * sub_pages_per_subframe,
1200 j_prime as int,
1201 );
1202 vstd::arithmetic::mul::lemma_mul_is_associative(
1203 i as int,
1204 sub_pages_per_subframe as int,
1205 PAGE_SIZE as int,
1206 );
1207 assert((small_pa + j_prime * PAGE_SIZE) as usize == (pa + big_j
1208 * PAGE_SIZE) as usize);
1209 assert(regions.slots.contains_key(
1215 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1216 ));
1217 }
1218 }
1219 let small_idx = frame_to_index(small_pa);
1220
1221 if i == 0 {
1226 assert(i * page_size((level - 1) as PagingLevel) == 0) by {
1228 vstd::arithmetic::mul::lemma_mul_by_zero_is_zero(
1229 page_size((level - 1) as PagingLevel) as int,
1230 );
1231 }
1232 } else {
1233 let ghost big_j =
1234 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1235 pa, level, i);
1236 assert(regions.slots.contains_key(
1238 frame_to_index((pa + big_j * PAGE_SIZE) as usize),
1239 ));
1240 }
1241
1242 regions.inv_implies_correct_addr(small_pa);
1245 let tracked mut small_slot = regions.slot_owners.tracked_remove(small_idx);
1246 small_slot.paths_in_pt = small_slot.paths_in_pt.insert(child_owner.path);
1247 regions.slot_owners.tracked_insert(small_idx, small_slot);
1248
1249 if (level - 1) > 1 {
1252 }
1253 let ghost target_idx = frame_to_index(small_pa);
1254 if i != 0 {
1255 let ghost _ =
1256 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_split_sub_page_big_j(
1257 pa, level, i);
1258
1259 }
1260 C::lemma_raw_item_well_formed_split(pa, level, prop, small_pa, i);
1261 }
1262
1263 let ghost nidx = frame_to_index(meta_to_frame(new_owner_meta_addr));
1267 proof {
1268 }
1272 let ghost regions_pre_replace = *regions;
1273 {
1274 let tracked new_owner_child_value = new_owner_child.tracked_borrow_mut_value();
1275 #[verus_spec(with Tracked(regions),
1276 Tracked(new_owner_child_value),
1277 Tracked(&mut child_owner),
1278 Tracked(&mut new_owner_node))]
1279 pt_lock_guard.replace_absent_with_frame(i, small_pa, level - 1, prop);
1280
1281 proof {
1282 *new_owner_child_value = child_owner;
1283 }
1284 }
1285
1286 proof {
1287 new_owner_child_before_update.lemma_set_value_observable_fields(child_owner);
1288 OwnerSubtree::lemma_ext_equal(
1289 *new_owner_child,
1290 new_owner_child_before_update.set_value(child_owner),
1291 );
1292 assert(new_owner_child.inv());
1293
1294 {
1295 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1296 new_owner_value.tracked_put_node(new_owner_node);
1297 }
1298
1299 let owner_with_updated_value = new_owner_before_update.set_value(new_owner.value());
1300 vstd::seq_lib::lemma_update_is_remove_insert(
1301 new_owner_before_update.children(),
1302 i as int,
1303 Some(*new_owner_child),
1304 );
1305 assert(new_owner.children() == new_owner_before_update.children().remove(
1306 i as int,
1307 ).insert(i as int, Some(*new_owner_child)));
1308 assert(owner_with_updated_value.insert(i as int, *new_owner_child).children()
1309 == new_owner_before_update.children().update(i as int, Some(*new_owner_child)));
1310 assert(new_owner.children() =~= owner_with_updated_value.insert(
1311 i as int,
1312 *new_owner_child,
1313 ).children());
1314 assert(new_owner.children() == owner_with_updated_value.insert(
1315 i as int,
1316 *new_owner_child,
1317 ).children());
1318 OwnerSubtree::lemma_ext_equal(
1319 new_owner,
1320 owner_with_updated_value.insert(i as int, *new_owner_child),
1321 );
1322 assert forall|j: int| 0 <= j < NR_ENTRIES implies (
1323 #[trigger] new_owner.children()[j]) is Some by {
1324 if j != i {
1325 assert(owner_with_updated_value.insert(
1326 i as int,
1327 *new_owner_child,
1328 ).children()[j] == owner_with_updated_value.children()[j]);
1329 }
1330 };
1331 assert(new_owner.inv());
1332
1333 }
1339 }
1340
1341 proof {
1342 }
1347 self.pte = {
1348 let tracked new_owner_value = new_owner.tracked_borrow_mut_value();
1349 #[verus_spec(with Tracked(new_owner_value), Tracked(regions))]
1350 Child::PageTable(new_page).into_pte()
1351 };
1352
1353 proof {
1354 *owner = new_owner;
1355 }
1356
1357 unsafe {
1362 let tracked owner_value = owner.tracked_borrow_mut_value();
1363 #[verus_spec(with Tracked(owner_value.tracked_borrow_mut_node()), Tracked(&*regions))]
1364 self.node.write_pte(self.idx, self.pte)
1365 };
1366
1367 Some(pt_lock_guard)
1368 }
1369
1370 #[verus_spec(res =>
1386 with Tracked(owner): Tracked<&EntryOwner<C>>,
1387 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1388 Tracked(regions): Tracked<&MetaRegionOwners>,
1389 requires
1390 owner.inv(),
1391 parent_owner.inv(),
1392 parent_owner.relate_guard(*guard),
1393 idx < NR_ENTRIES,
1394 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1395 regions.inv(),
1396 regions.slots.contains_key(parent_owner.slot_index),
1397 ensures
1398 res.wf(*owner),
1399 res.idx == idx,
1400 parent_owner.relate_guard(*res.node),
1401 *res.node == *old(guard),
1404 *final(guard) == *final(res.node),
1405 )]
1406 pub(in crate::mm) unsafe fn new_at(guard: &'a mut PageTableGuard<'rcu, C>, idx: usize) -> Self {
1407 let pte = unsafe {
1409 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1410 guard.read_pte(idx)
1411 };
1412 Self::new(pte, idx, guard)
1413 }
1414}
1415
1416#[verus_verify]
1417impl<'rcu, C: PageTableConfig> PageTableGuard<'rcu, C> {
1418 #[verus_spec(res =>
1419 with Tracked(owner): Tracked<&mut EntryOwner<C>>,
1420 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1421 Tracked(regions): Tracked<&MetaRegionOwners>,
1422 requires
1423 old(owner).inv(),
1424 old(owner).is_frame(),
1425 old(owner).match_pte(
1426 old(parent_owner).children_perm.value()[idx as int],
1427 old(owner).parent_level,
1428 ),
1429 old(parent_owner).inv(),
1430 old(parent_owner).relate_guard(*old(self)),
1431 old(parent_owner).level == old(owner).parent_level,
1432 old(parent_owner).metaregion_sound_node(*regions),
1433 idx < NR_ENTRIES,
1434 op.requires((old(owner).frame().prop,)),
1435 regions.inv(),
1436 regions.slots.contains_key(old(parent_owner).slot_index),
1437 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1438 #![auto]
1439 op.ensures((p_in,), p_out) ==> C::tracked(C::item_from_raw_spec(pa, level, p_out))
1440 == C::tracked(C::item_from_raw_spec(pa, level, p_in)),
1441 forall|pa: Paddr, level: PagingLevel, p_in: PageProperty, p_out: PageProperty|
1442 #![auto]
1443 op.ensures((p_in,), p_out) && C::E::new_page_req(pa, level, p_in)
1444 ==> C::E::new_page_req(pa, level, p_out),
1445 ensures
1446 final(owner).inv(),
1447 final(owner).is_frame(),
1448 final(owner).match_pte(res, final(parent_owner).level),
1449 final(owner).match_pte(
1450 final(parent_owner).children_perm.value()[idx as int],
1451 final(parent_owner).level,
1452 ),
1453 res == final(parent_owner).children_perm.value()[idx as int],
1454 final(parent_owner).inv(),
1455 final(parent_owner).slot_index == old(parent_owner).slot_index,
1456 final(parent_owner).level == old(parent_owner).level,
1457 final(parent_owner).tree_level == old(parent_owner).tree_level,
1458 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
1459 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
1460 final(parent_owner).relate_guard(*final(self)),
1461 final(parent_owner).metaregion_sound_node(*regions),
1462 final(owner).frame().mapped_pa == old(owner).frame().mapped_pa,
1463 final(owner).frame_is_tracked() == old(owner).frame_is_tracked(),
1464 final(owner).path == old(owner).path,
1465 final(owner).parent_level == old(owner).parent_level,
1466 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1467 #[trigger] final(parent_owner).children_perm.value()[j]
1468 == old(parent_owner).children_perm.value()[j],
1469 crate::specs::mm::page_table::node::owners::count_present(
1472 final(parent_owner).children_perm.value(),
1473 ) == crate::specs::mm::page_table::node::owners::count_present(
1474 old(parent_owner).children_perm.value(),
1475 ),
1476 op.ensures((old(owner).frame().prop,), final(owner).frame().prop),
1477 *final(self) == *old(self),
1478 )]
1479 pub(in crate::mm) fn protect_child(
1480 &mut self,
1481 idx: usize,
1482 op: impl FnOnce(PageProperty) -> PageProperty,
1483 ) -> C::E {
1484 let ghost cp_old = parent_owner.children_perm.value();
1485 let mut pte = unsafe {
1486 #[verus_spec(with Tracked(&*parent_owner), Tracked(regions))]
1487 self.read_pte(idx)
1488 };
1489
1490 let prop = pte.prop();
1491 let new_prop = op(prop);
1492
1493 proof {
1494 assert(owner.frame().prop == prop);
1495 assert(op.ensures((prop,), new_prop));
1496 C::lemma_raw_item_well_formed_preserved(
1497 owner.frame().mapped_pa,
1498 owner.parent_level,
1499 prop,
1500 new_prop,
1501 );
1502 }
1503
1504 assume(pte.set_prop_req(new_prop));
1505 pte.set_prop(new_prop);
1506
1507 unsafe {
1508 #[verus_spec(with Tracked(parent_owner), Tracked(regions))]
1509 self.write_pte(idx, pte)
1510 };
1511
1512 proof {
1513 owner.tracked_set_frame_prop(new_prop);
1514 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1518 cp_old,
1519 NR_ENTRIES as int,
1520 idx as int,
1521 pte,
1522 );
1523 }
1524
1525 pte
1526 }
1527
1528 #[verifier::spinoff_prover]
1529 #[verus_spec(res =>
1530 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
1531 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1532 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1533 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1534 requires
1535 old(owner).inv(),
1536 old(owner).metaregion_sound(*old(regions)),
1537 old(owner).match_pte(
1538 old(parent_owner).children_perm.value()[idx as int],
1539 old(owner).parent_level,
1540 ),
1541 old(parent_owner).inv(),
1542 old(parent_owner).relate_guard(*old(self)),
1543 old(parent_owner).level == old(owner).parent_level,
1544 idx < NR_ENTRIES,
1545 old(regions).inv(),
1546 old(regions).slots.contains_key(old(parent_owner).slot_index),
1547 new_child.invariants(*old(new_owner), *old(regions)),
1548 old(owner).path == old(new_owner).path,
1549 old(owner).parent_level == old(new_owner).parent_level,
1550 old(new_owner).is_node() ==> {
1551 &&& old(regions).slots.contains_key(frame_to_index(old(new_owner).meta_slot_paddr()->0))
1552 &&& old(regions).slot_owners[frame_to_index(
1553 old(new_owner).meta_slot_paddr()->0,
1554 )].inner_perms.ref_count.value() != REF_COUNT_UNUSED
1555 },
1556 old(parent_owner).metaregion_sound_node(*old(regions)),
1557 new_child matches Child::PageTable(node) ==> old(regions).frame_obligations.count(
1558 frame_to_index(meta_to_frame(node.ptr.addr())),
1559 ) > 0,
1560 ensures
1561 res.invariants(*final(owner), *final(regions)),
1562 final(new_owner).inv(),
1563 final(new_owner).metaregion_sound(*final(regions)),
1564 final(new_owner).match_pte(
1565 final(parent_owner).children_perm.value()[idx as int],
1566 final(parent_owner).level,
1567 ),
1568 final(new_owner).path == old(new_owner).path,
1569 final(new_owner).parent_level == old(new_owner).parent_level,
1570 *final(owner) == old(owner).from_pte_owner_spec(),
1571 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
1572 Entry::<C>::metaregion_sound_neq_preserved(
1573 *old(owner),
1574 *final(new_owner),
1575 *old(regions),
1576 *final(regions),
1577 ),
1578 !final(new_owner).is_node() ==> Entry::<C>::metaregion_sound_neq_old_preserved(
1579 *old(owner),
1580 *old(regions),
1581 *final(regions),
1582 ),
1583 (!old(owner).is_node() && !final(new_owner).is_node())
1584 ==> Entry::<C>::metaregion_sound_preserved(*old(regions), *final(regions)),
1585 final(new_owner).is_node() && !final(new_owner).is_absent() ==> PageTableOwner::<
1586 C,
1587 >::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
1588 final(parent_owner).inv(),
1589 final(parent_owner).level == old(parent_owner).level,
1590 final(parent_owner).relate_guard(*final(self)),
1591 final(parent_owner).metaregion_sound_node(*final(regions)),
1592 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1593 #[trigger] final(parent_owner).children_perm.value()[j]
1594 == old(parent_owner).children_perm.value()[j],
1595 forall|slot: int|
1596 #![trigger final(regions).slot_owners[slot].paths_in_pt]
1597 (!final(new_owner).is_node() || final(new_owner).is_absent() || slot
1598 != frame_to_index(final(new_owner).meta_slot_paddr()->0))
1599 ==> final(regions).slot_owners[slot].paths_in_pt == old(
1600 regions,
1601 ).slot_owners[slot].paths_in_pt,
1602 forall|k: int|
1603 old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(
1604 k,
1605 ),
1606 forall|slot: int|
1607 #![trigger final(regions).slot_owners[slot].inner_perms.ref_count.value()]
1608 final(regions).slot_owners[slot].inner_perms.ref_count.value() == old(
1609 regions,
1610 ).slot_owners[slot].inner_perms.ref_count.value(),
1611 forall|slot: int|
1612 #![trigger final(regions).slot_owners[slot].inner_perms]
1613 final(regions).slot_owners[slot].inner_perms == old(
1614 regions,
1615 ).slot_owners[slot].inner_perms,
1616 final(regions).slots == old(regions).slots,
1617 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
1618 &&& final(regions).slots == old(regions).slots
1619 &&& forall|i: int|
1620 #![trigger final(regions).slot_owners[i]]
1621 final(regions).slot_owners[i] == old(
1622 regions,
1623 ).slot_owners[i]
1624 &&& final(regions).frame_obligations == old(regions).frame_obligations
1625 },
1626 (old(owner).is_absent() && !final(new_owner).is_node()) ==> forall|k: int|
1627 old(regions).slots.contains_key(k) ==> old(regions).slots[k]
1628 == #[trigger] final(regions).slots[k],
1629 Entry::<C>::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
1630 *final(self) == *old(self),
1631 )]
1632 #[verifier::spinoff_prover]
1633 pub(in crate::mm) fn replace_child(&mut self, idx: usize, new_child: Child<C>) -> Child<C> {
1634 #[cfg(feature = "allow_panic")]
1635 {
1636 let guard_level = self.level();
1637 match &new_child {
1638 Child::PageTable(node) => {
1639 assert!(node.level() == guard_level - 1);
1640 },
1641 Child::Frame(_, level, _) => {
1642 assert!(*level == guard_level);
1643 },
1644 Child::None => {},
1645 }
1646 }
1647
1648 let pte = unsafe {
1649 #[verus_spec(with Tracked(&*parent_owner), Tracked(&*regions))]
1650 self.read_pte(idx)
1651 };
1652
1653 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1654 parent_owner.slot_index,
1655 );
1656 #[verus_spec(with Tracked(parent_meta_perm))]
1657 let level = self.level();
1658
1659 let old_child = unsafe {
1660 #[verus_spec(with Tracked(regions), Tracked(owner))]
1661 Child::from_pte(pte, level)
1662 };
1663
1664 let ghost cp0 = parent_owner.children_perm.value();
1666
1667 if old_child.is_none() && !new_child.is_none() {
1668 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1669 parent_owner.slot_index,
1670 );
1671 #[verus_spec(with Tracked(parent_meta_perm2))]
1672 let nr_children = self.nr_children_mut();
1673 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1674 proof {
1675 parent_owner.nr_children_absent_slot_bound(idx);
1676 }
1677 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
1678 } else if !old_child.is_none() && new_child.is_none() {
1679 let tracked parent_meta_perm3 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1680 parent_owner.slot_index,
1681 );
1682 #[verus_spec(with Tracked(parent_meta_perm3))]
1683 let nr_children = self.nr_children_mut();
1684 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1685 proof {
1686 parent_owner.nr_children_present_slot_bound(idx);
1687 }
1688 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
1689 }
1690 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
1691 let new_pte = new_child.into_pte();
1692
1693 unsafe {
1694 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1695 self.write_pte(idx, new_pte)
1696 };
1697
1698 proof {
1699 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1704 cp0,
1705 NR_ENTRIES as int,
1706 idx as int,
1707 new_pte,
1708 );
1709 }
1710
1711 proof {
1712 if new_owner.is_node() {
1713 let paddr = new_owner.meta_slot_paddr().unwrap();
1714 regions.inv_implies_correct_addr(paddr);
1715
1716 let new_idx = frame_to_index(new_owner.meta_slot_paddr().unwrap());
1717 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
1718 new_meta_slot.paths_in_pt = set![new_owner.path];
1719 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
1720 }
1721 }
1722
1723 proof {
1724 if new_owner.is_node() || new_owner.is_frame() {
1725 let paddr = new_owner.meta_slot_paddr().unwrap();
1726 regions.inv_implies_correct_addr(paddr);
1727 }
1728 }
1729
1730 old_child
1731 }
1732
1733 #[verifier::spinoff_prover]
1734 #[verus_spec(res =>
1735 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
1736 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
1737 Tracked(regions): Tracked<&mut MetaRegionOwners>,
1738 Tracked(guards): Tracked<&mut Guards<'rcu>>,
1739 requires
1740 old(owner).inv(),
1741 old(owner).value().is_absent(),
1742 old(owner).level() < INC_LEVELS - 1,
1743 old(owner).value().metaregion_sound(*old(regions)),
1744 old(parent_owner).inv(),
1745 old(parent_owner).relate_guard(*old(self)),
1746 old(parent_owner).level == old(owner).value().parent_level,
1747 old(parent_owner).level > 1,
1748 old(parent_owner).metaregion_sound_node(*old(regions)),
1749 idx < NR_ENTRIES,
1750 old(owner).value().match_pte(
1751 old(parent_owner).children_perm.value()[idx as int],
1752 old(owner).value().parent_level,
1753 ),
1754 old(regions).inv(),
1755 old(regions).slots.contains_key(old(parent_owner).slot_index),
1756 ensures
1757 final(owner).inv(),
1758 final(owner).value().is_node(),
1759 final(owner).level() == old(owner).level(),
1760 final(owner).value().parent_level == old(owner).value().parent_level,
1761 final(owner).value().path == old(owner).value().path,
1762 final(owner).value().metaregion_sound(*final(regions)),
1763 final(owner).value().node().relate_guard(res),
1764 final(owner).value().node().meta_vaddr() == res.inner.inner@.ptr.addr(),
1765 final(owner).value().match_pte(
1766 final(parent_owner).children_perm.value()[idx as int],
1767 final(parent_owner).level,
1768 ),
1769 final(guards).lock_held(final(owner).value().node().meta_vaddr()),
1770 OwnerSubtree::implies(
1771 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
1772 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr())),
1773 Entry::<C>::metaregion_sound_neq_preserved(
1774 old(owner).value(),
1775 final(owner).value(),
1776 *old(regions),
1777 *final(regions),
1778 ),
1779 Entry::<C>::path_tracked_pred_preserved(*old(regions), *final(regions)),
1780 old(regions).slots.contains_key(frame_to_index(final(owner).value().meta_slot_paddr()->0)),
1781 final(owner).subtree_satisfies(final(owner).value().path,
1782 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value().node().meta_vaddr())),
1783 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions))),
1784 final(owner).subtree_satisfies(final(owner).value().path, PageTableOwner::<C>::path_tracked_pred(*final(regions))),
1785 PageTableOwner(*final(owner)).view_rec(final(owner).value().path) == set![],
1786 forall|i: int| 0 <= i < NR_ENTRIES ==>
1787 #[trigger] final(owner).children()[i] is Some && final(owner).children()[i]->0.value().is_absent(),
1788 forall|i: int| 0 <= i < NR_ENTRIES ==>
1789 (#[trigger] final(owner).children()[i])->0.value().path
1790 == final(owner).value().path.push_tail(i),
1791 crate::specs::mm::page_table::allocated_empty_node_grandchildren_none(*final(owner)),
1792 forall|i: int| 0 <= i < NR_ENTRIES ==>
1793 (#[trigger] final(owner).children()[i])->0.value().parent_level
1794 == final(owner).value().node().level,
1795 forall|i: int| 0 <= i < NR_ENTRIES ==>
1796 (#[trigger] final(owner).children()[i])->0.value().match_pte(
1797 final(owner).value().node().children_perm.value()[i],
1798 final(owner).children()[i]->0.value().parent_level),
1799 forall|i: int| i != frame_to_index(final(owner).value().meta_slot_paddr()->0) ==>
1800 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i],
1801 forall|i: int| old(regions).slots.contains_key(i)
1802 ==> (#[trigger] final(regions).slots.contains_key(i)),
1803 forall|i: int| #![trigger final(regions).slots[i]]
1804 i != frame_to_index(final(owner).value().meta_slot_paddr()->0)
1805 && old(regions).slots.contains_key(i)
1806 ==> final(regions).slots[i] == old(regions).slots[i],
1807 final(regions).slot_owners[frame_to_index(final(owner).value().meta_slot_paddr()->0)]
1808 .inner_perms.ref_count.value() != REF_COUNT_UNUSED,
1809 old(regions).slot_owners[frame_to_index(final(owner).value().meta_slot_paddr().unwrap())]
1810 .inner_perms.ref_count.value() == REF_COUNT_UNUSED,
1811 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(
1812 final(owner).value().meta_slot_paddr().unwrap()),
1813 final(regions).inv(),
1814 final(parent_owner).inv(),
1815 final(parent_owner).level == old(parent_owner).level,
1816 final(parent_owner).relate_guard(*final(self)),
1817 final(parent_owner).metaregion_sound_node(*final(regions)),
1818 forall|j: int| 0 <= j < NR_ENTRIES && j != idx ==>
1819 #[trigger] final(parent_owner).children_perm.value()[j]
1820 == old(parent_owner).children_perm.value()[j],
1821 *final(self) == *old(self),
1822 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
1823 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value().node().meta_vaddr() ==> final(guards).unlocked(i),
1824 )]
1825 pub(in crate::mm) fn alloc_absent_child<A: InAtomicMode>(
1826 &mut self,
1827 idx: usize,
1828 guard: &'rcu A,
1829 ) -> PageTableGuard<'rcu, C> {
1830 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1831 parent_owner.slot_index,
1832 );
1833 #[verus_spec(with Tracked(parent_meta_perm))]
1834 let level = self.level();
1835
1836 let ghost old_path = owner.value().path;
1837
1838 proof {
1844 parent_owner.nr_children_absent_slot_bound(idx);
1845 }
1846 let ghost regions_pre = *regions;
1847 let ghost cp0 = parent_owner.children_perm.value();
1850 let ghost old_owner_val = owner.value();
1853
1854 proof_decl! {
1855 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
1856 }
1857
1858 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(idx) => Tracked(new_node_owner))]
1859 let new_page = PageTableNode::<C>::alloc(level - 1);
1860 let ghost fresh_children = new_node_owner.children();
1861 proof {
1862 assert forall|i: int| 0 <= i < NR_ENTRIES implies (
1863 #[trigger] fresh_children[i]) is Some by {
1864 assert(crate::specs::mm::page_table::allocated_empty_node_owner(
1865 new_node_owner,
1866 (level - 1) as PagingLevel,
1867 ));
1868 assert(new_node_owner.has_child(i));
1869 };
1870 }
1871
1872 proof {
1873 let pte = C::E::new_pt_spec(meta_to_frame(new_node_owner.value().node().meta_vaddr()));
1874 C::E::lemma_page_table_entry_properties();
1875 }
1876
1877 let ghost new_node_slot_idx = new_node_owner.value().node().slot_index;
1878 let tracked new_node_slot_perm = regions.slots.tracked_borrow(new_node_slot_idx);
1879 #[verus_spec(with Tracked(new_node_slot_perm))]
1880 let paddr = new_page.start_paddr();
1881
1882 let new_pte = {
1883 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1884 #[verus_spec(with Tracked(new_node_value), Tracked(regions))]
1885 Child::PageTable(new_page).into_pte()
1886 };
1887
1888 proof {
1889 broadcast use group_page_meta;
1890
1891 }
1892
1893 let pt_ref = unsafe {
1894 #[verus_spec(with Tracked(regions))]
1895 PageTableNodeRef::borrow_paddr(paddr)
1896 };
1897
1898 let pt_lock_guard = {
1899 let tracked new_node_value = new_node_owner.tracked_borrow_value();
1900 #[verus_spec(with Tracked(new_node_value.tracked_borrow_node()), Tracked(guards))]
1901 pt_ref.lock(guard)
1902 };
1903
1904 unsafe {
1905 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
1906 self.write_pte(idx, new_pte)
1907 };
1908
1909 let tracked parent_meta_perm2 = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
1917 parent_owner.slot_index,
1918 );
1919 #[verus_spec(with Tracked(parent_meta_perm2))]
1920 let nr_children = self.nr_children_mut();
1921 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
1922 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
1923
1924 proof {
1925 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
1930 cp0,
1931 NR_ENTRIES as int,
1932 idx as int,
1933 new_pte,
1934 );
1935 }
1936
1937 proof {
1938 {
1939 let tracked new_node_value = new_node_owner.tracked_borrow_mut_value();
1940 new_node_value.parent_level = level as PagingLevel;
1941 new_node_value.path = old_path;
1942 }
1943 *owner = new_node_owner;
1944 assert(owner.children() == fresh_children);
1945 crate::specs::mm::page_table::rebase_freshly_allocated_children(owner, old_path);
1946
1947 let new_paddr = owner.value().meta_slot_paddr().unwrap();
1948 regions.inv_implies_correct_addr(new_paddr);
1949 let new_idx = frame_to_index(new_paddr);
1950 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
1951 new_meta_slot.paths_in_pt = set![owner.value().path];
1952 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
1953 }
1954
1955 proof {
1956 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
1960 let ghost new_node_addr = owner.value().node().meta_vaddr();
1968 let f_nu = CursorOwner::<'rcu, C>::node_unlocked_except(*guards, new_node_addr);
1969 let f_ms = PageTableOwner::<C>::metaregion_sound_pred(*regions);
1970 let f_pt = PageTableOwner::<C>::path_tracked_pred(*regions);
1971
1972 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1975 *owner,
1976 owner.value().path,
1977 f_nu,
1978 );
1979 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1980 *owner,
1981 owner.value().path,
1982 f_ms,
1983 );
1984 crate::specs::mm::page_table::fresh_node_subtree_satisfies(
1985 *owner,
1986 owner.value().path,
1987 f_pt,
1988 );
1989 }
1990
1991 pt_lock_guard
1992 }
1993
1994 #[verifier::spinoff_prover]
1995 #[verus_spec(
1996 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
1997 Tracked(owner): Tracked<&mut EntryOwner<C>>,
1998 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
1999 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
2000 requires
2001 old(owner).inv(),
2002 old(owner).is_absent(),
2003 old(owner).metaregion_sound(*old(regions)),
2004 old(parent_owner).inv(),
2005 old(parent_owner).relate_guard(*old(self)),
2006 old(parent_owner).level == old(owner).parent_level,
2007 idx < NR_ENTRIES,
2008 old(owner).match_pte(
2009 old(parent_owner).children_perm.value()[idx as int],
2010 old(owner).parent_level,
2011 ),
2012 old(regions).inv(),
2013 old(regions).slots.contains_key(old(parent_owner).slot_index),
2014 old(parent_owner).metaregion_sound_node(*old(regions)),
2015 Child::<C>::Frame(paddr, level, prop).invariants(*old(new_owner), *old(regions)),
2016 old(owner).path == old(new_owner).path,
2017 old(owner).parent_level == old(new_owner).parent_level,
2018 ensures
2019 final(new_owner).inv(),
2020 final(parent_owner).inv(),
2021 *final(owner) == old(owner).from_pte_owner_spec(),
2022 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
2023 final(new_owner).pte_invariants(
2024 final(parent_owner).children_perm.value()[idx as int],
2025 *final(regions),
2026 ),
2027 forall|i: int|
2028 0 <= i < NR_ENTRIES && i != idx ==> #[trigger] old(parent_owner).children_perm.value()[i]
2029 == final(parent_owner).children_perm.value()[i],
2030 final(parent_owner).slot_index == old(parent_owner).slot_index,
2031 final(parent_owner).level == old(parent_owner).level,
2032 final(parent_owner).tree_level == old(parent_owner).tree_level,
2033 final(parent_owner).meta_own.nr_children.id() == old(parent_owner).meta_own.nr_children.id(),
2034 final(parent_owner).meta_own.stray == old(parent_owner).meta_own.stray,
2035 final(parent_owner).relate_guard(*final(self)),
2036 final(parent_owner).metaregion_sound_node(*final(regions)),
2037 *final(regions) == *old(regions),
2038 *final(self) == *old(self),
2039 )]
2040 pub(in crate::mm) fn replace_absent_with_frame(
2041 &mut self,
2042 idx: usize,
2043 paddr: Paddr,
2044 level: PagingLevel,
2045 prop: PageProperty,
2046 ) {
2047 let ghost cp0 = parent_owner.children_perm.value();
2049 let tracked parent_meta_perm = regions.borrow_typed_perm::<PageTablePageMeta<C>>(
2050 parent_owner.slot_index,
2051 );
2052 #[verus_spec(with Tracked(parent_meta_perm))]
2053 let nr_children = self.nr_children_mut();
2054 let old_nr_children = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
2055 proof {
2056 parent_owner.nr_children_absent_slot_bound(idx);
2057 }
2058 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), old_nr_children + 1);
2059
2060 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
2061 let new_pte = Child::<C>::Frame(paddr, level, prop).into_pte();
2062
2063 unsafe {
2064 #[verus_spec(with Tracked(parent_owner), Tracked(&*regions))]
2065 self.write_pte(idx, new_pte)
2066 };
2067
2068 proof {
2069 crate::specs::mm::page_table::node::owners::lemma_count_present_upto_update(
2073 cp0,
2074 NR_ENTRIES as int,
2075 idx as int,
2076 new_pte,
2077 );
2078 }
2079 }
2080}
2081
2082}