1use vstd::prelude::*;
4
5use vstd::simple_pptr::{self, PPtr, PointsTo};
6
7use vstd_extra::cast_ptr;
8use vstd_extra::drop_tracking::ManuallyDrop;
9use vstd_extra::ghost_tree::*;
10use vstd_extra::ownership::*;
11
12use crate::mm::frame::meta::mapping::{frame_to_index, frame_to_meta, meta_to_frame};
13use crate::mm::frame::{Frame, FrameRef};
14use crate::mm::page_table::*;
15use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
16use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
17use crate::specs::arch::paging_consts::PagingConsts;
18use crate::specs::mm::frame::meta_owners::{MetaSlotOwner, REF_COUNT_UNUSED};
19use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
20use crate::specs::mm::page_table::{PageTableOwner, INC_LEVELS};
21use crate::specs::task::InAtomicMode;
22
23use core::marker::PhantomData;
24use core::ops::Deref;
25
26use crate::{
27 mm::{nr_subpage_per_huge, page_prop::PageProperty},
28 };
31
32use super::*;
33
34verus! {
35
36pub type PageTableNodeRef<'a, C> = FrameRef<'a, PageTablePageMeta<C>>;
38
39pub struct PageTableGuard<'rcu, C: PageTableConfig> {
41 pub inner: PageTableNodeRef<'rcu, C>,
42}
43
44impl<'rcu, C: PageTableConfig> Deref for PageTableGuard<'rcu, C> {
45 type Target = PageTableNodeRef<'rcu, C>;
46
47 #[verus_spec(ensures returns self.inner)]
48 fn deref(&self) -> &Self::Target {
49 &self.inner
50 }
51}
52
53pub struct Entry<'rcu, C: PageTableConfig> {
54 pub pte: C::E,
73 pub idx: usize,
75 pub node: PPtr<PageTableGuard<'rcu, C>>,
79}
80
81impl<'rcu, C: PageTableConfig> Entry<'rcu, C> {
82 pub open spec fn new_spec(pte: C::E, idx: usize, node: PPtr<PageTableGuard<'rcu, C>>) -> Self {
83 Self { pte, idx, node }
84 }
85
86 #[verifier::when_used_as_spec(new_spec)]
87 pub fn new(pte: C::E, idx: usize, node: PPtr<PageTableGuard<'rcu, C>>) -> Self {
88 Self { pte, idx, node }
89 }
90}
91
92#[verus_verify]
93impl<'a, 'rcu, C: PageTableConfig> Entry<'rcu, C> {
94 #[verus_spec(r =>
96 with Tracked(owner): Tracked<&EntryOwner<C>>,
97 requires
98 self.wf(*owner),
99 owner.inv(),
100 returns owner.is_absent(),
101 )]
102 pub(in crate::mm) fn is_none(&self) -> bool {
103 !self.pte.is_present()
104 }
105
106 #[verus_spec(
108 with Tracked(owner): Tracked<EntryOwner<C>>,
109 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
110 Tracked(guard_perm): Tracked<&GuardPerm<'rcu, C>>
111 )]
112 pub(in crate::mm) fn is_node(&self) -> bool
113 requires
114 owner.inv(),
115 self.wf(owner),
116 guard_perm.addr() == self.node.addr(),
117 parent_owner.relate_guard_perm(*guard_perm),
118 parent_owner.inv(),
119 parent_owner.level == owner.parent_level,
120 returns
121 owner.is_node(),
122 {
123 let guard = self.node.borrow(Tracked(guard_perm));
124
125 self.pte.is_present() && !self.pte.is_last(
126 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
127 guard.level(),
128 )
129 }
130
131 #[verus_spec(
133 with Tracked(owner): Tracked<&EntryOwner<C>>,
134 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
135 Tracked(regions): Tracked<&mut MetaRegionOwners>,
136 Tracked(guard_perm): Tracked<&GuardPerm<'rcu, C>>
137 )]
138 pub(in crate::mm) fn to_ref(&self) -> (res: ChildRef<'rcu, C>)
139 requires
140 self.invariants(*owner, *old(regions)),
141 self.node_matching(*owner, *parent_owner, *guard_perm),
142 !owner.in_scope,
143 ensures
144 res.invariants(*owner, *regions),
145 regions.slot_owners =~= old(regions).slot_owners,
146 forall |k: usize| old(regions).slots.contains_key(k) ==> #[trigger] regions.slots.contains_key(k),
147 regions.inv(),
148 {
149 let guard = self.node.borrow(Tracked(guard_perm));
150
151 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
152 let level = guard.level();
153
154 #[verus_spec(with Tracked(regions), Tracked(owner))]
158 let res = ChildRef::from_pte(&self.pte, level);
159
160 res
161 }
162
163 #[verus_spec(
181 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
182 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
183 Tracked(guard_perm): Tracked<&mut GuardPerm<'rcu, C>>,
184 )]
185 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty)
186 requires
187 old(owner).inv(),
188 old(self).wf(*old(owner)),
189 old(self).node_matching(*old(owner), *old(parent_owner), *old(guard_perm)),
190 op.requires((old(self).pte.prop(),)),
191 old(owner).is_frame(),
192 ensures
193 owner.inv(),
194 self.wf(*owner),
195 self.node_matching(*owner, *parent_owner, *guard_perm),
196 self.parent_perms_preserved(*old(parent_owner), *parent_owner, *old(guard_perm), *guard_perm),
197 owner.is_frame(),
198 owner.frame.unwrap().mapped_pa == old(owner).frame.unwrap().mapped_pa,
199 owner.frame.unwrap().slot_perm == old(owner).frame.unwrap().slot_perm,
200 owner.path == old(owner).path,
201 owner.parent_level == old(owner).parent_level,
202 owner.in_scope == old(owner).in_scope,
203 self.idx == old(self).idx,
204 old(self).pte.is_present() ==> op.ensures((old(owner).frame.unwrap().prop,), owner.frame.unwrap().prop),
205 {
206 let ghost pte0 = self.pte;
207
208 if !self.pte.is_present() {
209 return ;
210 }
211 let prop = self.pte.prop();
212 let new_prop = op(prop);
213
214 proof {
219 self.pte.set_prop_properties(new_prop);
220 }
221 self.pte.set_prop(new_prop);
222
223 let mut guard = self.node.take(Tracked(guard_perm));
224
225 #[verus_spec(with Tracked(parent_owner))]
231 guard.write_pte(self.idx, self.pte);
232
233 proof {
234 let tracked mut frame_owner = owner.frame.tracked_take();
235 frame_owner.prop = new_prop;
236 owner.frame = Some(frame_owner);
237 }
238 assert(owner.match_pte(self.pte, owner.parent_level));
239
240 self.node.put(Tracked(guard_perm), guard);
241 }
242
243 #[verus_spec(
264 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
265 Tracked(owner): Tracked<&mut EntryOwner<C>>,
266 Tracked(new_owner): Tracked<&mut EntryOwner<C>>,
267 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
268 Tracked(guard_perm): Tracked<&mut GuardPerm<'rcu, C>>
269 )]
270 pub(in crate::mm) fn replace(&mut self, new_child: Child<C>) -> (res: Child<C>)
271 requires
272 old(self).invariants(*old(owner), *old(regions)),
273 new_child.invariants(*old(new_owner), *old(regions)),
274 old(self).node_matching(*old(owner), *old(parent_owner), *old(guard_perm)),
275 old(self).new_owner_compatible(new_child, *old(owner), *old(new_owner), *old(regions)),
276 !old(owner).in_scope,
277 Self::replace_panic_condition(*old(parent_owner), *old(new_owner)),
278 ensures
279 self.invariants(*new_owner, *regions),
280 res.invariants(*owner, *regions),
281 self.node_matching(*new_owner, *parent_owner, *guard_perm),
282 self.idx == old(self).idx,
283 *owner == old(owner).from_pte_owner_spec(),
284 *new_owner == old(new_owner).into_pte_owner_spec(),
285 Self::relate_region_neq_preserved(*old(owner), *new_owner, *old(regions), *regions),
286 Self::path_tracked_pred_preserved(*old(regions), *regions),
287 !new_owner.is_absent() ==> PageTableOwner::<C>::path_tracked_pred(*regions)(*new_owner, new_owner.path),
288 self.parent_perms_preserved(*old(parent_owner), *parent_owner, *guard_perm, *old(guard_perm)),
289 forall|idx: usize| #![trigger regions.slot_owners[idx].path_if_in_pt]
291 (new_owner.is_absent() || idx != frame_to_index(new_owner.meta_slot_paddr().unwrap()))
292 ==> regions.slot_owners[idx].path_if_in_pt == old(regions).slot_owners[idx].path_if_in_pt,
293 {
294 let ghost new_idx = frame_to_index(new_owner.meta_slot_paddr().unwrap());
295 let ghost old_idx = frame_to_index(owner.meta_slot_paddr().unwrap());
296
297 let mut guard = self.node.take(Tracked(guard_perm));
298
299 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
315 let level = guard.level();
316
317 #[verus_spec(with Tracked(regions), Tracked(owner))]
318 let old_child = Child::from_pte(self.pte, level);
319
320 let ghost regions_after_from = *regions;
321
322 assert(new_owner.is_node() ==> regions.slots.contains_key(frame_to_index(new_owner.meta_slot_paddr().unwrap())));
323
324 if old_child.is_none() && !new_child.is_none() {
325 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
326 let nr_children = guard.nr_children_mut();
327 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
328 assume(_tmp < NR_ENTRIES);
329 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
330 } else if !old_child.is_none() && new_child.is_none() {
331 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
332 let nr_children = guard.nr_children_mut();
333 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
334 assume(_tmp > 0);
335 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
336 }
337 proof {
338 assert(owner.relate_region(*regions));
339 }
340
341 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
342 let new_pte = new_child.into_pte();
343
344 let ghost regions_after_into = *regions;
345
346 proof {
347 assert(owner.relate_region(*regions));
348 }
349
350 #[verus_spec(with Tracked(parent_owner))]
355 guard.write_pte(self.idx, new_pte);
356
357 self.node.put(Tracked(guard_perm), guard);
358
359 self.pte = new_pte;
360
361 proof {
362 if new_owner.is_node() || new_owner.is_frame() {
363 let paddr = new_owner.meta_slot_paddr().unwrap();
364 regions.inv_implies_correct_addr(paddr);
365
366 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
367 new_meta_slot.path_if_in_pt = Some(new_owner.get_path());
368 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
369 }
370 owner.in_scope = true;
371 }
372
373 assert(Self::relate_region_neq_preserved(*old(owner), *new_owner, *old(regions), *regions));
374 assert(Self::path_tracked_pred_preserved(*old(regions), *regions));
375
376 proof {
377 if new_owner.is_node() || new_owner.is_frame() {
378 let paddr = new_owner.meta_slot_paddr().unwrap();
379 regions.inv_implies_correct_addr(paddr);
380 }
381 }
382
383 old_child
384 }
385
386 #[verus_spec(res =>
403 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
404 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
405 Tracked(regions): Tracked<&mut MetaRegionOwners>,
406 Tracked(guards): Tracked<&mut Guards<'rcu, C>>,
407 Tracked(parent_guard_perm): Tracked<&mut GuardPerm<'rcu, C>>
408 -> guard_perm: Tracked<Option<GuardPerm<'rcu, C>>>
409 requires
410 old(self).invariants(old(owner).value, *old(regions)),
411 old(owner).inv(),
412 old(self).node_matching(old(owner).value, *old(parent_owner), *old(parent_guard_perm)),
413 old(owner).level < INC_LEVELS - 1,
414 ensures
415 self.invariants(owner.value, *regions),
416 self.parent_perms_preserved(*old(parent_owner), *parent_owner, *old(parent_guard_perm), *parent_guard_perm),
417 self.idx == old(self).idx,
418 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
419 &&& self.node_matching(owner.value, *parent_owner, *parent_guard_perm)
421 &&& owner.inv()
423 &&& !owner.value.in_scope
425 },
426 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
427 &&& res is Some
428 &&& owner.value.is_node()
429 &&& guard_perm@ is Some
430 &&& guard_perm@.unwrap().addr() == res.unwrap().addr()
431 &&& owner.level == old(owner).level
432 &&& owner.value.parent_level == old(owner).value.parent_level
433 &&& owner.value.node.unwrap().relate_guard_perm(guard_perm@.unwrap())
434 &&& guards.lock_held(owner.value.node.unwrap().meta_perm.addr())
435 &&& owner.value.path == old(owner).value.path
436 &&& owner.value.relate_region(*regions)
437 &&& OwnerSubtree::implies(
438 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
439 CursorOwner::<'rcu, C>::node_unlocked_except(*guards, owner.value.node.unwrap().meta_perm.addr()))
440 &&& Self::relate_region_neq_preserved(old(owner).value, owner.value, *old(regions), *regions)
441 &&& Self::path_tracked_pred_preserved(*old(regions), *regions)
442 &&& old(regions).slots.contains_key(frame_to_index(owner.value.meta_slot_paddr().unwrap()))
443 &&& owner.tree_predicate_map(owner.value.path,
444 CursorOwner::<'rcu, C>::node_unlocked_except(*guards, owner.value.node.unwrap().meta_perm.addr()))
445 &&& owner.tree_predicate_map(owner.value.path, PageTableOwner::<C>::relate_region_pred(*regions))
446 &&& owner.tree_predicate_map(owner.value.path, PageTableOwner::<C>::path_tracked_pred(*regions))
447 &&& PageTableOwner(*owner).view_rec(owner.value.path) =~= set![]
448 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
450 #[trigger] owner.children[i] is Some && owner.children[i].unwrap().value.is_absent()
451 &&& forall|i: usize| i != frame_to_index(owner.value.meta_slot_paddr().unwrap()) ==>
453 (#[trigger] regions.slot_owners[i]) == old(regions).slot_owners[i]
454 &&& forall|i: usize| old(regions).slots.contains_key(i)
456 ==> (#[trigger] regions.slots.contains_key(i))
457 &&& regions.slot_owners[frame_to_index(owner.value.meta_slot_paddr().unwrap())]
459 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
460 &&& old(regions).slot_owners[frame_to_index(owner.value.meta_slot_paddr().unwrap())]
462 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
463 },
464 !old(owner).value.is_absent() ==> {
465 &&& res is None
466 &&& *owner == *old(owner)
467 },
468 forall |i: usize| old(guards).lock_held(i) ==> guards.lock_held(i),
469 forall |i: usize| old(guards).unlocked(i) && i != owner.value.node.unwrap().meta_perm.addr() ==> guards.unlocked(i),
470 )]
471 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A)
472 -> (res: Option<PPtr<PageTableGuard<'rcu, C>>>) {
473 let entry_is_present = self.pte.is_present();
474
475 let mut parent_guard = self.node.take(Tracked(parent_guard_perm));
476
477 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
478 let level = parent_guard.level();
479
480 if entry_is_present || level <= 1 {
481 self.node.put(Tracked(parent_guard_perm), parent_guard);
482
483 proof_with!{|= Tracked(None)}
484 None
485 } else {
486 let tracked old_path = owner.value.get_path();
487
488 proof_decl! {
489 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
490 }
491
492 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
493 let new_page = PageTableNode::<C>::alloc(level - 1);
494
495 proof {
496 let pte = C::E::new_pt_spec(meta_to_frame(new_node_owner.value.node.unwrap().meta_perm.addr()));
497 old(parent_owner).set_children_perm_axiom(self.idx, pte);
498 C::E::new_properties();
499 assert(!pte.is_last_spec(level as PagingLevel));
500 }
501
502 #[verus_spec(with Tracked(&new_node_owner.value.node.tracked_borrow().meta_perm.points_to))]
503 let paddr = new_page.start_paddr();
504
505 assert(new_node_owner.value.relate_region(*regions));
506
507 #[verus_spec(with Tracked(&mut new_node_owner.value), Tracked(regions))]
508 let new_pte = Child::PageTable(new_page).into_pte();
509 self.pte = new_pte;
510
511 proof {
512 assert(new_node_owner.value.pte_invariants(self.pte, *regions));
514 assert(new_node_owner.value.match_pte(self.pte, new_node_owner.value.parent_level));
515 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
516 }
517
518 #[verus_spec(with Tracked(regions), Tracked(&new_node_owner.value.node.tracked_borrow().meta_perm))]
519 let pt_ref = PageTableNodeRef::borrow_paddr(paddr);
520
521 proof_decl! {
522 let tracked mut guard_perm: Tracked<GuardPerm<'rcu, C>>;
523 }
524
525 #[verus_spec(with Tracked(&new_node_owner.value.node.tracked_borrow()), Tracked(guards) => Tracked(guard_perm))]
527 let pt_lock_guard = pt_ref.lock(guard);
528
529 #[verus_spec(with Tracked(parent_owner))]
534 parent_guard.write_pte(self.idx, self.pte);
535
536 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
537 let nr_children = parent_guard.nr_children_mut();
538 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
539 assume(_tmp < NR_ENTRIES);
540 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
541
542 self.node.put(Tracked(parent_guard_perm), parent_guard);
543
544 proof {
545 owner.value = new_node_owner.value;
546 owner.value.parent_level = level as PagingLevel;
547 owner.value.path = old_path;
548 owner.children = new_node_owner.children;
549 assert(forall|i: int| 0 <= i < NR_ENTRIES ==>
551 (#[trigger] owner.children[i]) is Some && owner.children[i].unwrap().value.is_absent());
552
553 let new_paddr = owner.value.meta_slot_paddr().unwrap();
554 assert(old(regions).slots.contains_key(frame_to_index(new_paddr)));
555 regions.inv_implies_correct_addr(new_paddr);
556 let new_idx = frame_to_index(new_paddr);
557 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
558 new_meta_slot.path_if_in_pt = Some(owner.value.get_path());
559 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
560 }
561
562 proof_with!{|= Tracked(Some(guard_perm))}
563 Some(pt_lock_guard)
564 }
565 }
566
567 #[verus_spec(res =>
583 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
584 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
585 Tracked(regions): Tracked<&mut MetaRegionOwners>,
586 Tracked(guards): Tracked<&mut Guards<'rcu, C>>,
587 Tracked(guard_perm): Tracked<&mut GuardPerm<'rcu, C>>
588 requires
589 old(regions).inv(),
590 old(owner).inv(),
591 old(self).wf(old(owner).value),
592 old(self).node.addr() == old(guard_perm).addr(),
593 old(guard_perm).is_init(),
594 old(parent_owner).relate_guard_perm(*old(guard_perm)),
595 old(parent_owner).inv(),
596 old(parent_owner).level == old(owner).value.parent_level,
597 old(parent_owner).level < NR_LEVELS,
598 ensures
599 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
600 &&& res is Some
601 &&& owner.value.is_node()
602 &&& owner.level == old(owner).level
603 &&& parent_owner.relate_guard_perm(*guard_perm)
604 &&& guards.guards.contains_key(res.unwrap().addr())
605 &&& guards.guards[res.unwrap().addr()] is Some
606 &&& guards.guards[res.unwrap().addr()].unwrap().pptr() == res.unwrap()
607 &&& owner.value.node.unwrap().relate_guard_perm(guards.guards[res.unwrap().addr()].unwrap())
608 &&& owner.value.node.unwrap().meta_perm.addr() == res.unwrap().addr()
609 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
611 (#[trigger] owner.children[j]).unwrap().value.is_frame()
612 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
613 (#[trigger] owner.children[j]).unwrap().value.frame.unwrap().prop
614 == old(owner).value.frame.unwrap().prop
615 &&& owner.value.path == old(owner).value.path
616 &&& owner.value.relate_region(*regions)
617 &&& OwnerSubtree::implies(
618 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
619 CursorOwner::<'rcu, C>::node_unlocked(*guards))
620 &&& OwnerSubtree::implies(
621 PageTableOwner::<C>::relate_region_pred(*old(regions)),
622 PageTableOwner::<C>::relate_region_pred(*regions))
623 &&& owner.tree_predicate_map(owner.value.path,
624 CursorOwner::<'rcu, C>::node_unlocked(*guards))
625 &&& owner.tree_predicate_map(owner.value.path,
626 PageTableOwner::<C>::relate_region_pred(*regions))
627 },
628 !old(owner).value.is_frame() || old(parent_owner).level <= 1 ==> {
629 &&& res is None
630 &&& *owner == *old(owner)
631 },
632 owner.inv(),
633 owner.value.parent_level == old(owner).value.parent_level,
634 self.idx == old(self).idx,
635 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> !owner.value.in_scope,
636 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
637 self.node_matching(owner.value, *parent_owner, *guard_perm),
638 regions.inv(),
639 parent_owner.inv(),
640 parent_owner.level == old(parent_owner).level,
641 guard_perm.pptr() == old(guard_perm).pptr(),
642 guard_perm.value().inner.inner@.ptr.addr() == old(guard_perm).value().inner.inner@.ptr.addr(),
643 forall |i: usize| old(guards).lock_held(i) ==> guards.lock_held(i),
644 forall |i: usize| old(guards).unlocked(i) ==> guards.unlocked(i),
645 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
647 &&& forall|i: usize| i != frame_to_index(meta_to_frame(owner.value.node.unwrap().meta_perm.addr())) ==>
648 (#[trigger] regions.slot_owners[i]) == old(regions).slot_owners[i]
649 &&& forall|i: usize| old(regions).slots.contains_key(i)
651 ==> (#[trigger] regions.slots.contains_key(i))
652 &&& regions.slot_owners[frame_to_index(meta_to_frame(owner.value.node.unwrap().meta_perm.addr()))]
654 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
655 &&& old(regions).slot_owners[frame_to_index(meta_to_frame(owner.value.node.unwrap().meta_perm.addr()))]
657 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
658 },
659 )]
660 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A)
661 -> (res: Option<PPtr<PageTableGuard<'rcu, C>>>) {
662 let mut node_guard = self.node.take(Tracked(guard_perm));
663
664 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
665 let level = node_guard.level();
666
667 if !(self.pte.is_last(level) && level > 1) {
668 self.node.put(Tracked(guard_perm), node_guard);
669
670 return None;
671 }
672 let pa = self.pte.paddr();
673 let prop = self.pte.prop();
674
675 proof {
676 EntryOwner::last_pte_implies_frame_match(owner.value, self.pte, level);
677 }
678
679 proof_decl!{
680 let tracked mut new_owner: OwnerSubtree<C>;
681 }
682
683 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
684 let new_page = PageTableNode::<C>::alloc(level);
685
686 #[verus_spec(with Tracked(&new_owner.value.node.tracked_borrow().meta_perm.points_to))]
687 let paddr = new_page.start_paddr();
688
689 proof {
690 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
691 }
692
693 #[verus_spec(with Tracked(regions), Tracked(&new_owner.value.node.tracked_borrow().meta_perm))]
694 let pt_ref = PageTableNodeRef::borrow_paddr(paddr);
695
696 proof_decl! {
697 let tracked mut new_guard_perm: Tracked<GuardPerm<'rcu, C>>;
698 }
699
700 #[verus_spec(with Tracked(&new_owner.value.node.tracked_borrow()), Tracked(guards) => Tracked(new_guard_perm))]
702 let pt_lock_guard = pt_ref.lock(guard);
703
704 let ghost children_perm = new_owner.value.node.unwrap().children_perm;
705 let ghost new_owner_path = new_owner.value.path;
706 let ghost new_owner_meta_addr = new_owner.value.node.unwrap().meta_perm.addr();
707
708 for i in 0..nr_subpage_per_huge::<C>()
709 invariant
710 1 < level < NR_LEVELS,
711 owner.inv(),
712 owner.value.is_frame(),
713 owner.value.parent_level == level,
714 owner.value.frame.unwrap().mapped_pa == pa,
715 owner.value.frame.unwrap().prop == prop,
716 pa % page_size(level) == 0,
717 pa + page_size(level) <= MAX_PADDR,
718 regions.inv(),
719 parent_owner.inv(),
720 new_owner.value.is_node(),
721 new_owner.inv(),
722 new_owner.value.path == new_owner_path,
723 new_owner.value.node.unwrap().meta_perm.addr() == new_owner_meta_addr,
724 new_owner.value.node.unwrap().relate_guard_perm(new_guard_perm),
725 new_owner.value.node.unwrap().level == (level - 1) as PagingLevel,
726 pt_lock_guard.addr() == new_guard_perm.addr(),
727 forall|j: int|
728 #![auto]
729 0 <= j < NR_ENTRIES ==> {
730 &&& new_owner.children[j] is Some
731 &&& new_owner.children[j].unwrap().value.match_pte(new_owner.value.node.unwrap().children_perm.value()[j], new_owner.value.node.unwrap().level)
732 &&& new_owner.children[j].unwrap().value.parent_level == new_owner.value.node.unwrap().level
733 &&& new_owner.children[j].unwrap().value.inv()
734 &&& new_owner.children[j].unwrap().value.path == new_owner_path.push_tail(j as usize)
735 },
736 forall|j: int| #![auto] i <= j < NR_ENTRIES ==> {
737 &&& new_owner.children[j].unwrap().value.is_absent()
738 &&& !new_owner.children[j].unwrap().value.in_scope
739 &&& new_owner.value.node.unwrap().children_perm.value()[j] == C::E::new_absent_spec()
740 },
741 forall|j: int| #![auto] 0 <= j < i ==> {
743 new_owner.children[j].unwrap().value.is_frame()
744 },
745 new_page.ptr.addr() == new_owner_meta_addr,
746 {
747 proof {
748 C::axiom_nr_subpage_per_huge_eq_nr_entries();
749 }
750 assert(i < NR_ENTRIES);
751
752 proof {
753 let ghost the_node = new_owner.value.node.unwrap();
755 assert(0 <= i < NR_ENTRIES);
756 assert(new_owner.children[i as int].unwrap().value.match_pte(
757 the_node.children_perm.value()[i as int],
758 new_owner.children[i as int].unwrap().value.parent_level,
759 ));
760 assert(the_node.relate_guard_perm(new_guard_perm));
761 assert(new_guard_perm.addr() == pt_lock_guard.addr());
762 assert(new_owner.children[i as int].unwrap().value.parent_level == the_node.level);
763 assert(!new_owner.children[i as int].unwrap().value.in_scope);
764
765 OwnerSubtree::child_some_properties(new_owner, i as usize);
766 }
767
768 let tracked mut new_owner_node = new_owner.value.node.tracked_take();
769
770 proof {
771 let ghost old_children_perm = new_owner_node.children_perm;
772 }
773
774 proof {
775 EntryOwner::huge_frame_split_child_at(owner.value, *regions, i as usize);
776 }
777
778 let small_pa = pa + i * page_size(level - 1);
779
780 assert(small_pa % PAGE_SIZE == 0);
781
782 let tracked split_slot_perm = EntryOwner::<C>::placeholder_slot_perm(small_pa, regions);
783 let tracked child_owner = EntryOwner::new_frame(
784 small_pa,
785 new_owner.value.path.push_tail(i as usize),
786 (level - 1) as PagingLevel,
787 prop,
788 split_slot_perm,
789 );
790
791 #[verus_spec(with Tracked(&new_owner_node), Tracked(&new_owner.children.tracked_borrow(i as int).tracked_borrow().value), Tracked(&new_guard_perm))]
792 let mut entry = PageTableGuard::entry(pt_lock_guard, i);
793
794 proof {
795 assert(entry.idx == i as usize);
796 let ghost child_before_remove = new_owner.child(i as usize).unwrap();
797 assert(child_before_remove.inv());
798 }
799 let tracked mut new_owner_child = new_owner.children.tracked_remove(i as int).tracked_unwrap();
800
801 proof {
802 assert(new_owner_child.value.match_pte(
803 new_owner_node.children_perm.value()[i as int],
804 new_owner_child.value.parent_level,
805 ));
806
807 let idx = frame_to_index(small_pa);
808 assert(regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED);
809 assert(regions.slot_owners[idx].path_if_in_pt is None);
810
811 assert(entry.node_matching(new_owner_child.value, new_owner_node, new_guard_perm)) by {
812 let pte = new_owner_node.children_perm.value()[i as int];
813 assert(pte == C::E::new_absent_spec());
814 crate::specs::arch::PageTableEntry::absent_pte_paddr_ok();
815 EntryOwner::absent_match_pte(
816 new_owner_child.value,
817 pte,
818 new_owner_child.value.parent_level,
819 );
820 };
821
822 assert(Child::<C>::Frame(small_pa, (level - 1) as PagingLevel, prop)
823 .invariants(child_owner, *regions));
824 }
825
826 #[verus_spec(with Tracked(regions),
827 Tracked(&mut new_owner_child.value),
828 Tracked(&mut child_owner),
829 Tracked(&mut new_owner_node),
830 Tracked(&mut new_guard_perm))]
831 let old = entry.replace(Child::Frame(small_pa, level - 1, prop));
832
833 proof {
834 new_owner.value.node = Some(new_owner_node);
835 new_owner_child.value.in_scope = false;
836 child_owner.in_scope = false;
837 OwnerSubtree::set_value_property(new_owner_child, child_owner);
838 new_owner_child.value = child_owner;
839 new_owner.children.tracked_insert(i as int, Some(new_owner_child));
840
841 TreePath::push_tail_property_len(new_owner_path, i as usize);
842 OwnerSubtree::insert_preserves_inv(new_owner, i as usize, new_owner_child);
843 }
844 }
845
846 self.pte = (#[verus_spec(with Tracked(&mut new_owner.value), Tracked(regions))]
847 Child::PageTable(new_page).into_pte());
848
849 proof {
850 new_owner.level = owner.level;
851 *owner = new_owner;
852 }
853
854 let tracked mut node_owner = owner.value.node.tracked_take();
855
856 #[verus_spec(with Tracked(&mut node_owner))]
861 node_guard.write_pte(self.idx, self.pte);
862
863 proof {
864 owner.value.node = Some(node_owner);
865 }
866
867 self.node.put(Tracked(guard_perm), node_guard);
868
869 Some(pt_lock_guard)
870 }
871
872 #[verus_spec(
888 with Tracked(owner): Tracked<&EntryOwner<C>>,
889 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
890 Tracked(guard_perm): Tracked<&GuardPerm<'rcu, C>>
891 )]
892 pub(in crate::mm) fn new_at(guard: PPtr<PageTableGuard<'rcu, C>>, idx: usize) -> (res: Self)
893 requires
894 owner.inv(),
895 !owner.in_scope,
896 parent_owner.inv(),
897 guard_perm.addr() == guard.addr(),
898 parent_owner.relate_guard_perm(*guard_perm),
899 idx < NR_ENTRIES,
900 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
901 ensures
902 res.wf(*owner),
903 res.node.addr() == guard_perm.addr(),
904 res.idx == idx,
905 {
906 let guard_val = guard.borrow(Tracked(guard_perm));
908 #[verus_spec(with Tracked(parent_owner))]
909 let pte = guard_val.read_pte(idx);
910 Self { pte, idx, node: guard }
911 }
912}
913
914}