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, *final(regions)),
145 final(regions).slot_owners =~= old(regions).slot_owners,
146 forall |k: usize| old(regions).slots.contains_key(k) ==> #[trigger] final(regions).slots.contains_key(k),
147 forall |k: usize| old(regions).slots.contains_key(k) ==> old(regions).slots[k] == #[trigger] final(regions).slots[k],
148 final(regions).inv(),
149 {
150 let guard = self.node.borrow(Tracked(guard_perm));
151
152 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
153 let level = guard.level();
154
155 #[verus_spec(with Tracked(regions), Tracked(owner))]
159 let res = ChildRef::from_pte(&self.pte, level);
160
161 res
162 }
163
164 #[verus_spec(
182 with Tracked(owner) : Tracked<&mut EntryOwner<C>>,
183 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
184 Tracked(guard_perm): Tracked<&mut GuardPerm<'rcu, C>>,
185 )]
186 pub(in crate::mm) fn protect(&mut self, op: impl FnOnce(PageProperty) -> PageProperty)
187 requires
188 old(owner).inv(),
189 old(self).wf(*old(owner)),
190 old(self).node_matching(*old(owner), *old(parent_owner), *old(guard_perm)),
191 op.requires((old(self).pte.prop(),)),
192 old(owner).is_frame(),
193 ensures
194 final(owner).inv(),
195 final(self).wf(*final(owner)),
196 final(self).node_matching(*final(owner), *final(parent_owner), *final(guard_perm)),
197 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner), *old(guard_perm), *final(guard_perm)),
198 final(owner).is_frame(),
199 final(owner).frame.unwrap().mapped_pa == old(owner).frame.unwrap().mapped_pa,
200 final(owner).path == old(owner).path,
201 final(owner).parent_level == old(owner).parent_level,
202 final(owner).in_scope == old(owner).in_scope,
203 final(self).idx == old(self).idx,
204 old(self).pte.is_present() ==> op.ensures((old(owner).frame.unwrap().prop,), final(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 ensures
278 final(self).invariants(*final(new_owner), *final(regions)),
279 res.invariants(*final(owner), *final(regions)),
280 final(self).node_matching(*final(new_owner), *final(parent_owner), *final(guard_perm)),
281 final(self).idx == old(self).idx,
282 *final(owner) == old(owner).from_pte_owner_spec(),
283 *final(new_owner) == old(new_owner).into_pte_owner_spec(),
284 Self::metaregion_sound_neq_preserved(*old(owner), *final(new_owner), *old(regions), *final(regions)),
285 !final(new_owner).is_node() ==>
286 Self::metaregion_sound_neq_old_preserved(*old(owner), *old(regions), *final(regions)),
287 (!old(owner).is_node() && !final(new_owner).is_node()) ==>
288 Self::metaregion_sound_preserved(*old(regions), *final(regions)),
289 final(new_owner).is_node() && !final(new_owner).is_absent() ==>
290 PageTableOwner::<C>::path_tracked_pred(*final(regions))(*final(new_owner), final(new_owner).path),
291 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner), *final(guard_perm), *old(guard_perm)),
292 forall|idx: usize| #![trigger final(regions).slot_owners[idx].paths_in_pt]
294 (!final(new_owner).is_node() || final(new_owner).is_absent()
295 || idx != frame_to_index(final(new_owner).meta_slot_paddr().unwrap()))
296 ==> final(regions).slot_owners[idx].paths_in_pt == old(regions).slot_owners[idx].paths_in_pt,
297 forall|k: usize| old(regions).slots.contains_key(k)
299 ==> #[trigger] final(regions).slots.contains_key(k),
300 (!old(owner).is_node() && !final(new_owner).is_node()) ==> {
302 &&& final(regions).slots == old(regions).slots
303 &&& forall|i: usize| #![trigger final(regions).slot_owners[i]]
304 final(regions).slot_owners[i] == old(regions).slot_owners[i]
305 },
306 (old(owner).is_absent() && !final(new_owner).is_node()) ==>
308 forall|k: usize| old(regions).slots.contains_key(k)
309 ==> old(regions).slots[k] == #[trigger] final(regions).slots[k],
310 Self::replace_nonpanic_condition(*old(parent_owner), *old(new_owner)),
311 {
312 let ghost new_idx = frame_to_index(new_owner.meta_slot_paddr().unwrap());
313 let ghost old_idx = frame_to_index(owner.meta_slot_paddr().unwrap());
314
315 let mut guard = self.node.take(Tracked(guard_perm));
316
317 match &new_child {
318 Child::PageTable(node) => {
319 #[cfg(feature = "allow_panic")]
320 assert!(node.level() == guard.level() - 1);
321 }
322 Child::Frame(_, level, _) => {
323 #[cfg(feature = "allow_panic")]
324 assert!(*level == guard.level());
325 }
326 Child::None => {}
327 }
328
329 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
333 let level = guard.level();
334
335 #[verus_spec(with Tracked(regions), Tracked(owner))]
336 let old_child = Child::from_pte(self.pte, level);
337
338 let ghost regions_after_from = *regions;
339
340 assert(new_owner.is_node() ==> regions.slots.contains_key(frame_to_index(new_owner.meta_slot_paddr().unwrap())));
341
342 if old_child.is_none() && !new_child.is_none() {
343 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
344 let nr_children = guard.nr_children_mut();
345 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
346 proof {
347 parent_owner.nr_children_absent_slot_bound(self.idx);
348 }
349 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
350 } else if !old_child.is_none() && new_child.is_none() {
351 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
352 let nr_children = guard.nr_children_mut();
353 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
354 proof {
355 parent_owner.nr_children_present_slot_bound(self.idx);
356 }
357 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp - 1);
358 }
359 proof {
360 assert(owner.metaregion_sound(*regions));
361 }
362
363 #[verus_spec(with Tracked(new_owner), Tracked(regions))]
364 let new_pte = new_child.into_pte();
365
366 let ghost regions_after_into = *regions;
367
368 proof {
369 assert(owner.metaregion_sound(*regions));
370 }
371
372 #[verus_spec(with Tracked(parent_owner))]
377 guard.write_pte(self.idx, new_pte);
378
379 self.node.put(Tracked(guard_perm), guard);
380
381 self.pte = new_pte;
382
383 proof {
384 if new_owner.is_node() {
391 let paddr = new_owner.meta_slot_paddr().unwrap();
392 regions.inv_implies_correct_addr(paddr);
393
394 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
395 new_meta_slot.paths_in_pt = set![new_owner.path];
396 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
397 }
398 owner.in_scope = true;
399 }
400
401 assert(Self::metaregion_sound_neq_preserved(*old(owner), *new_owner, *old(regions), *regions));
402
403 proof {
404 if !old(owner).is_node() && !new_owner.is_node() {
407 }
409 }
410
411 proof {
412 if new_owner.is_node() || new_owner.is_frame() {
413 let paddr = new_owner.meta_slot_paddr().unwrap();
414 regions.inv_implies_correct_addr(paddr);
415 }
416 if new_owner.is_frame() && new_owner.parent_level > 1 {
420 assert(new_owner.frame_sub_pages_valid(*regions));
421 }
422 if owner.is_frame() && owner.parent_level > 1 {
423 assert(owner.frame_sub_pages_valid(*regions));
424 }
425 }
426
427 old_child
428 }
429
430 #[verus_spec(res =>
447 with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
448 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
449 Tracked(regions): Tracked<&mut MetaRegionOwners>,
450 Tracked(guards): Tracked<&mut Guards<'rcu, C>>,
451 Tracked(parent_guard_perm): Tracked<&mut GuardPerm<'rcu, C>>
452 -> guard_perm: Tracked<Option<GuardPerm<'rcu, C>>>
453 requires
454 old(self).invariants(old(owner).value, *old(regions)),
455 old(owner).inv(),
456 old(self).node_matching(old(owner).value, *old(parent_owner), *old(parent_guard_perm)),
457 old(owner).level < INC_LEVELS - 1,
458 ensures
459 final(self).invariants(final(owner).value, *final(regions)),
460 final(self).parent_perms_preserved(*old(parent_owner), *final(parent_owner), *old(parent_guard_perm), *final(parent_guard_perm)),
461 final(self).idx == old(self).idx,
462 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
463 &&& final(self).node_matching(final(owner).value, *final(parent_owner), *final(parent_guard_perm))
465 &&& final(owner).inv()
467 &&& !final(owner).value.in_scope
469 },
470 old(owner).value.is_absent() && old(parent_owner).level > 1 ==> {
471 &&& res is Some
472 &&& final(owner).value.is_node()
473 &&& guard_perm@ is Some
474 &&& guard_perm@.unwrap().addr() == res.unwrap().addr()
475 &&& final(owner).level == old(owner).level
476 &&& final(owner).value.parent_level == old(owner).value.parent_level
477 &&& final(owner).value.node.unwrap().relate_guard_perm(guard_perm@.unwrap())
478 &&& final(guards).lock_held(final(owner).value.node.unwrap().meta_perm.addr())
479 &&& final(owner).value.path == old(owner).value.path
480 &&& final(owner).value.metaregion_sound(*final(regions))
481 &&& OwnerSubtree::implies(
482 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
483 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node.unwrap().meta_perm.addr()))
484 &&& Self::metaregion_sound_neq_preserved(old(owner).value, final(owner).value, *old(regions), *final(regions))
485 &&& Self::path_tracked_pred_preserved(*old(regions), *final(regions))
486 &&& old(regions).slots.contains_key(frame_to_index(final(owner).value.meta_slot_paddr().unwrap()))
487 &&& final(owner).tree_predicate_map(final(owner).value.path,
488 CursorOwner::<'rcu, C>::node_unlocked_except(*final(guards), final(owner).value.node.unwrap().meta_perm.addr()))
489 &&& final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
490 &&& final(owner).tree_predicate_map(final(owner).value.path, PageTableOwner::<C>::path_tracked_pred(*final(regions)))
491 &&& PageTableOwner(*final(owner)).view_rec(final(owner).value.path) =~= set![]
492 &&& forall|i: int| 0 <= i < NR_ENTRIES ==>
494 #[trigger] final(owner).children[i] is Some && final(owner).children[i].unwrap().value.is_absent()
495 &&& forall|i: usize| i != frame_to_index(final(owner).value.meta_slot_paddr().unwrap()) ==>
497 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
498 &&& forall|i: usize| old(regions).slots.contains_key(i)
500 ==> (#[trigger] final(regions).slots.contains_key(i))
501 &&& final(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr().unwrap())]
503 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
504 &&& old(regions).slot_owners[frame_to_index(final(owner).value.meta_slot_paddr().unwrap())]
506 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
507 },
508 !old(owner).value.is_absent() ==> {
509 &&& res is None
510 &&& *final(owner) == *old(owner)
511 },
512 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
513 forall |i: usize| old(guards).unlocked(i) && i != final(owner).value.node.unwrap().meta_perm.addr() ==> final(guards).unlocked(i),
514 )]
515 pub(in crate::mm) fn alloc_if_none<A: InAtomicMode>(&mut self, guard: &'rcu A)
516 -> (res: Option<PPtr<PageTableGuard<'rcu, C>>>) {
517 let entry_is_present = self.pte.is_present();
518
519 let mut parent_guard = self.node.take(Tracked(parent_guard_perm));
520
521 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
522 let level = parent_guard.level();
523
524 if entry_is_present || level <= 1 {
525 self.node.put(Tracked(parent_guard_perm), parent_guard);
526
527 proof_with!{|= Tracked(None)}
528 None
529 } else {
530 let tracked old_path = owner.value.get_path();
531
532 proof_decl! {
533 let tracked mut new_node_owner: Tracked<OwnerSubtree<C>>;
534 }
535
536 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_node_owner))]
537 let new_page = PageTableNode::<C>::alloc(level - 1);
538
539 proof {
540 let pte = C::E::new_pt_spec(meta_to_frame(new_node_owner.value.node.unwrap().meta_perm.addr()));
541 old(parent_owner).set_children_perm_axiom(self.idx, pte);
542 C::E::new_properties();
543 assert(!pte.is_last_spec(level as PagingLevel));
544 }
545
546 #[verus_spec(with Tracked(&new_node_owner.value.node.tracked_borrow().meta_perm.points_to))]
547 let paddr = new_page.start_paddr();
548
549 assert(new_node_owner.value.metaregion_sound(*regions));
550
551 #[verus_spec(with Tracked(&mut new_node_owner.value), Tracked(regions))]
552 let new_pte = Child::PageTable(new_page).into_pte();
553 self.pte = new_pte;
554
555 proof {
556 assert(new_node_owner.value.pte_invariants(self.pte, *regions));
557 assert(new_node_owner.value.match_pte(self.pte, new_node_owner.value.parent_level));
558 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
559 assert(new_node_owner.value.metaregion_sound(*regions));
560 assert(new_node_owner.value.meta_slot_paddr().unwrap() == paddr);
561 }
562
563 #[verus_spec(with Tracked(regions), Tracked(&new_node_owner.value.node.tracked_borrow().meta_perm))]
564 let pt_ref = PageTableNodeRef::borrow_paddr(paddr);
565
566 proof_decl! {
567 let tracked mut guard_perm: Tracked<GuardPerm<'rcu, C>>;
568 }
569
570 #[verus_spec(with Tracked(&new_node_owner.value.node.tracked_borrow()), Tracked(guards) => Tracked(guard_perm))]
572 let pt_lock_guard = pt_ref.lock(guard);
573
574 proof {
575 parent_owner.nr_children_absent_slot_bound(self.idx);
576 }
577
578 #[verus_spec(with Tracked(parent_owner))]
583 parent_guard.write_pte(self.idx, self.pte);
584
585 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
586 let nr_children = parent_guard.nr_children_mut();
587 let _tmp = nr_children.read(Tracked(&parent_owner.meta_own.nr_children));
588 nr_children.write(Tracked(&mut parent_owner.meta_own.nr_children), _tmp + 1);
589
590 self.node.put(Tracked(parent_guard_perm), parent_guard);
591
592 proof {
593 owner.value = new_node_owner.value;
594 owner.value.parent_level = level as PagingLevel;
595 owner.value.path = old_path;
596 owner.children = new_node_owner.children;
597 assert(forall|i: int| 0 <= i < NR_ENTRIES ==>
599 (#[trigger] owner.children[i]) is Some && owner.children[i].unwrap().value.is_absent());
600
601 let new_paddr = owner.value.meta_slot_paddr().unwrap();
602 assert(old(regions).slots.contains_key(frame_to_index(new_paddr)));
603 regions.inv_implies_correct_addr(new_paddr);
604 let new_idx = frame_to_index(new_paddr);
605 let tracked mut new_meta_slot = regions.slot_owners.tracked_remove(new_idx);
606 new_meta_slot.paths_in_pt = set![owner.value.path];
607 regions.slot_owners.tracked_insert(new_idx, new_meta_slot);
608 }
609
610 proof_with!{|= Tracked(Some(guard_perm))}
611 Some(pt_lock_guard)
612 }
613 }
614
615 #[verus_spec(res =>
631 with Tracked(owner) : Tracked<&mut OwnerSubtree<C>>,
632 Tracked(parent_owner): Tracked<&mut NodeOwner<C>>,
633 Tracked(regions): Tracked<&mut MetaRegionOwners>,
634 Tracked(guards): Tracked<&mut Guards<'rcu, C>>,
635 Tracked(guard_perm): Tracked<&mut GuardPerm<'rcu, C>>
636 requires
637 old(regions).inv(),
638 old(owner).inv(),
639 old(self).wf(old(owner).value),
640 old(self).node.addr() == old(guard_perm).addr(),
641 old(guard_perm).is_init(),
642 old(parent_owner).relate_guard_perm(*old(guard_perm)),
643 old(parent_owner).inv(),
644 old(parent_owner).level == old(owner).value.parent_level,
645 old(parent_owner).level < NR_LEVELS,
646 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
651 forall |j: usize| #![trigger frame_to_index(
652 (old(owner).value.frame.unwrap().mapped_pa
653 + j * PAGE_SIZE) as usize)]
654 0 < j < page_size(old(parent_owner).level) / PAGE_SIZE ==> {
655 let sub_idx = frame_to_index(
656 (old(owner).value.frame.unwrap().mapped_pa
657 + j * PAGE_SIZE) as usize);
658 &&& old(regions).slots.contains_key(sub_idx)
659 &&& old(regions).slot_owners[sub_idx].inner_perms.ref_count.value()
660 != REF_COUNT_UNUSED
661 },
662 ensures
663 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
664 &&& res is Some
665 &&& final(owner).value.is_node()
666 &&& final(owner).level == old(owner).level
667 &&& final(parent_owner).relate_guard_perm(*final(guard_perm))
668 &&& final(guards).guards.contains_key(res.unwrap().addr())
669 &&& final(guards).guards[res.unwrap().addr()] is Some
670 &&& final(guards).guards[res.unwrap().addr()].unwrap().pptr() == res.unwrap()
671 &&& final(owner).value.node.unwrap().relate_guard_perm(final(guards).guards[res.unwrap().addr()].unwrap())
672 &&& final(owner).value.node.unwrap().meta_perm.addr() == res.unwrap().addr()
673 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
675 (#[trigger] final(owner).children[j]).unwrap().value.is_frame()
676 &&& forall |j: int| 0 <= j < NR_ENTRIES ==>
677 (#[trigger] final(owner).children[j]).unwrap().value.frame.unwrap().prop
678 == old(owner).value.frame.unwrap().prop
679 &&& final(owner).value.path == old(owner).value.path
680 &&& final(owner).value.metaregion_sound(*final(regions))
681 &&& OwnerSubtree::implies(
682 CursorOwner::<'rcu, C>::node_unlocked(*old(guards)),
683 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
684 &&& OwnerSubtree::implies(
685 PageTableOwner::<C>::metaregion_sound_pred(*old(regions)),
686 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
687 &&& final(owner).tree_predicate_map(final(owner).value.path,
688 CursorOwner::<'rcu, C>::node_unlocked(*final(guards)))
689 &&& final(owner).tree_predicate_map(final(owner).value.path,
690 PageTableOwner::<C>::metaregion_sound_pred(*final(regions)))
691 },
692 !old(owner).value.is_frame() || old(parent_owner).level <= 1 ==> {
693 &&& res is None
694 &&& *final(owner) == *old(owner)
695 },
696 final(owner).inv(),
697 final(owner).value.parent_level == old(owner).value.parent_level,
698 final(self).idx == old(self).idx,
699 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> !final(owner).value.in_scope,
700 old(owner).value.is_frame() && old(parent_owner).level > 1 ==>
701 final(self).node_matching(final(owner).value, *final(parent_owner), *final(guard_perm)),
702 final(regions).inv(),
703 final(parent_owner).inv(),
704 final(parent_owner).level == old(parent_owner).level,
705 final(guard_perm).pptr() == old(guard_perm).pptr(),
706 final(guard_perm).value().inner.inner@.ptr.addr() == old(guard_perm).value().inner.inner@.ptr.addr(),
707 forall |i: usize| old(guards).lock_held(i) ==> final(guards).lock_held(i),
708 forall |i: usize| old(guards).unlocked(i) ==> final(guards).unlocked(i),
709 old(owner).value.is_frame() && old(parent_owner).level > 1 ==> {
711 &&& forall|i: usize| i != frame_to_index(meta_to_frame(final(owner).value.node.unwrap().meta_perm.addr())) ==>
712 (#[trigger] final(regions).slot_owners[i]) == old(regions).slot_owners[i]
713 &&& forall|i: usize| old(regions).slots.contains_key(i)
715 ==> (#[trigger] final(regions).slots.contains_key(i))
716 &&& final(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value.node.unwrap().meta_perm.addr()))]
718 .inner_perms.ref_count.value() != REF_COUNT_UNUSED
719 &&& old(regions).slot_owners[frame_to_index(meta_to_frame(final(owner).value.node.unwrap().meta_perm.addr()))]
721 .inner_perms.ref_count.value() == REF_COUNT_UNUSED
722 },
723 )]
724 pub(in crate::mm) fn split_if_mapped_huge<A: InAtomicMode>(&mut self, guard: &'rcu A)
725 -> (res: Option<PPtr<PageTableGuard<'rcu, C>>>) {
726 let mut node_guard = self.node.take(Tracked(guard_perm));
727
728 #[verus_spec(with Tracked(&parent_owner.meta_perm))]
729 let level = node_guard.level();
730
731 if !(self.pte.is_last(level) && level > 1) {
732 self.node.put(Tracked(guard_perm), node_guard);
733
734 return None;
735 }
736 let pa = self.pte.paddr();
737 let prop = self.pte.prop();
738
739 proof {
740 EntryOwner::last_pte_implies_frame_match(owner.value, self.pte, level);
741 }
742
743 proof_decl!{
744 let tracked mut new_owner: OwnerSubtree<C>;
745 }
746
747 #[verus_spec(with Tracked(parent_owner), Tracked(regions), Tracked(guards), Ghost(self.idx) => Tracked(new_owner))]
748 let new_page = PageTableNode::<C>::alloc(level);
749
750 #[verus_spec(with Tracked(&new_owner.value.node.tracked_borrow().meta_perm.points_to))]
751 let paddr = new_page.start_paddr();
752
753 proof {
754 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
755 assert(new_owner.value.metaregion_sound(*regions));
756 assert(new_owner.value.meta_slot_paddr().unwrap() == paddr);
757 }
758
759 #[verus_spec(with Tracked(regions), Tracked(&new_owner.value.node.tracked_borrow().meta_perm))]
760 let pt_ref = PageTableNodeRef::borrow_paddr(paddr);
761
762 proof_decl! {
763 let tracked mut new_guard_perm: Tracked<GuardPerm<'rcu, C>>;
764 }
765
766 #[verus_spec(with Tracked(&new_owner.value.node.tracked_borrow()), Tracked(guards) => Tracked(new_guard_perm))]
768 let pt_lock_guard = pt_ref.lock(guard);
769
770 let ghost children_perm = new_owner.value.node.unwrap().children_perm;
771 let ghost new_owner_path = new_owner.value.path;
772 let ghost new_owner_meta_addr = new_owner.value.node.unwrap().meta_perm.addr();
773
774 for i in 0..nr_subpage_per_huge::<C>()
775 invariant
776 1 < level < NR_LEVELS,
777 owner.inv(),
778 owner.value.is_frame(),
779 owner.value.parent_level == level,
780 owner.value.frame.unwrap().mapped_pa == pa,
781 owner.value.frame.unwrap().prop == prop,
782 pa == old(owner).value.frame.unwrap().mapped_pa,
783 level == old(parent_owner).level,
784 pa % page_size(level) == 0,
785 pa + page_size(level) <= MAX_PADDR,
786 regions.inv(),
787 parent_owner.inv(),
788 new_owner.value.is_node(),
789 new_owner.inv(),
790 new_owner.value.path == new_owner_path,
791 new_owner.value.node.unwrap().meta_perm.addr() == new_owner_meta_addr,
792 new_owner.value.node.unwrap().relate_guard_perm(new_guard_perm),
793 new_owner.value.node.unwrap().level == (level - 1) as PagingLevel,
794 pt_lock_guard.addr() == new_guard_perm.addr(),
795 forall|j: int|
796 #![auto]
797 0 <= j < NR_ENTRIES ==> {
798 &&& new_owner.children[j] is Some
799 &&& new_owner.children[j].unwrap().value.match_pte(new_owner.value.node.unwrap().children_perm.value()[j], new_owner.value.node.unwrap().level)
800 &&& new_owner.children[j].unwrap().value.parent_level == new_owner.value.node.unwrap().level
801 &&& new_owner.children[j].unwrap().value.inv()
802 &&& new_owner.children[j].unwrap().value.path == new_owner_path.push_tail(j as usize)
803 },
804 forall|j: int| #![auto] i <= j < NR_ENTRIES ==> {
805 &&& new_owner.children[j].unwrap().value.is_absent()
806 &&& !new_owner.children[j].unwrap().value.in_scope
807 &&& new_owner.value.node.unwrap().children_perm.value()[j] == C::E::new_absent_spec()
808 },
809 forall|j: int| #![auto] 0 <= j < i ==> {
811 new_owner.children[j].unwrap().value.is_frame()
812 },
813 forall |j: usize| #![trigger frame_to_index(
816 (pa + j * PAGE_SIZE) as usize)]
817 0 < j < page_size(level) / PAGE_SIZE ==> {
818 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
819 &&& regions.slots.contains_key(sub_idx)
820 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
821 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
822 },
823 regions.slots.contains_key(frame_to_index(pa)),
828 regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value()
829 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED,
830 regions.slot_owners[frame_to_index(pa)].inner_perms.ref_count.value() > 0,
831 new_page.ptr.addr() == new_owner_meta_addr,
832 {
833 proof {
834 C::axiom_nr_subpage_per_huge_eq_nr_entries();
835 }
836 assert(i < NR_ENTRIES);
837
838 proof {
839 let ghost the_node = new_owner.value.node.unwrap();
841 assert(0 <= i < NR_ENTRIES);
842 assert(new_owner.children[i as int].unwrap().value.match_pte(
843 the_node.children_perm.value()[i as int],
844 new_owner.children[i as int].unwrap().value.parent_level,
845 ));
846 assert(the_node.relate_guard_perm(new_guard_perm));
847 assert(new_guard_perm.addr() == pt_lock_guard.addr());
848 assert(new_owner.children[i as int].unwrap().value.parent_level == the_node.level);
849 assert(!new_owner.children[i as int].unwrap().value.in_scope);
850
851 OwnerSubtree::child_some_properties(new_owner, i as usize);
852 }
853
854 let tracked mut new_owner_node = new_owner.value.node.tracked_take();
855
856 proof {
857 let ghost old_children_perm = new_owner_node.children_perm;
858 }
859
860 proof {
861 EntryOwner::huge_frame_split_child_at(owner.value, *regions, i as usize);
862 }
863
864 let small_pa = pa + i * page_size(level - 1);
865
866 assert(small_pa % PAGE_SIZE == 0);
867
868 let tracked child_owner = EntryOwner::new_frame(
869 small_pa,
870 new_owner.value.path.push_tail(i as usize),
871 (level - 1) as PagingLevel,
872 prop,
873 );
874
875 #[verus_spec(with Tracked(&new_owner_node), Tracked(&new_owner.children.tracked_borrow(i as int).tracked_borrow().value), Tracked(&new_guard_perm))]
876 let mut entry = PageTableGuard::entry(pt_lock_guard, i);
877
878 proof {
879 assert(entry.idx == i as usize);
880 let ghost child_before_remove = new_owner.child(i as usize).unwrap();
881 assert(child_before_remove.inv());
882 }
883 let tracked mut new_owner_child = new_owner.children.tracked_remove(i as int).tracked_unwrap();
884
885 proof {
886 assert(new_owner_child.value.match_pte(
887 new_owner_node.children_perm.value()[i as int],
888 new_owner_child.value.parent_level,
889 ));
890
891 let idx = frame_to_index(small_pa);
892 assert(idx == frame_to_index(
893 (pa + i * page_size((level - 1) as PagingLevel)) as usize));
894 if i != 0 {
895 let ghost big_j = crate::specs::mm::page_table::cursor::
896 page_size_lemmas::lemma_split_sub_page_big_j(pa, level, i);
897 assert(small_pa == (pa + big_j * PAGE_SIZE) as usize);
898 }
899
900 assert(entry.node_matching(new_owner_child.value, new_owner_node, new_guard_perm)) by {
901 let pte = new_owner_node.children_perm.value()[i as int];
902 assert(pte == C::E::new_absent_spec());
903 crate::specs::arch::PageTableEntry::absent_pte_paddr_ok();
904 EntryOwner::absent_match_pte(
905 new_owner_child.value,
906 pte,
907 new_owner_child.value.parent_level,
908 );
909 };
910
911 if level - 1 > 1 {
912 let nr_subpages = page_size((level - 1) as PagingLevel) / PAGE_SIZE;
913 crate::specs::mm::page_table::cursor::page_size_lemmas::
914 lemma_page_size_div_mul_eq((level - 1) as PagingLevel);
915 crate::specs::mm::page_table::cursor::page_size_lemmas::
916 lemma_page_size_div_mul_eq(level);
917 crate::specs::mm::page_table::cursor::page_size_lemmas::
918 lemma_nr_entries_times_sub_page_size(level);
919 assert forall |j_prime: usize|
920 #![trigger frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize)]
921 0 < j_prime < nr_subpages implies {
922 let sub_idx = frame_to_index((small_pa + j_prime * PAGE_SIZE) as usize);
923 &&& regions.slots.contains_key(sub_idx)
924 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
925 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
926 } by {
927 let sub_pages_per_subframe = page_size((level - 1) as PagingLevel) / PAGE_SIZE;
928 let big_j_int: int = i as int * sub_pages_per_subframe as int + j_prime as int;
929 vstd::arithmetic::mul::lemma_mul_nonnegative(
930 i as int, sub_pages_per_subframe as int);
931 vstd::arithmetic::mul::lemma_mul_inequality(
932 (i + 1) as int, NR_ENTRIES as int, sub_pages_per_subframe as int);
933 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
934 sub_pages_per_subframe as int, i as int, 1int);
935 vstd::arithmetic::mul::lemma_mul_is_associative(
936 NR_ENTRIES as int, sub_pages_per_subframe as int, PAGE_SIZE as int);
937 vstd::arithmetic::div_mod::lemma_div_by_multiple(
938 NR_ENTRIES as int * sub_pages_per_subframe as int, PAGE_SIZE as int);
939 let big_j: usize = big_j_int as usize;
940 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
941 PAGE_SIZE as int,
942 i as int * sub_pages_per_subframe as int,
943 j_prime as int);
944 vstd::arithmetic::mul::lemma_mul_is_associative(
945 i as int, sub_pages_per_subframe as int, PAGE_SIZE as int);
946 assert((small_pa + j_prime * PAGE_SIZE) as usize == (pa + big_j * PAGE_SIZE) as usize);
947 }
948 assert(child_owner.frame_sub_pages_valid(*regions));
949 }
950
951 let small_idx = frame_to_index(small_pa);
952 regions.inv_implies_correct_addr(small_pa);
953 let tracked mut small_slot = regions.slot_owners.tracked_remove(small_idx);
954 small_slot.paths_in_pt = small_slot.paths_in_pt.insert(child_owner.path);
955 regions.slot_owners.tracked_insert(small_idx, small_slot);
956
957 if (level - 1) > 1 {
958 assert(child_owner.frame_sub_pages_valid(*regions));
959 }
960
961 assert(Child::<C>::Frame(small_pa, (level - 1) as PagingLevel, prop)
962 .invariants(child_owner, *regions));
963 }
964
965 #[verus_spec(with Tracked(regions),
966 Tracked(&mut new_owner_child.value),
967 Tracked(&mut child_owner),
968 Tracked(&mut new_owner_node),
969 Tracked(&mut new_guard_perm))]
970 let old = entry.replace(Child::Frame(small_pa, level - 1, prop));
971
972 proof {
973 new_owner.value.node = Some(new_owner_node);
974 new_owner_child.value.in_scope = false;
975 child_owner.in_scope = false;
976 OwnerSubtree::set_value_property(new_owner_child, child_owner);
977 new_owner_child.value = child_owner;
978 new_owner.children.tracked_insert(i as int, Some(new_owner_child));
979
980 TreePath::push_tail_property_len(new_owner_path, i as usize);
981 OwnerSubtree::insert_preserves_inv(new_owner, i as usize, new_owner_child);
982 }
983 }
984
985 self.pte = (#[verus_spec(with Tracked(&mut new_owner.value), Tracked(regions))]
986 Child::PageTable(new_page).into_pte());
987
988 proof {
989 new_owner.level = owner.level;
990 *owner = new_owner;
991 }
992
993 let tracked mut node_owner = owner.value.node.tracked_take();
994
995 #[verus_spec(with Tracked(&mut node_owner))]
1000 node_guard.write_pte(self.idx, self.pte);
1001
1002 proof {
1003 owner.value.node = Some(node_owner);
1004 }
1005
1006 self.node.put(Tracked(guard_perm), node_guard);
1007
1008 Some(pt_lock_guard)
1009 }
1010
1011 #[verus_spec(
1027 with Tracked(owner): Tracked<&EntryOwner<C>>,
1028 Tracked(parent_owner): Tracked<&NodeOwner<C>>,
1029 Tracked(guard_perm): Tracked<&GuardPerm<'rcu, C>>
1030 )]
1031 pub(in crate::mm) fn new_at(guard: PPtr<PageTableGuard<'rcu, C>>, idx: usize) -> (res: Self)
1032 requires
1033 owner.inv(),
1034 !owner.in_scope,
1035 parent_owner.inv(),
1036 guard_perm.addr() == guard.addr(),
1037 parent_owner.relate_guard_perm(*guard_perm),
1038 idx < NR_ENTRIES,
1039 owner.match_pte(parent_owner.children_perm.value()[idx as int], owner.parent_level),
1040 ensures
1041 res.wf(*owner),
1042 res.node.addr() == guard_perm.addr(),
1043 res.idx == idx,
1044 {
1045 let guard_val = guard.borrow(Tracked(guard_perm));
1047 #[verus_spec(with Tracked(parent_owner))]
1048 let pte = guard_val.read_pte(idx);
1049 Self { pte, idx, node: guard }
1050 }
1051}
1052
1053}