1use vstd::prelude::*;
2
3use vstd::modes::tracked_swap;
4use vstd::simple_pptr::PointsTo;
5
6use vstd_extra::ghost_tree::*;
7use vstd_extra::ownership::*;
8
9use crate::arch::mm::PagingConsts;
10use crate::mm::frame::meta::MetaSlot;
11use crate::mm::frame::meta::{
12 REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED, mapping::meta_to_frame,
13};
14use crate::mm::page_prop::PageProperty;
15use crate::mm::page_table::*;
16use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
17use crate::specs::arch::*;
18use crate::specs::arch::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
19use crate::specs::mm::frame::mapping::{frame_to_index, meta_addr};
20use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
21use crate::specs::mm::page_table::node::entry_view::*;
22use crate::specs::mm::page_table::*;
23use core::marker::PhantomData;
24
25verus! {
26
27pub tracked struct FrameEntryOwner {
37 pub mapped_pa: usize,
38 pub size: usize,
39 pub prop: PageProperty,
40 pub is_tracked: bool,
41}
42
43pub tracked enum EntryOwnerKind<C: PageTableConfig> {
44 Node(NodeOwner<C>),
45 Frame(FrameEntryOwner),
46 Borrowed(ghost Set<Mapping>),
56 Absent,
57}
58
59pub tracked struct EntryOwner<C: PageTableConfig> {
60 pub kind: EntryOwnerKind<C>,
61 pub ghost path: TreePath<NR_ENTRIES>,
62 pub ghost parent_level: PagingLevel,
63}
64
65impl<C: PageTableConfig> EntryOwner<C> {
66 #[verifier::inline]
67 pub open spec fn is_node(self) -> bool {
68 self.kind is Node
69 }
70
71 #[verifier::inline]
72 pub open spec fn is_frame(self) -> bool {
73 self.kind is Frame
74 }
75
76 #[verifier::inline]
77 pub open spec fn is_absent(self) -> bool {
78 self.kind is Absent
79 }
80
81 #[verifier::inline]
82 pub open spec fn is_borrowed(self) -> bool {
83 self.kind is Borrowed
84 }
85
86 pub open spec fn node(self) -> NodeOwner<C> {
87 self.kind->Node_0
88 }
89
90 pub open spec fn frame(self) -> FrameEntryOwner {
91 self.kind->Frame_0
92 }
93
94 pub open spec fn borrowed(self) -> Set<Mapping> {
95 self.kind->Borrowed_0
96 }
97
98 pub open spec fn new_absent(path: TreePath<NR_ENTRIES>, parent_level: PagingLevel) -> Self {
99 EntryOwner { kind: EntryOwnerKind::Absent, path, parent_level }
100 }
101
102 pub open spec fn new_frame(
103 paddr: Paddr,
104 path: TreePath<NR_ENTRIES>,
105 parent_level: PagingLevel,
106 prop: PageProperty,
107 is_tracked: bool,
108 ) -> Self {
109 EntryOwner {
110 kind: EntryOwnerKind::Frame(
111 FrameEntryOwner {
112 mapped_pa: paddr,
113 size: page_size(parent_level),
114 prop,
115 is_tracked,
116 },
117 ),
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_take_frame(tracked &mut self) -> (tracked res: FrameEntryOwner)
210 requires
211 old(self).kind is Frame,
212 ensures
213 res == old(self).frame(),
214 *final(self) == (EntryOwner { kind: EntryOwnerKind::Absent, ..*old(self) }),
215 {
216 let tracked mut tmp = EntryOwnerKind::Absent;
217 tracked_swap(&mut self.kind, &mut tmp);
218 match tmp {
219 EntryOwnerKind::Frame(frame) => frame,
220 _ => { proof_from_false() },
221 }
222 }
223
224 pub proof fn tracked_put_frame(tracked &mut self, tracked frame: FrameEntryOwner)
225 ensures
226 *final(self) == (EntryOwner { kind: EntryOwnerKind::Frame(frame), ..*old(self) }),
227 {
228 self.kind = EntryOwnerKind::Frame(frame);
229 }
230
231 pub proof fn tracked_borrow_frame(tracked &self) -> (tracked res: &FrameEntryOwner)
232 requires
233 self.kind is Frame,
234 ensures
235 *res == self.frame(),
236 {
237 match self.kind {
238 EntryOwnerKind::Frame(ref frame) => frame,
239 _ => { proof_from_false() },
240 }
241 }
242
243 pub proof fn tracked_borrow_mut_frame(tracked &mut self) -> (tracked res: &mut FrameEntryOwner)
244 requires
245 old(self).kind is Frame,
246 ensures
247 *res == old(self).frame(),
248 *final(self) == (EntryOwner { kind: EntryOwnerKind::Frame(*final(res)), ..*old(self) }),
249 {
250 match self.kind {
251 EntryOwnerKind::Frame(ref mut frame) => frame,
252 _ => { proof_from_false() },
253 }
254 }
255
256 pub axiom fn tracked_new_frame(
257 paddr: Paddr,
258 path: TreePath<NR_ENTRIES>,
259 parent_level: PagingLevel,
260 prop: PageProperty,
261 is_tracked: bool,
262 ) -> tracked Self
263 returns
264 Self::new_frame(paddr, path, parent_level, prop, is_tracked),
265 ;
266
267 pub axiom fn axiom_frame_is_tracked_matches_item(entry: Self)
283 requires
284 entry.is_frame(),
285 entry.inv_base(),
286 ensures
287 entry.frame().is_tracked == C::tracked(
288 C::item_from_raw_spec(
289 entry.frame().mapped_pa,
290 entry.parent_level,
291 entry.frame().prop,
292 ),
293 ),
294 ;
295
296 pub broadcast axiom fn axiom_frame_is_tracked_iff_not_mmio(entry: Self)
302 requires
303 entry.is_frame(),
304 entry.inv_base(),
305 ensures
306 #[trigger] entry.frame().is_tracked
307 != crate::specs::mm::frame::meta_owners::is_mmio_paddr(entry.frame().mapped_pa),
308 ;
309
310 pub proof fn tracked_new_node(
311 tracked node: NodeOwner<C>,
312 path: TreePath<NR_ENTRIES>,
313 ) -> tracked Self
314 returns
315 Self::new_node(node, path),
316 {
317 Self {
318 parent_level: (node.level + 1) as PagingLevel,
319 kind: EntryOwnerKind::Node(node),
320 path,
321 }
322 }
323
324 pub axiom fn new_untracked_frame(
332 paddr: Paddr,
333 parent_level: PagingLevel,
334 prop: PageProperty,
335 ) -> (tracked res: Self)
336 requires
337 paddr % PAGE_SIZE == 0,
338 paddr < MAX_PADDR,
339 1 <= parent_level,
340 parent_level <= NR_LEVELS,
341 ensures
342 res.is_frame(),
343 res.frame().mapped_pa == paddr,
344 res.frame().prop == prop,
345 res.frame().size == page_size(parent_level),
346 res.frame().is_tracked == false,
347 res.parent_level == parent_level,
348 res.path.inv(),
349 res.inv_base(),
350 crate::mm::page_table::Child::<C>::Frame(paddr, parent_level, prop).wf(res),
351 ;
352
353 pub open spec fn match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
354 &&& pte.paddr() % PAGE_SIZE == 0
355 &&& pte.paddr() < MAX_PADDR
356 &&& !pte.is_present() ==> {
357 &&& self.is_absent()
358 &&& parent_level > 1 ==> !pte.is_last(parent_level)
359 }
360 &&& pte.is_present() && !pte.is_last(parent_level) ==> {
361 &&& self.is_node()
362 &&& meta_to_frame(self.node().meta_addr_self()) == pte.paddr()
363 }
364 &&& pte.is_present() && pte.is_last(parent_level) ==> {
365 &&& self.is_frame()
366 &&& self.frame().mapped_pa == pte.paddr()
367 &&& self.frame().prop == pte.prop()
368 }
369 }
370
371 pub open spec fn borrowed_match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
379 &&& self.is_borrowed()
380 &&& pte.paddr() % PAGE_SIZE == 0
381 &&& pte.paddr() < MAX_PADDR
382 &&& pte.is_present()
383 &&& !pte.is_last(parent_level)
384 }
385
386 pub proof fn absent_match_pte(owner: Self, pte: C::E, parent_level: PagingLevel)
388 requires
389 owner.is_absent(),
390 pte == C::E::new_absent_spec(),
391 pte.paddr() % PAGE_SIZE == 0,
392 pte.paddr() < MAX_PADDR,
393 ensures
394 owner.match_pte(pte, parent_level),
395 {
396 C::E::lemma_page_table_entry_properties();
397 if parent_level > 1 {
398 assert(!pte.is_last(parent_level));
399 }
400 }
401
402 pub proof fn last_pte_implies_frame_match(self, pte: C::E, parent_level: PagingLevel)
403 requires
404 self.inv(),
405 self.match_pte(pte, parent_level),
406 1 < parent_level,
407 pte.is_last(parent_level),
408 ensures
409 self.is_frame(),
410 self.frame().mapped_pa == pte.paddr(),
411 self.frame().prop == pte.prop(),
412 {
413 }
414
415 pub proof fn huge_frame_split_child_at(self, regions: MetaRegionOwners, idx: usize)
416 requires
417 self.inv(),
418 self.is_frame(),
419 regions.inv(),
420 1 < self.parent_level < NR_LEVELS,
421 idx < NR_ENTRIES,
422 ensures
423 self.frame().mapped_pa + idx * page_size((self.parent_level - 1) as PagingLevel)
424 < MAX_PADDR,
425 ((self.frame().mapped_pa + idx * page_size(
426 (self.parent_level - 1) as PagingLevel,
427 )) as Paddr) % page_size((self.parent_level - 1) as PagingLevel) == 0,
428 ((self.frame().mapped_pa + idx * page_size(
429 (self.parent_level - 1) as PagingLevel,
430 )) as Paddr) + page_size((self.parent_level - 1) as PagingLevel) <= MAX_PADDR,
431 ((self.frame().mapped_pa + idx * page_size(
432 (self.parent_level - 1) as PagingLevel,
433 )) as Paddr) % PAGE_SIZE == 0,
434 {
435 let pa = self.frame().mapped_pa;
436 let child_pa = (pa + idx * page_size((self.parent_level - 1) as PagingLevel)) as Paddr;
437 assert(self.parent_level == 2 || self.parent_level == 3);
438 assert(NR_ENTRIES == 512) by {
439 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
440 };
441 assert(crate::mm::nr_subpage_per_huge::<PagingConsts>() == 512usize) by {
442 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
443 };
444 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
445 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_level1();
446 assert(512usize.ilog2() == 9);
447 vstd::arithmetic::power2::lemma2_to64();
448 if self.parent_level == 2 {
449 assert(page_size(2) == (PAGE_SIZE * pow2((512usize.ilog2() * 1usize) as nat)) as usize);
450 assert(page_size(2) == 2097152);
451 assert(pa % page_size(2) == 0);
452 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(1, 2);
453 assert(child_pa % page_size(1) == 0);
454 assert(child_pa + page_size(1) <= MAX_PADDR) by {
455 assert(idx * 4096 + 4096 <= 2097152);
456 assert(child_pa + page_size(1) <= pa + page_size(2));
457 };
458 } else {
459 assert(self.parent_level == 3);
460 assert(page_size(3) == (PAGE_SIZE * pow2((512usize.ilog2() * 2usize) as nat)) as usize);
461 assert(page_size(3) == 1073741824);
462 assert(pa % page_size(3) == 0);
463 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_va_align_page_size(pa, 2);
464 assert(child_pa == pa + idx * page_size(2));
465 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(idx as int, page_size(2) as int);
466 vstd::arithmetic::div_mod::lemma_add_mod_noop(
467 pa as int,
468 (idx * page_size(2)) as int,
469 page_size(2) as int,
470 );
471 assert(child_pa % page_size(2) == 0);
472 assert(child_pa + page_size(2) <= MAX_PADDR) by {
473 assert(idx * 2097152 + 2097152 <= 1073741824);
474 assert(child_pa + page_size(2) <= pa + page_size(3));
475 };
476 }
477 }
478
479 pub proof fn frame_sub_pages_valid_preserved_at_own_slot(
482 self,
483 r0: MetaRegionOwners,
484 r1: MetaRegionOwners,
485 )
486 requires
487 self.inv(),
488 r0.inv(),
489 self.is_frame(),
490 self.parent_level <= NR_LEVELS,
491 self.frame_sub_pages_valid(r0),
492 r0.slots == r1.slots,
493 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
494 forall|i: usize|
495 #![trigger r1.slot_owners[i]]
496 i != frame_to_index(self.meta_slot_paddr()->0) && r0.slot_owners.contains_key(i)
497 ==> r0.slot_owners[i] == r1.slot_owners[i],
498 ensures
499 self.frame_sub_pages_valid(r1),
500 {
501 if self.parent_level > 1 {
502 let pa = self.frame().mapped_pa;
503 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
504 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
505 assert forall|j: usize|
506 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
507 0 < j < nr_pages implies {
508 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
509 &&& r1.slots.contains_key(sub_idx)
510 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
511 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
512 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
513 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
514 }
515 } by {
516 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
517 assert(r0.slots.contains_key(sub_idx));
519 let pa_plus_int: int = pa + j * PAGE_SIZE;
523 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
524 self.parent_level);
525 assert(j * PAGE_SIZE < nr_pages * PAGE_SIZE) by {
526 vstd::arithmetic::mul::lemma_mul_strict_inequality(
527 j as int,
528 nr_pages as int,
529 PAGE_SIZE as int,
530 );
531 };
532 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
533 self.parent_level,
534 );
535 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
536 j as int,
537 pa as int,
538 PAGE_SIZE as int,
539 );
540 assert(self_idx == pa as int / PAGE_SIZE as int);
541 assert(sub_idx != self_idx);
542 assert(r0.slot_owners.contains_key(sub_idx));
543 assert(r0.slot_owners[sub_idx] == r1.slot_owners[sub_idx]);
544 }
546 }
547 }
548
549 pub open spec fn frame_sub_pages_valid(self, regions: MetaRegionOwners) -> bool {
562 self.is_frame() && self.parent_level > 1 ==> {
563 let pa = self.frame().mapped_pa;
564 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
565 forall|j: usize|
566 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
567 0 < j < nr_pages ==> {
568 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
569 &&& regions.slots.contains_key(
572 sub_idx,
573 )
574 &&& regions.slot_owners[sub_idx].usage !is MMIO ==> {
578 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
579 != REF_COUNT_UNUSED
580 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
581 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
582 <= REF_COUNT_MAX
583 }
584 }
585 }
586 }
587
588 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
589 if self.is_node() {
590 let idx = frame_to_index(self.meta_slot_paddr()->0);
591 &&& regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
592 &&& 0 < regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
593 &&& regions.slot_owners[idx].slot_vaddr == self.node().meta_addr_self()
594 &&& regions.slots[idx].value().wf(regions.slot_owners[idx])
595 &&& regions.slot_owners[idx].paths_in_pt == set![self.path]
596 &&& self.node().metaregion_sound_node(regions)
597 } else if self.is_frame() {
598 let idx = frame_to_index(self.meta_slot_paddr()->0);
599 &&& regions.slots.contains_key(idx)
600 &&& regions.slots[idx].addr() == meta_addr(idx)
601 &&& regions.slots[idx].is_init()
602 &&& regions.slots[idx].value().wf(
603 regions.slot_owners[idx],
604 )
605 &&& regions.slot_owners[idx].usage !is MMIO ==> {
610 &&& regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
611 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
612 > 0
613 &&& regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
618 }
619 &&& regions.slot_owners[idx].paths_in_pt.contains(self.path)
620 &&& self.frame_sub_pages_valid(regions)
621 } else {
622 true
623 }
624 }
625
626 pub axiom fn active_entry_not_in_free_pool(
632 entry: Self,
633 regions: MetaRegionOwners,
634 free_idx: usize,
635 )
636 requires
637 regions.inv(),
638 entry.inv(),
639 entry.is_node(),
640 entry.metaregion_sound(regions),
641 regions.slots.contains_key(free_idx),
642 ensures
643 frame_to_index(entry.meta_slot_paddr()->0) != free_idx,
644 ;
645
646 pub open spec fn meta_slot_paddr(self) -> Option<Paddr> {
647 if self.is_node() {
648 Some(meta_to_frame(self.node().meta_addr_self()))
649 } else if self.is_frame() {
650 Some(self.frame().mapped_pa)
651 } else {
652 None
653 }
654 }
655
656 pub open spec fn meta_slot_paddr_neq(self, other: Self) -> bool {
657 self.meta_slot_paddr() is Some ==> other.meta_slot_paddr() is Some
658 ==> self.meta_slot_paddr()->0 != other.meta_slot_paddr()->0
659 }
660
661 pub proof fn metaregion_sound_slot_owners_only(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
665 requires
666 self.inv(),
667 self.metaregion_sound(r0),
668 r0.slot_owners == r1.slot_owners,
669 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
670 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
671 ensures
672 self.metaregion_sound(r1),
673 {
674 if self.is_node() {
675 let slot_idx = self.node().slot_index;
676 assert(r0.slots.contains_key(slot_idx));
677 assert(self.node().meta_perm_of(r1) == self.node().meta_perm_of(r0));
678 }
679 }
680
681 pub proof fn metaregion_sound_one_slot_changed(
684 self,
685 r0: MetaRegionOwners,
686 r1: MetaRegionOwners,
687 changed_idx: usize,
688 )
689 requires
690 self.inv(),
691 self.metaregion_sound(r0),
692 forall|i: usize|
693 #![trigger r1.slot_owners[i]]
694 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
695 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
696 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
698 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
699 self.meta_slot_paddr() is Some ==> frame_to_index(self.meta_slot_paddr()->0)
700 != changed_idx,
701 self.is_frame() && self.parent_level > 1 ==> {
705 let pa = self.frame().mapped_pa;
706 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
707 forall|j: usize|
708 0 < j < nr_pages ==> {
709 let sub_idx = #[trigger] frame_to_index((pa + j * PAGE_SIZE) as usize);
710 sub_idx != changed_idx || r1.slot_owners[sub_idx].usage is MMIO || (
711 r1.slots.contains_key(sub_idx)
712 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
713 != REF_COUNT_UNUSED
714 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
715 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
716 <= REF_COUNT_MAX)
717 }
718 },
719 ensures
720 self.metaregion_sound(r1),
721 {
722 if self.is_node() {
723 let slot_idx = self.node().slot_index;
724 let outer_idx = frame_to_index(self.meta_slot_paddr().unwrap());
725 assert(r0.slots.contains_key(slot_idx));
726 assert(slot_idx != changed_idx);
727 assert(r1.slot_owners[slot_idx] == r0.slot_owners[slot_idx]);
728 assert(self.node().meta_perm_of(r1) == self.node().meta_perm_of(r0));
729 }
730 }
731
732 pub proof fn metaregion_sound_paths_in_pt_changed(
735 self,
736 r0: MetaRegionOwners,
737 r1: MetaRegionOwners,
738 changed_idx: usize,
739 )
740 requires
741 self.inv(),
742 r0.inv(),
743 self.metaregion_sound(r0),
744 r0.slots == r1.slots,
745 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
746 forall|i: usize|
748 #![trigger r1.slot_owners[i]]
749 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
750 r1.slot_owners[changed_idx].inner_perms == r0.slot_owners[changed_idx].inner_perms,
752 r1.slot_owners[changed_idx].slot_vaddr == r0.slot_owners[changed_idx].slot_vaddr,
753 r1.slot_owners[changed_idx].usage == r0.slot_owners[changed_idx].usage,
754 self.is_node() && self.meta_slot_paddr() is Some && frame_to_index(
756 self.meta_slot_paddr()->0,
757 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt == set![self.path],
758 self.is_frame() && self.meta_slot_paddr() is Some && frame_to_index(
760 self.meta_slot_paddr()->0,
761 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt.contains(self.path),
762 self.is_frame() && self.parent_level > 1 ==> {
765 let pa = self.frame().mapped_pa;
766 let sub_level = (self.parent_level - 1) as PagingLevel;
767 forall|j: usize|
768 0 < j < NR_ENTRIES ==> {
769 let sub_idx = #[trigger] frame_to_index(
770 (pa + j * page_size(sub_level)) as usize,
771 );
772 sub_idx != changed_idx || r1.slot_owners[changed_idx].paths_in_pt.is_empty()
773 }
774 },
775 ensures
776 self.metaregion_sound(r1),
777 {
778 if self.meta_slot_paddr() is Some {
779 let eidx = frame_to_index(self.meta_slot_paddr().unwrap());
780 if self.is_frame() {
783 if eidx == changed_idx {
784 assert(r1.slot_owners[eidx].inner_perms == r0.slot_owners[eidx].inner_perms);
785 } else {
786 assert(r1.slot_owners[eidx] == r0.slot_owners[eidx]);
787 }
788 if self.parent_level > 1 {
791 let pa = self.frame().mapped_pa;
792 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
793 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
794 assert forall|j: usize|
795 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
796 0 < j < nr_pages implies {
797 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
798 &&& r1.slots.contains_key(sub_idx)
799 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
800 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value()
801 != REF_COUNT_UNUSED
802 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
803 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value()
804 <= REF_COUNT_MAX
805 }
806 } by {
807 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
808 assert(r0.slots.contains_key(sub_idx));
810 if sub_idx == changed_idx {
811 assert(r1.slot_owners[sub_idx].inner_perms
812 == r0.slot_owners[sub_idx].inner_perms);
813 assert(r1.slot_owners[sub_idx].usage == r0.slot_owners[sub_idx].usage);
814 } else {
815 assert(r1.slot_owners[sub_idx] == r0.slot_owners[sub_idx]);
816 }
817 }
818 }
819 }
820 }
821 }
822
823 pub proof fn same_paddr_implies_same_path(self, other: Self, regions: MetaRegionOwners)
826 requires
827 self.meta_slot_paddr() is Some,
828 self.meta_slot_paddr() == other.meta_slot_paddr(),
829 regions.slot_owners[frame_to_index(self.meta_slot_paddr()->0)].paths_in_pt
830 == set![self.path],
831 regions.slot_owners[frame_to_index(self.meta_slot_paddr()->0)].paths_in_pt
832 == set![other.path],
833 ensures
834 self.path == other.path,
835 {
836 assert(set![self.path].contains(other.path));
837 }
838
839 pub proof fn metaregion_sound_rc_value_changed(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
842 requires
843 self.inv(),
844 r0.inv(),
845 self.metaregion_sound(r0),
846 self.meta_slot_paddr() is Some,
847 r0.slots == r1.slots,
848 ({
849 let idx = frame_to_index(self.meta_slot_paddr()->0);
850 &&& r1.slot_owners[idx].inner_perms.ref_count.id()
851 == r0.slot_owners[idx].inner_perms.ref_count.id()
852 &&& r1.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
853 &&& r1.slot_owners[idx].inner_perms.ref_count.value()
854 > 0
855 &&& r1.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
857 &&& r1.slot_owners[idx].inner_perms.storage
858 == r0.slot_owners[idx].inner_perms.storage
859 &&& r1.slot_owners[idx].inner_perms.vtable_ptr
860 == r0.slot_owners[idx].inner_perms.vtable_ptr
861 &&& r1.slot_owners[idx].inner_perms.in_list
862 == r0.slot_owners[idx].inner_perms.in_list
863 &&& r1.slot_owners[idx].slot_vaddr == r0.slot_owners[idx].slot_vaddr
864 &&& r1.slot_owners[idx].paths_in_pt
865 == r0.slot_owners[idx].paths_in_pt
866 &&& r1.slot_owners[idx].usage == r0.slot_owners[idx].usage
869 }),
870 forall|i: usize|
872 #![trigger r1.slot_owners[i]]
873 i != frame_to_index(self.meta_slot_paddr()->0) && r0.slot_owners.contains_key(i)
874 ==> r0.slot_owners[i] == r1.slot_owners[i],
875 ensures
876 self.metaregion_sound(r1),
877 {
878 if self.is_frame() && self.parent_level > 1 {
879 let pa = self.frame().mapped_pa;
880 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
881 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
882 assert forall|j: usize|
883 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
884 0 < j < nr_pages implies {
885 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
886 &&& r1.slots.contains_key(sub_idx)
887 &&& r1.slot_owners[sub_idx].usage !is MMIO ==> {
888 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
889 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
890 }
891 } by {
892 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
893 assert(r0.slots.contains_key(sub_idx));
894 let pa_plus_int: int = pa + j * PAGE_SIZE;
895 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
896 self.parent_level);
897 assert(j * PAGE_SIZE < nr_pages * PAGE_SIZE) by {
898 vstd::arithmetic::mul::lemma_mul_strict_inequality(
899 j as int,
900 nr_pages as int,
901 PAGE_SIZE as int,
902 );
903 };
904 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
905 self.parent_level,
906 );
907 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
909 j as int,
910 pa as int,
911 PAGE_SIZE as int,
912 );
913 assert(self_idx == pa as int / PAGE_SIZE as int);
914 assert(sub_idx != self_idx);
915 assert(r0.slot_owners.contains_key(sub_idx));
916 assert(r0.slot_owners[sub_idx] == r1.slot_owners[sub_idx]);
917 }
918 }
919 }
920
921 pub proof fn nodes_different_paths_different_addrs(self, other: Self, regions: MetaRegionOwners)
924 requires
925 self.is_node(),
926 other.is_node(),
927 self.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(
928 self.meta_slot_paddr()->0,
929 )].paths_in_pt == set![self.path],
930 other.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(
931 other.meta_slot_paddr()->0,
932 )].paths_in_pt == set![other.path],
933 self.path != other.path,
934 ensures
935 self.node().meta_addr_self() != other.node().meta_addr_self(),
936 {
937 let slot_vaddr = self.node().meta_addr_self();
938 let other_addr = other.node().meta_addr_self();
939 let self_idx = frame_to_index(meta_to_frame(slot_vaddr));
940 let other_idx = frame_to_index(meta_to_frame(other_addr));
941
942 if slot_vaddr == other_addr {
943 assert(regions.slot_owners[self_idx].paths_in_pt == set![self.path]);
944 assert(regions.slot_owners[other_idx].paths_in_pt == set![other.path]);
945 assert(set![self.path].contains(other.path));
946 assert(self.path == other.path);
947 assert(false); }
949 }
950
951 pub proof fn nodes_different_path_lengths_neq_slot(self, other: Self, regions: MetaRegionOwners)
958 requires
959 self.is_node(),
960 other.is_node(),
961 self.metaregion_sound(regions),
962 other.metaregion_sound(regions),
963 self.path.len() != other.path.len(),
964 ensures
965 self.meta_slot_paddr_neq(other),
966 {
967 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
968 let other_idx = frame_to_index(other.meta_slot_paddr().unwrap());
969 if self_idx == other_idx {
970 assert(regions.slot_owners[self_idx].paths_in_pt == set![self.path]);
971 assert(regions.slot_owners[other_idx].paths_in_pt == set![other.path]);
972 assert(set![self.path].contains(other.path));
973 assert(self.path == other.path);
974 assert(false);
975 }
976 }
977}
978
979impl<C: PageTableConfig> EntryOwner<C> {
980 pub open spec fn inv_base(self) -> bool {
983 &&& self.is_node() ==> {
984 &&& self.node().inv()
985 &&& self.parent_level == self.node().level + 1
986 }
987 &&& self.is_frame() ==> {
988 &&& 1 <= self.parent_level < NR_LEVELS
993 &&& self.frame().mapped_pa % PAGE_SIZE == 0
994 &&& self.frame().mapped_pa < MAX_PADDR
995 &&& self.frame().size == page_size(self.parent_level)
996 &&& self.frame().mapped_pa % page_size(self.parent_level) == 0
997 &&& self.frame().mapped_pa + page_size(self.parent_level) <= MAX_PADDR
998 }
999 &&& self.is_borrowed() ==> { true }
1000 &&& self.path.inv()
1001 }
1002}
1003
1004impl<C: PageTableConfig> Inv for EntryOwner<C> {
1005 open spec fn inv(self) -> bool {
1006 self.inv_base()
1007 }
1008}
1009
1010impl<C: PageTableConfig> View for EntryOwner<C> {
1011 type V = EntryView<C>;
1012
1013 open spec fn view(&self) -> <Self as View>::V {
1014 if self.is_frame() {
1015 let frame = self.frame();
1016 EntryView::Leaf {
1017 leaf: LeafPageTableEntryView {
1018 map_va: vaddr(self.path) as int,
1019 map_to_pa: frame.mapped_pa as int,
1022 level: self.path.len() as u8,
1023 prop: frame.prop,
1024 phantom: PhantomData,
1025 },
1026 }
1027 } else if self.is_node() {
1028 let node = self.node();
1029 EntryView::Intermediate {
1030 node: IntermediatePageTableEntryView {
1031 map_va: vaddr(self.path) as int,
1032 map_to_pa: meta_to_frame(node.meta_addr_self()) as int,
1035 level: self.path.len() as u8,
1036 phantom: PhantomData,
1037 },
1038 }
1039 } else {
1040 EntryView::Absent
1041 }
1042 }
1043}
1044
1045impl<C: PageTableConfig> InvView for EntryOwner<C> {
1046 proof fn view_preserves_inv(self) {
1047 }
1051}
1052
1053impl<'a, 'rcu, C: PageTableConfig> OwnerOf for Entry<'a, 'rcu, C> {
1054 type Owner = EntryOwner<C>;
1055
1056 open spec fn wf(self, owner: Self::Owner) -> bool {
1057 &&& self.idx < NR_ENTRIES
1058 &&& owner.match_pte(self.pte, owner.parent_level)
1059 &&& self.pte.paddr() % PAGE_SIZE == 0
1060 &&& self.pte.paddr() < MAX_PADDR
1061 }
1062}
1063
1064}