1use core::marker::PhantomData;
2
3use vstd::prelude::*;
4
5use vstd::{modes::tracked_swap, simple_pptr::PointsTo};
6use vstd_extra::{ghost_tree::*, ownership::*};
7
8use crate::specs::{
9 arch::*,
10 mm::{
11 frame::{
12 mapping::{frame_to_index, index_to_meta},
13 meta_owners::PageUsage,
14 meta_region_owners::MetaRegionOwners,
15 },
16 page_table::{node::entry_view::*, *},
17 },
18};
19
20use crate::arch::mm::PagingConsts;
21use crate::mm::{
22 Paddr, PagingConstsTrait, PagingLevel, Vaddr,
23 frame::meta::{
24 MetaSlot, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED, mapping::meta_to_frame,
25 },
26 page_prop::PageProperty,
27 page_table::*,
28};
29
30verus! {
31
32pub ghost struct FrameEntryState {
38 pub mapped_pa: usize,
39 pub prop: PageProperty,
40}
41
42pub tracked enum EntryOwnerKind<C: PageTableConfig> {
43 Node(NodeOwner<C>),
44 Frame(ghost FrameEntryState),
45 Borrowed(ghost Set<Mapping>),
55 Absent,
56}
57
58pub tracked struct EntryOwner<C: PageTableConfig> {
59 pub kind: EntryOwnerKind<C>,
60 pub ghost path: TreePath<NR_ENTRIES>,
61 pub ghost parent_level: PagingLevel,
62}
63
64impl<C: PageTableConfig> EntryOwner<C> {
65 #[verifier::inline]
66 pub open spec fn is_node(self) -> bool {
67 self.kind is Node
68 }
69
70 #[verifier::inline]
71 pub open spec fn is_frame(self) -> bool {
72 self.kind is Frame
73 }
74
75 #[verifier::inline]
76 pub open spec fn is_absent(self) -> bool {
77 self.kind is Absent
78 }
79
80 #[verifier::inline]
81 pub open spec fn is_borrowed(self) -> bool {
82 self.kind is Borrowed
83 }
84
85 pub open spec fn node(self) -> NodeOwner<C> {
86 self.kind->Node_0
87 }
88
89 pub open spec fn frame(self) -> FrameEntryState {
90 self.kind->Frame_0
91 }
92
93 pub open spec fn frame_is_tracked(self) -> bool
94 recommends
95 self.is_frame(),
96 {
97 C::tracked(
98 C::item_from_raw_spec(self.frame().mapped_pa, self.parent_level, self.frame().prop),
99 )
100 }
101
102 pub open spec fn borrowed(self) -> Set<Mapping> {
103 self.kind->Borrowed_0
104 }
105
106 pub open spec fn new_absent(path: TreePath<NR_ENTRIES>, parent_level: PagingLevel) -> Self {
107 EntryOwner { kind: EntryOwnerKind::Absent, path, parent_level }
108 }
109
110 pub open spec fn new_frame(
111 paddr: Paddr,
112 path: TreePath<NR_ENTRIES>,
113 parent_level: PagingLevel,
114 prop: PageProperty,
115 ) -> Self {
116 EntryOwner {
117 kind: EntryOwnerKind::Frame(FrameEntryState { mapped_pa: paddr, prop }),
118 path,
119 parent_level,
120 }
121 }
122
123 pub open spec fn new_node(node: NodeOwner<C>, path: TreePath<NR_ENTRIES>) -> Self {
124 EntryOwner {
125 kind: EntryOwnerKind::Node(node),
126 path,
127 parent_level: (node.level + 1) as PagingLevel,
128 }
129 }
130
131 pub open spec fn new_borrowed(
134 path: TreePath<NR_ENTRIES>,
135 parent_level: PagingLevel,
136 mappings: Set<Mapping>,
137 ) -> Self {
138 EntryOwner { kind: EntryOwnerKind::Borrowed(mappings), path, parent_level }
139 }
140
141 pub proof fn tracked_new_borrowed(
142 path: TreePath<NR_ENTRIES>,
143 parent_level: PagingLevel,
144 mappings: Set<Mapping>,
145 ) -> tracked Self
146 returns
147 Self::new_borrowed(path, parent_level, mappings),
148 {
149 Self { kind: EntryOwnerKind::Borrowed(mappings), path, parent_level }
150 }
151
152 pub proof fn tracked_new_absent(
153 path: TreePath<NR_ENTRIES>,
154 parent_level: PagingLevel,
155 ) -> tracked Self
156 returns
157 Self::new_absent(path, parent_level),
158 {
159 Self { kind: EntryOwnerKind::Absent, path, parent_level }
160 }
161
162 pub proof fn tracked_take_node(tracked &mut self) -> (tracked res: NodeOwner<C>)
163 requires
164 old(self).kind is Node,
165 ensures
166 res == old(self).node(),
167 *final(self) == (EntryOwner { kind: EntryOwnerKind::Absent, ..*old(self) }),
168 {
169 let tracked mut tmp = EntryOwnerKind::Absent;
170 tracked_swap(&mut self.kind, &mut tmp);
171 match tmp {
172 EntryOwnerKind::Node(node) => node,
173 _ => { proof_from_false() },
174 }
175 }
176
177 pub proof fn tracked_put_node(tracked &mut self, tracked node: NodeOwner<C>)
178 ensures
179 *final(self) == (EntryOwner { kind: EntryOwnerKind::Node(node), ..*old(self) }),
180 {
181 self.kind = EntryOwnerKind::Node(node);
182 }
183
184 pub proof fn tracked_borrow_node(tracked &self) -> (tracked res: &NodeOwner<C>)
185 requires
186 self.kind is Node,
187 ensures
188 *res == self.node(),
189 {
190 match self.kind {
191 EntryOwnerKind::Node(ref node) => node,
192 _ => { proof_from_false() },
193 }
194 }
195
196 pub proof fn tracked_borrow_mut_node(tracked &mut self) -> (tracked res: &mut NodeOwner<C>)
197 requires
198 old(self).kind is Node,
199 ensures
200 *res == old(self).node(),
201 *final(self) == (EntryOwner { kind: EntryOwnerKind::Node(*final(res)), ..*old(self) }),
202 {
203 match self.kind {
204 EntryOwnerKind::Node(ref mut node) => node,
205 _ => { proof_from_false() },
206 }
207 }
208
209 pub proof fn tracked_set_frame_prop(tracked &mut self, prop: PageProperty)
210 requires
211 old(self).kind is Frame,
212 ensures
213 *final(self) == (EntryOwner {
214 kind: EntryOwnerKind::Frame(FrameEntryState { prop, ..old(self).frame() }),
215 ..*old(self)
216 }),
217 {
218 let ghost old_frame = self.frame();
219 self.kind = EntryOwnerKind::Frame(FrameEntryState { prop, ..old_frame });
220 }
221
222 pub proof fn tracked_new_frame(
223 paddr: Paddr,
224 path: TreePath<NR_ENTRIES>,
225 parent_level: PagingLevel,
226 prop: PageProperty,
227 ) -> tracked Self
228 returns
229 Self::new_frame(paddr, path, parent_level, prop),
230 {
231 Self {
232 kind: EntryOwnerKind::Frame(FrameEntryState { mapped_pa: paddr, prop }),
233 path,
234 parent_level,
235 }
236 }
237
238 pub broadcast axiom fn axiom_frame_is_tracked_iff_not_mmio(entry: Self)
244 requires
245 entry.is_frame(),
246 entry.inv_base(),
247 ensures
248 #[trigger] entry.frame_is_tracked()
249 != crate::specs::mm::frame::meta_owners::is_mmio_paddr(entry.frame().mapped_pa),
250 ;
251
252 pub proof fn tracked_new_node(
253 tracked node: NodeOwner<C>,
254 path: TreePath<NR_ENTRIES>,
255 ) -> tracked Self
256 returns
257 Self::new_node(node, path),
258 {
259 Self {
260 parent_level: (node.level + 1) as PagingLevel,
261 kind: EntryOwnerKind::Node(node),
262 path,
263 }
264 }
265
266 pub proof fn tracked_new_untracked_frame(
275 paddr: Paddr,
276 parent_level: PagingLevel,
277 prop: PageProperty,
278 ) -> (tracked res: Self)
279 requires
280 valid_frame_paddr(paddr),
281 1 <= parent_level < NR_LEVELS,
282 paddr % page_size(parent_level) == 0,
283 paddr + page_size(parent_level) <= MAX_PADDR,
284 C::raw_item_well_formed(paddr, parent_level, prop),
285 C::E::new_page_req(paddr, parent_level, prop),
286 !C::tracked(C::item_from_raw_spec(paddr, parent_level, prop)),
287 ensures
288 res.is_frame(),
289 res.frame().mapped_pa == paddr,
290 res.frame().prop == prop,
291 !res.frame_is_tracked(),
292 res.parent_level == parent_level,
293 res.path.inv(),
294 res.inv_base(),
295 crate::mm::page_table::Child::<C>::Frame(paddr, parent_level, prop).wf(res),
296 {
297 Self {
298 kind: EntryOwnerKind::Frame(FrameEntryState { mapped_pa: paddr, prop }),
299 path: TreePath(Seq::empty()),
300 parent_level,
301 }
302 }
303
304 pub open spec fn match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
305 &&& valid_frame_paddr(pte.paddr())
306 &&& !pte.is_present() ==> {
307 &&& self.is_absent()
308 &&& parent_level > 1 ==> !pte.is_last(parent_level)
309 }
310 &&& pte.is_present() && !pte.is_last(parent_level) ==> {
311 &&& self.is_node()
312 &&& meta_to_frame(self.node().meta_vaddr()) == pte.paddr()
313 }
314 &&& pte.is_present() && pte.is_last(parent_level) ==> {
315 &&& self.is_frame()
316 &&& self.frame().mapped_pa == pte.paddr()
317 &&& self.frame().prop == pte.prop()
318 }
319 }
320
321 pub open spec fn borrowed_match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
329 &&& self.is_borrowed()
330 &&& valid_frame_paddr(pte.paddr())
331 &&& pte.is_present()
332 &&& !pte.is_last(parent_level)
333 }
334
335 pub proof fn absent_match_pte(owner: Self, pte: C::E, parent_level: PagingLevel)
337 requires
338 owner.is_absent(),
339 pte == C::E::new_absent_spec(),
340 valid_frame_paddr(pte.paddr()),
341 ensures
342 owner.match_pte(pte, parent_level),
343 {
344 C::E::lemma_page_table_entry_properties();
345 }
346
347 pub proof fn last_pte_implies_frame_match(self, pte: C::E, parent_level: PagingLevel)
348 requires
349 self.inv(),
350 self.match_pte(pte, parent_level),
351 1 < parent_level,
352 pte.is_last(parent_level),
353 ensures
354 self.is_frame(),
355 self.frame().mapped_pa == pte.paddr(),
356 self.frame().prop == pte.prop(),
357 {
358 }
359
360 pub proof fn huge_frame_split_child_at(self, regions: MetaRegionOwners, idx: usize)
361 requires
362 self.inv(),
363 self.is_frame(),
364 regions.inv(),
365 1 < self.parent_level < NR_LEVELS,
366 idx < NR_ENTRIES,
367 ensures
368 self.frame().mapped_pa + idx * page_size((self.parent_level - 1) as PagingLevel)
369 < MAX_PADDR,
370 ((self.frame().mapped_pa + idx * page_size(
371 (self.parent_level - 1) as PagingLevel,
372 )) as Paddr) % page_size((self.parent_level - 1) as PagingLevel) == 0,
373 ((self.frame().mapped_pa + idx * page_size(
374 (self.parent_level - 1) as PagingLevel,
375 )) as Paddr) + page_size((self.parent_level - 1) as PagingLevel) <= MAX_PADDR,
376 ((self.frame().mapped_pa + idx * page_size(
377 (self.parent_level - 1) as PagingLevel,
378 )) as Paddr) % PAGE_SIZE == 0,
379 {
380 let pa = self.frame().mapped_pa;
381 let child_pa = (pa + idx * page_size((self.parent_level - 1) as PagingLevel)) as Paddr;
382 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_values();
383 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
384 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_level1();
385 vstd::arithmetic::power2::lemma2_to64();
386 if self.parent_level == 2 {
387 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(1, 2);
388 assert(child_pa + page_size(1) <= MAX_PADDR) by {
389 assert(idx * 4096 + 4096 <= 2097152);
390 };
391 } else {
392 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_va_align_page_size(pa, 2);
393 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(idx as int, page_size(2) as int);
394 vstd::arithmetic::div_mod::lemma_add_mod_noop(
395 pa as int,
396 (idx * page_size(2)) as int,
397 page_size(2) as int,
398 );
399 }
400 }
401
402 pub proof fn frame_sub_pages_valid_preserved_at_own_slot(
405 self,
406 r0: MetaRegionOwners,
407 r1: MetaRegionOwners,
408 )
409 requires
410 self.inv(),
411 r0.inv(),
412 self.is_frame(),
413 self.parent_level <= NR_LEVELS,
414 self.frame_sub_pages_valid(r0),
415 r0.slots == r1.slots,
416 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
417 forall|i: int|
418 #![trigger r1.slot_owners[i]]
419 i != frame_to_index(self.meta_slot_paddr()->0) && r0.slot_owners.contains_key(i)
420 ==> r0.slot_owners[i] == r1.slot_owners[i],
421 ensures
422 self.frame_sub_pages_valid(r1),
423 {
424 if self.parent_level > 1 {
425 let pa = self.frame().mapped_pa;
426 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
427 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
428 assert forall|j: usize|
429 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
430 0 < j < nr_pages implies {
431 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
432 &&& r1.slots.contains_key(sub_idx)
433 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
434 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
435 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
436 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
437 }
438 } by {
439 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
440 let pa_plus_int: int = pa + j * PAGE_SIZE;
445 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
446 self.parent_level);
447 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
448 self.parent_level,
449 );
450 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
451 j as int,
452 pa as int,
453 PAGE_SIZE as int,
454 );
455 }
457 }
458 }
459
460 pub open spec fn frame_sub_pages_valid(self, regions: MetaRegionOwners) -> bool {
473 self.is_frame() && self.parent_level > 1 ==> {
474 let pa = self.frame().mapped_pa;
475 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
476 forall|j: usize|
477 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
478 0 < j < nr_pages ==> {
479 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
480 &&& regions.slots.contains_key(
483 sub_idx,
484 )
485 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
489 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
490 != REF_COUNT_UNUSED
491 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
492 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
493 <= REF_COUNT_MAX
494 }
495 }
496 }
497 }
498
499 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
500 if self.is_node() {
501 let idx = frame_to_index(self.meta_slot_paddr()->0);
502 &&& regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
503 &&& 0 < regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
504 &&& regions.slot_owners[idx].slot_vaddr == self.node().meta_vaddr()
505 &&& regions.slots[idx].value().wf(regions.slot_owners[idx])
506 &&& regions.slot_owners[idx].paths_in_pt == set![self.path]
507 &&& self.node().metaregion_sound_node(regions)
508 } else if self.is_frame() {
509 let idx = frame_to_index(self.meta_slot_paddr()->0);
510 &&& regions.slots.contains_key(idx)
511 &&& regions.slots[idx].addr() == index_to_meta(idx)
512 &&& regions.slots[idx].is_init()
513 &&& regions.slots[idx].value().wf(regions.slot_owners[idx])
514 &&& regions.slot_owners[idx].usage !is PageTable
515 &&& regions.slot_owners[idx].usage !is MMIO ==> {
520 &&& regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
521 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
522 > 0
523 &&& regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
528 }
529 &&& regions.slot_owners[idx].paths_in_pt.contains(self.path)
530 &&& self.frame_sub_pages_valid(regions)
531 } else {
532 true
533 }
534 }
535
536 pub proof fn lemma_active_entry_not_in_free_pool(
539 entry: Self,
540 regions: MetaRegionOwners,
541 free_idx: int,
542 )
543 requires
544 regions.inv(),
545 entry.inv(),
546 entry.is_node(),
547 entry.metaregion_sound(regions),
548 regions.slots.contains_key(free_idx),
549 regions.slot_owners[free_idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED,
550 ensures
551 frame_to_index(entry.meta_slot_paddr()->0) != free_idx,
552 {
553 let idx = frame_to_index(entry.meta_slot_paddr().unwrap());
554 if idx == free_idx {
555 assert(false);
556 }
557 }
558
559 pub open spec fn meta_slot_paddr(self) -> Option<Paddr> {
560 if self.is_node() {
561 Some(meta_to_frame(self.node().meta_vaddr()))
562 } else if self.is_frame() {
563 Some(self.frame().mapped_pa)
564 } else {
565 None
566 }
567 }
568
569 pub open spec fn meta_slot_paddr_neq(self, other: Self) -> bool {
570 self.meta_slot_paddr() is Some ==> other.meta_slot_paddr() is Some
571 ==> self.meta_slot_paddr()->0 != other.meta_slot_paddr()->0
572 }
573
574 pub proof fn metaregion_sound_slot_owners_only(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
578 requires
579 self.inv(),
580 self.metaregion_sound(r0),
581 r0.slot_owners == r1.slot_owners,
582 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
583 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
584 ensures
585 self.metaregion_sound(r1),
586 {
587 }
588
589 pub proof fn metaregion_sound_one_slot_changed(
592 self,
593 r0: MetaRegionOwners,
594 r1: MetaRegionOwners,
595 changed_idx: int,
596 )
597 requires
598 self.inv(),
599 self.metaregion_sound(r0),
600 forall|i: int|
601 #![trigger r1.slot_owners[i]]
602 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
603 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
604 forall|k: int| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
606 forall|k: int| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
607 self.meta_slot_paddr() is Some ==> frame_to_index(self.meta_slot_paddr()->0)
608 != changed_idx,
609 self.is_frame() && self.parent_level > 1 ==> {
613 let pa = self.frame().mapped_pa;
614 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
615 forall|j: usize|
616 0 < j < nr_pages ==> {
617 let sub_idx = #[trigger] frame_to_index((pa + j * PAGE_SIZE) as usize);
618 sub_idx != changed_idx || r1.slot_owners[sub_idx].usage is MMIO || (
619 r1.slots.contains_key(sub_idx)
620 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
621 != REF_COUNT_UNUSED
622 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
623 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
624 <= REF_COUNT_MAX)
625 }
626 },
627 ensures
628 self.metaregion_sound(r1),
629 {
630 }
631
632 pub proof fn metaregion_sound_paths_in_pt_changed(
635 self,
636 r0: MetaRegionOwners,
637 r1: MetaRegionOwners,
638 changed_idx: int,
639 )
640 requires
641 self.inv(),
642 r0.inv(),
643 self.metaregion_sound(r0),
644 r0.slots == r1.slots,
645 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
646 forall|i: int|
648 #![trigger r1.slot_owners[i]]
649 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
650 r1.slot_owners[changed_idx].inner_perms == r0.slot_owners[changed_idx].inner_perms,
652 r1.slot_owners[changed_idx].slot_vaddr == r0.slot_owners[changed_idx].slot_vaddr,
653 r1.slot_owners[changed_idx].usage == r0.slot_owners[changed_idx].usage,
654 self.is_node() && self.meta_slot_paddr() is Some && frame_to_index(
656 self.meta_slot_paddr()->0,
657 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt == set![self.path],
658 self.is_frame() && self.meta_slot_paddr() is Some && frame_to_index(
660 self.meta_slot_paddr()->0,
661 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt.contains(self.path),
662 self.is_frame() && self.parent_level > 1 ==> {
665 let pa = self.frame().mapped_pa;
666 let sub_level = (self.parent_level - 1) as PagingLevel;
667 forall|j: int|
668 0 < j < NR_ENTRIES ==> {
669 let sub_idx = #[trigger] frame_to_index(
670 (pa + j * page_size(sub_level)) as usize,
671 );
672 sub_idx != changed_idx || r1.slot_owners[changed_idx].paths_in_pt.is_empty()
673 }
674 },
675 ensures
676 self.metaregion_sound(r1),
677 {
678 if self.meta_slot_paddr() is Some {
679 let eidx = frame_to_index(self.meta_slot_paddr().unwrap());
680 if self.is_frame() {
683 if self.parent_level > 1 {
686 let pa = self.frame().mapped_pa;
687 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
688 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
689 assert forall|j: usize|
690 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
691 0 < j < nr_pages implies {
692 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
693 &&& r1.slots.contains_key(sub_idx)
694 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
695 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value()
696 != REF_COUNT_UNUSED
697 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
698 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value()
699 <= REF_COUNT_MAX
700 }
701 } by {
702 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
703 }
705 }
706 }
707 }
708 }
709
710 pub proof fn same_paddr_implies_same_path(self, other: Self, regions: MetaRegionOwners)
713 requires
714 self.meta_slot_paddr() is Some,
715 self.meta_slot_paddr() == other.meta_slot_paddr(),
716 regions.slot_owners[frame_to_index(self.meta_slot_paddr()->0)].paths_in_pt
717 == set![self.path],
718 regions.slot_owners[frame_to_index(self.meta_slot_paddr()->0)].paths_in_pt
719 == set![other.path],
720 ensures
721 self.path == other.path,
722 {
723 assert(set![self.path].contains(other.path));
724 }
725
726 pub proof fn metaregion_sound_rc_value_changed(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
729 requires
730 self.inv(),
731 r0.inv(),
732 self.metaregion_sound(r0),
733 self.meta_slot_paddr() is Some,
734 r0.slots == r1.slots,
735 ({
736 let idx = frame_to_index(self.meta_slot_paddr()->0);
737 &&& r1.slot_owners[idx].inner_perms.ref_count.id()
738 == r0.slot_owners[idx].inner_perms.ref_count.id()
739 &&& r1.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
740 &&& r1.slot_owners[idx].inner_perms.ref_count.value()
741 > 0
742 &&& r1.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
744 &&& r1.slot_owners[idx].inner_perms.storage
745 == r0.slot_owners[idx].inner_perms.storage
746 &&& r1.slot_owners[idx].inner_perms.vtable_ptr
747 == r0.slot_owners[idx].inner_perms.vtable_ptr
748 &&& r1.slot_owners[idx].inner_perms.in_list
749 == r0.slot_owners[idx].inner_perms.in_list
750 &&& r1.slot_owners[idx].slot_vaddr == r0.slot_owners[idx].slot_vaddr
751 &&& r1.slot_owners[idx].paths_in_pt
752 == r0.slot_owners[idx].paths_in_pt
753 &&& r1.slot_owners[idx].usage == r0.slot_owners[idx].usage
756 }),
757 forall|i: int|
759 #![trigger r1.slot_owners[i]]
760 i != frame_to_index(self.meta_slot_paddr()->0) && r0.slot_owners.contains_key(i)
761 ==> r0.slot_owners[i] == r1.slot_owners[i],
762 ensures
763 self.metaregion_sound(r1),
764 {
765 if self.is_frame() && self.parent_level > 1 {
766 let pa = self.frame().mapped_pa;
767 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
768 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
769 assert forall|j: usize|
770 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
771 0 < j < nr_pages implies {
772 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
773 &&& r1.slots.contains_key(sub_idx)
774 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
775 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
776 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
777 }
778 } by {
779 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
780 let pa_plus_int: int = pa + j * PAGE_SIZE;
781 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
782 self.parent_level);
783 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
784 self.parent_level,
785 );
786 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
788 j as int,
789 pa as int,
790 PAGE_SIZE as int,
791 );
792 }
793 }
794 }
795
796 pub proof fn nodes_different_paths_different_addrs(self, other: Self, regions: MetaRegionOwners)
799 requires
800 self.is_node(),
801 other.is_node(),
802 self.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(
803 self.meta_slot_paddr()->0,
804 )].paths_in_pt == set![self.path],
805 other.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(
806 other.meta_slot_paddr()->0,
807 )].paths_in_pt == set![other.path],
808 self.path != other.path,
809 ensures
810 self.node().meta_vaddr() != other.node().meta_vaddr(),
811 {
812 let slot_vaddr = self.node().meta_vaddr();
813 let other_addr = other.node().meta_vaddr();
814 let self_idx = frame_to_index(meta_to_frame(slot_vaddr));
815 let other_idx = frame_to_index(meta_to_frame(other_addr));
816
817 if slot_vaddr == other_addr {
818 assert(set![self.path].contains(other.path));
819 assert(false); }
821 }
822
823 pub proof fn nodes_different_path_lengths_neq_slot(self, other: Self, regions: MetaRegionOwners)
830 requires
831 self.is_node(),
832 other.is_node(),
833 self.metaregion_sound(regions),
834 other.metaregion_sound(regions),
835 self.path.len() != other.path.len(),
836 ensures
837 self.meta_slot_paddr_neq(other),
838 {
839 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
840 let other_idx = frame_to_index(other.meta_slot_paddr().unwrap());
841 if self_idx == other_idx {
842 assert(set![self.path].contains(other.path));
843 assert(false);
844 }
845 }
846}
847
848impl<C: PageTableConfig> EntryOwner<C> {
849 pub open spec fn inv_base(self) -> bool {
852 &&& self.is_node() ==> {
853 &&& self.node().inv()
854 &&& self.parent_level == self.node().level + 1
855 }
856 &&& self.is_frame() ==> {
857 &&& 1 <= self.parent_level < NR_LEVELS
862 &&& valid_frame_paddr(self.frame().mapped_pa)
863 &&& self.frame().mapped_pa % page_size(self.parent_level) == 0
864 &&& self.frame().mapped_pa + page_size(self.parent_level) <= MAX_PADDR
865 &&& C::raw_item_well_formed(
866 self.frame().mapped_pa,
867 self.parent_level,
868 self.frame().prop,
869 )
870 &&& C::E::new_page_req(self.frame().mapped_pa, self.parent_level, self.frame().prop)
871 }
872 &&& self.is_borrowed() ==> { true }
873 &&& self.path.inv()
874 }
875}
876
877impl<C: PageTableConfig> Inv for EntryOwner<C> {
878 open spec fn inv(self) -> bool {
879 self.inv_base()
880 }
881}
882
883impl<C: PageTableConfig> View for EntryOwner<C> {
884 type V = EntryView<C>;
885
886 open spec fn view(&self) -> <Self as View>::V {
887 if self.is_frame() {
888 let frame = self.frame();
889 EntryView::Leaf {
890 leaf: LeafPageTableEntryView {
891 map_va: vaddr(self.path) as int,
892 map_to_pa: frame.mapped_pa as int,
895 level: self.path.len() as u8,
896 prop: frame.prop,
897 phantom: PhantomData,
898 },
899 }
900 } else if self.is_node() {
901 let node = self.node();
902 EntryView::Intermediate {
903 node: IntermediatePageTableEntryView {
904 map_va: vaddr(self.path) as int,
905 map_to_pa: meta_to_frame(node.meta_vaddr()) as int,
908 level: self.path.len() as u8,
909 phantom: PhantomData,
910 },
911 }
912 } else {
913 EntryView::Absent
914 }
915 }
916}
917
918impl<C: PageTableConfig> InvView for EntryOwner<C> {
919 proof fn view_preserves_inv(self) {
920 }
924}
925
926impl<'a, 'rcu, C: PageTableConfig> OwnerOf for Entry<'a, 'rcu, C> {
927 type Owner = EntryOwner<C>;
928
929 open spec fn wf(self, owner: Self::Owner) -> bool {
930 &&& self.idx < NR_ENTRIES
931 &&& owner.match_pte(self.pte, owner.parent_level)
932 &&& valid_frame_paddr(self.pte.paddr())
933 }
934}
935
936}