1use vstd::prelude::*;
2
3use vstd::cell;
4use vstd::simple_pptr::PointsTo;
5use vstd_extra::array_ptr;
6use vstd_extra::ghost_tree::*;
7use vstd_extra::ownership::*;
8
9use crate::mm::frame::meta::MetaSlot;
10use crate::mm::frame::meta::{REF_COUNT_MAX, REF_COUNT_UNUSED};
11use crate::mm::page_prop::PageProperty;
12use crate::mm::page_table::*;
13use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
14use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
15use crate::specs::arch::paging_consts::PagingConsts;
16use crate::specs::arch::*;
17use crate::specs::mm::frame::mapping::{frame_to_index, meta_addr, meta_to_frame};
18use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
19use crate::specs::mm::page_table::node::entry_view::*;
20use crate::specs::mm::page_table::*;
21use core::marker::PhantomData;
22
23verus! {
24
25pub tracked struct FrameEntryOwner {
26 pub mapped_pa: usize,
27 pub size: usize,
28 pub prop: PageProperty,
29 pub is_tracked: bool,
33}
34
35pub tracked struct EntryOwner<C: PageTableConfig> {
36 pub node: Option<NodeOwner<C>>,
37 pub frame: Option<FrameEntryOwner>,
38 pub locked: Option<Ghost<Seq<FrameView<C>>>>,
39 pub borrowed: Option<Ghost<Set<Mapping>>>,
49 pub absent: bool,
50 pub in_scope: bool,
51 pub path: TreePath<NR_ENTRIES>,
52 pub parent_level: PagingLevel,
53}
54
55impl<C: PageTableConfig> EntryOwner<C> {
56 pub open spec fn is_node(self) -> bool {
57 self.node is Some
58 }
59
60 pub open spec fn is_frame(self) -> bool {
61 self.frame is Some
62 }
63
64 pub open spec fn is_locked(self) -> bool {
65 self.locked is Some
66 }
67
68 pub open spec fn is_absent(self) -> bool {
69 self.absent
70 }
71
72 pub open spec fn is_borrowed(self) -> bool {
73 self.borrowed is Some
74 }
75
76 pub open spec fn new_absent(path: TreePath<NR_ENTRIES>, parent_level: PagingLevel) -> Self {
77 EntryOwner {
78 node: None,
79 frame: None,
80 locked: None,
81 borrowed: None,
82 absent: true,
83 in_scope: true,
84 path,
85 parent_level,
86 }
87 }
88
89 pub open spec fn new_frame(
90 paddr: Paddr,
91 path: TreePath<NR_ENTRIES>,
92 parent_level: PagingLevel,
93 prop: PageProperty,
94 is_tracked: bool,
95 ) -> Self {
96 EntryOwner {
97 node: None,
98 frame: Some(
99 FrameEntryOwner {
100 mapped_pa: paddr,
101 size: page_size(parent_level),
102 prop,
103 is_tracked,
104 },
105 ),
106 locked: None,
107 borrowed: None,
108 absent: false,
109 in_scope: true,
110 path,
111 parent_level,
112 }
113 }
114
115 pub open spec fn new_node(node: NodeOwner<C>, path: TreePath<NR_ENTRIES>) -> Self {
116 EntryOwner {
117 node: Some(node),
118 frame: None,
119 locked: None,
120 borrowed: None,
121 absent: false,
122 in_scope: true,
123 path,
124 parent_level: (node.level + 1) as PagingLevel,
125 }
126 }
127
128 pub open spec fn new_borrowed(
131 path: TreePath<NR_ENTRIES>,
132 parent_level: PagingLevel,
133 mappings: Set<Mapping>,
134 ) -> Self {
135 EntryOwner {
136 node: None,
137 frame: None,
138 locked: None,
139 borrowed: Some(Ghost(mappings)),
140 absent: false,
141 in_scope: true,
142 path,
143 parent_level,
144 }
145 }
146
147 pub axiom fn tracked_new_borrowed(
148 path: TreePath<NR_ENTRIES>,
149 parent_level: PagingLevel,
150 mappings: Set<Mapping>,
151 ) -> tracked Self
152 returns
153 Self::new_borrowed(path, parent_level, mappings),
154 ;
155
156 pub axiom fn tracked_new_absent(
157 path: TreePath<NR_ENTRIES>,
158 parent_level: PagingLevel,
159 ) -> tracked Self
160 returns
161 Self::new_absent(path, parent_level),
162 ;
163
164 pub axiom fn set_path_axiom(tracked &mut self, path: TreePath<NR_ENTRIES>)
169 ensures
170 *final(self) == (EntryOwner { path, ..*old(self) }),
171 ;
172
173 pub axiom fn tracked_new_frame(
174 paddr: Paddr,
175 path: TreePath<NR_ENTRIES>,
176 parent_level: PagingLevel,
177 prop: PageProperty,
178 is_tracked: bool,
179 ) -> tracked Self
180 returns
181 Self::new_frame(paddr, path, parent_level, prop, is_tracked),
182 ;
183
184 pub axiom fn axiom_frame_is_tracked_matches_item(entry: Self)
200 requires
201 entry.is_frame(),
202 entry.inv_base(),
203 ensures
204 entry.frame.unwrap().is_tracked == C::tracked(
205 C::item_from_raw_spec(
206 entry.frame.unwrap().mapped_pa,
207 entry.parent_level,
208 entry.frame.unwrap().prop,
209 ),
210 ),
211 ;
212
213 pub broadcast axiom fn axiom_frame_is_tracked_iff_not_mmio(entry: Self)
219 requires
220 entry.is_frame(),
221 entry.inv_base(),
222 ensures
223 #[trigger] entry.frame.unwrap().is_tracked
224 != crate::specs::mm::frame::meta_owners::is_mmio_paddr(
225 entry.frame.unwrap().mapped_pa,
226 ),
227 ;
228
229 pub axiom fn tracked_new_node(node: NodeOwner<C>, path: TreePath<NR_ENTRIES>) -> tracked Self
230 returns
231 Self::new_node(node, path),
232 ;
233
234 pub axiom fn new_untracked_frame(
242 paddr: Paddr,
243 parent_level: PagingLevel,
244 prop: PageProperty,
245 ) -> (tracked res: Self)
246 requires
247 paddr % PAGE_SIZE == 0,
248 paddr < MAX_PADDR,
249 1 <= parent_level,
250 parent_level <= NR_LEVELS,
251 ensures
252 res.is_frame(),
253 res.frame.unwrap().mapped_pa == paddr,
254 res.frame.unwrap().prop == prop,
255 res.frame.unwrap().size == page_size(parent_level),
256 res.frame.unwrap().is_tracked == false,
257 res.parent_level == parent_level,
258 res.path.inv(),
259 res.in_scope,
260 res.inv_base(),
261 crate::mm::page_table::Child::<C>::Frame(paddr, parent_level, prop).wf(res),
262 ;
263
264 pub open spec fn match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
265 &&& pte.paddr() % PAGE_SIZE == 0
266 &&& pte.paddr() < MAX_PADDR
267 &&& !pte.is_present() ==> {
268 &&& self.is_absent()
269 &&& parent_level > 1 ==> !pte.is_last(parent_level)
270 }
271 &&& pte.is_present() && !pte.is_last(parent_level) ==> {
272 &&& self.is_node()
273 &&& meta_to_frame(self.node.unwrap().meta_addr_self()) == pte.paddr()
274 }
275 &&& pte.is_present() && pte.is_last(parent_level) ==> {
276 &&& self.is_frame()
277 &&& self.frame.unwrap().mapped_pa == pte.paddr()
278 &&& self.frame.unwrap().prop == pte.prop()
279 }
280 }
281
282 pub open spec fn borrowed_match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
290 &&& self.is_borrowed()
291 &&& pte.paddr() % PAGE_SIZE == 0
292 &&& pte.paddr() < MAX_PADDR
293 &&& pte.is_present()
294 &&& !pte.is_last(parent_level)
295 }
296
297 pub proof fn absent_match_pte(owner: Self, pte: C::E, parent_level: PagingLevel)
299 requires
300 owner.is_absent(),
301 pte == C::E::new_absent_spec(),
302 pte.paddr() % PAGE_SIZE == 0,
303 pte.paddr() < MAX_PADDR,
304 ensures
305 owner.match_pte(pte, parent_level),
306 {
307 C::E::new_properties();
308 assert(!pte.is_present());
309 if parent_level > 1 {
310 assert(!pte.is_last(parent_level));
311 }
312 if pte.is_present() && !pte.is_last(parent_level) {
313 assert(pte.is_present());
314 assert(!pte.is_present());
315 }
316 if pte.is_present() && pte.is_last(parent_level) {
317 assert(pte.is_present());
318 assert(!pte.is_present());
319 }
320 }
321
322 pub proof fn last_pte_implies_frame_match(self, pte: C::E, parent_level: PagingLevel)
323 requires
324 self.inv(),
325 self.match_pte(pte, parent_level),
326 1 < parent_level,
327 pte.is_last(parent_level),
328 ensures
329 self.is_frame(),
330 self.frame.unwrap().mapped_pa == pte.paddr(),
331 self.frame.unwrap().prop == pte.prop(),
332 {
333 if !pte.is_present() {
334 assert(self.is_absent());
335 assert(!pte.is_last(parent_level));
336 assert(false);
337 }
338 assert(self.is_frame());
339 assert(self.frame.unwrap().mapped_pa == pte.paddr());
340 assert(self.frame.unwrap().prop == pte.prop());
341 }
342
343 pub proof fn huge_frame_split_child_at(self, regions: MetaRegionOwners, idx: usize)
344 requires
345 self.inv(),
346 self.is_frame(),
347 regions.inv(),
348 1 < self.parent_level < NR_LEVELS,
349 idx < NR_ENTRIES,
350 ensures
351 self.frame.unwrap().mapped_pa + idx * page_size((self.parent_level - 1) as PagingLevel)
352 < MAX_PADDR,
353 ((self.frame.unwrap().mapped_pa + idx * page_size(
354 (self.parent_level - 1) as PagingLevel,
355 )) as Paddr) % page_size((self.parent_level - 1) as PagingLevel) == 0,
356 ((self.frame.unwrap().mapped_pa + idx * page_size(
357 (self.parent_level - 1) as PagingLevel,
358 )) as Paddr) + page_size((self.parent_level - 1) as PagingLevel) <= MAX_PADDR,
359 ((self.frame.unwrap().mapped_pa + idx * page_size(
360 (self.parent_level - 1) as PagingLevel,
361 )) as Paddr) % PAGE_SIZE == 0,
362 {
363 let pa = self.frame.unwrap().mapped_pa;
364 let child_pa = (pa + idx * page_size((self.parent_level - 1) as PagingLevel)) as Paddr;
365 assert(self.parent_level == 2 || self.parent_level == 3);
366 assert(NR_ENTRIES == 512) by {
367 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
368 };
369 assert(crate::mm::nr_subpage_per_huge::<PagingConsts>() == 512usize) by {
370 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
371 };
372 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
373 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_level1();
374 assert(512usize.ilog2() == 9);
375 assert(crate::mm::nr_subpage_per_huge::<PagingConsts>().ilog2() == 512usize.ilog2());
376 vstd::arithmetic::power2::lemma2_to64();
377 if self.parent_level == 2 {
378 assert(page_size_spec(1) == 4096);
379 assert(page_size_spec(2) == (PAGE_SIZE * pow2(
380 (512usize.ilog2() * 1usize) as nat,
381 )) as usize);
382 assert(page_size_spec(2) == (4096 * pow2(9)) as usize);
383 assert(page_size_spec(2) == 2097152);
384 assert(pa % page_size(2) == 0);
385 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides(1, 2);
386 assert(child_pa % page_size(1) == 0);
387 assert(child_pa + page_size(1) <= MAX_PADDR) by {
388 assert(idx < 512);
389 assert(idx * 4096 + 4096 <= 2097152);
390 assert(child_pa + page_size(1) <= pa + page_size(2));
391 };
392 } else {
393 assert(self.parent_level == 3);
394 assert(page_size_spec(2) == (PAGE_SIZE * pow2(
395 (512usize.ilog2() * 1usize) as nat,
396 )) as usize);
397 assert(page_size_spec(2) == (4096 * pow2(9)) as usize);
398 assert(page_size_spec(2) == 2097152);
399 assert(page_size_spec(3) == (PAGE_SIZE * pow2(
400 (512usize.ilog2() * 2usize) as nat,
401 )) as usize);
402 assert(page_size_spec(3) == (4096 * pow2(18)) as usize);
403 assert(page_size_spec(3) == 1073741824);
404 assert(pa % page_size(3) == 0);
405 assert(pa % PAGE_SIZE == 0);
406 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_va_align_page_size(pa, 2);
407 assert(child_pa == pa + idx * page_size(2));
408 vstd::arithmetic::div_mod::lemma_mod_multiples_basic(idx as int, page_size(2) as int);
409 vstd::arithmetic::div_mod::lemma_add_mod_noop(
410 pa as int,
411 (idx * page_size(2)) as int,
412 page_size(2) as int,
413 );
414 assert(child_pa % page_size(2) == 0);
415 assert(child_pa + page_size(2) <= MAX_PADDR) by {
416 assert(idx < 512);
417 assert(idx * 2097152 + 2097152 <= 1073741824);
418 assert(child_pa + page_size(2) <= pa + page_size(3));
419 };
420 }
421 assert(child_pa < MAX_PADDR);
422 assert(child_pa % PAGE_SIZE == 0);
423 }
424
425 pub proof fn frame_sub_pages_valid_preserved_at_own_slot(
428 self,
429 r0: MetaRegionOwners,
430 r1: MetaRegionOwners,
431 )
432 requires
433 self.inv(),
434 r0.inv(),
435 self.is_frame(),
436 self.parent_level <= NR_LEVELS,
437 self.frame_sub_pages_valid(r0),
438 r0.slots == r1.slots,
439 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
440 forall|i: usize|
441 #![trigger r1.slot_owners[i]]
442 i != frame_to_index(self.meta_slot_paddr().unwrap()) && r0.slot_owners.contains_key(
443 i,
444 ) ==> r0.slot_owners[i] == r1.slot_owners[i],
445 ensures
446 self.frame_sub_pages_valid(r1),
447 {
448 if self.parent_level > 1 {
449 let pa = self.frame.unwrap().mapped_pa;
450 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
451 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
452 assert forall|j: usize|
453 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
454 0 < j < nr_pages implies {
455 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
456 &&& r1.slots.contains_key(sub_idx)
457 &&& r1.slot_owners[sub_idx].usage
458 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
459 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
460 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
461 }
462 } by {
463 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
464 assert(r0.slots.contains_key(sub_idx));
466 let pa_plus_int: int = pa as int + (j as int) * (PAGE_SIZE as int);
470 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
471 self.parent_level);
472 assert((j as int) * (PAGE_SIZE as int) < (nr_pages as int) * (PAGE_SIZE as int))
473 by {
474 vstd::arithmetic::mul::lemma_mul_strict_inequality(
475 j as int,
476 nr_pages as int,
477 PAGE_SIZE as int,
478 );
479 };
480 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
481 self.parent_level,
482 );
483 assert(pa_plus_int < MAX_PADDR);
484 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
485 j as int,
486 pa as int,
487 PAGE_SIZE as int,
488 );
489 assert(self_idx as int == pa as int / PAGE_SIZE as int);
490 assert(sub_idx != self_idx);
491 assert(r0.slot_owners.contains_key(sub_idx));
492 assert(r0.slot_owners[sub_idx] == r1.slot_owners[sub_idx]);
493 }
495 }
496 }
497
498 pub open spec fn frame_sub_pages_valid(self, regions: MetaRegionOwners) -> bool {
511 self.is_frame() && self.parent_level > 1 ==> {
512 let pa = self.frame.unwrap().mapped_pa;
513 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
514 forall|j: usize|
515 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
516 0 < j < nr_pages ==> {
517 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
518 &&& regions.slots.contains_key(
521 sub_idx,
522 )
523 &&& regions.slot_owners[sub_idx].usage
527 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
528 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value()
529 != REF_COUNT_UNUSED
530 &&& regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
531 }
532 }
533 }
534 }
535
536 pub open spec fn metaregion_sound(self, regions: MetaRegionOwners) -> bool {
537 if self.is_node() {
538 let idx = frame_to_index(self.meta_slot_paddr().unwrap());
539 &&& regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
540 &&& 0 < regions.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
541 &&& regions.slot_owners[idx].self_addr == self.node.unwrap().meta_addr_self()
542 &&& regions.slots[idx].value().wf(regions.slot_owners[idx])
543 &&& regions.slot_owners[idx].paths_in_pt == set![self.path]
544 &&& self.node.unwrap().metaregion_sound_node(regions)
545 } else if self.is_frame() {
546 let idx = frame_to_index(self.meta_slot_paddr().unwrap());
547 &&& regions.slots.contains_key(idx)
548 &&& regions.slots[idx].addr() == meta_addr(idx)
549 &&& regions.slots[idx].is_init()
550 &&& regions.slots[idx].value().wf(
551 regions.slot_owners[idx],
552 )
553 &&& regions.slot_owners[idx].usage
558 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
559 &&& regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
560 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
561 }
562 &&& regions.slot_owners[idx].paths_in_pt.contains(self.path)
563 &&& self.frame_sub_pages_valid(regions)
564 } else {
565 true
566 }
567 }
568
569 pub axiom fn active_entry_not_in_free_pool(
575 entry: Self,
576 regions: MetaRegionOwners,
577 free_idx: usize,
578 )
579 requires
580 regions.inv(),
581 entry.inv(),
582 entry.is_node(),
583 entry.metaregion_sound(regions),
584 regions.slots.contains_key(free_idx),
585 ensures
586 frame_to_index(entry.meta_slot_paddr().unwrap()) != free_idx,
587 ;
588
589 pub axiom fn get_path(self) -> tracked TreePath<NR_ENTRIES>
590 returns
591 self.path,
592 ;
593
594 pub open spec fn meta_slot_paddr(self) -> Option<Paddr> {
595 if self.is_node() {
596 Some(meta_to_frame(self.node.unwrap().meta_addr_self()))
597 } else if self.is_frame() {
598 Some(self.frame.unwrap().mapped_pa)
599 } else {
600 None
601 }
602 }
603
604 pub open spec fn meta_slot_paddr_neq(self, other: Self) -> bool {
605 self.meta_slot_paddr() is Some ==> other.meta_slot_paddr() is Some
606 ==> self.meta_slot_paddr().unwrap() != other.meta_slot_paddr().unwrap()
607 }
608
609 pub proof fn metaregion_sound_slot_owners_only(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
613 requires
614 self.inv(),
615 self.metaregion_sound(r0),
616 r0.slot_owners == r1.slot_owners,
617 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
618 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
619 ensures
620 self.metaregion_sound(r1),
621 {
622 if self.is_node() {
623 let slot_idx = self.node.unwrap().slot_index;
624 assert(r0.slots.contains_key(slot_idx));
625 assert(self.node.unwrap().meta_perm_of(r1) == self.node.unwrap().meta_perm_of(r0));
626 }
627 }
628
629 pub proof fn metaregion_sound_one_slot_changed(
632 self,
633 r0: MetaRegionOwners,
634 r1: MetaRegionOwners,
635 changed_idx: usize,
636 )
637 requires
638 self.inv(),
639 self.metaregion_sound(r0),
640 forall|i: usize|
641 #![trigger r1.slot_owners[i]]
642 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
643 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
644 forall|k: usize| r0.slots.contains_key(k) ==> #[trigger] r1.slots.contains_key(k),
646 forall|k: usize| r0.slots.contains_key(k) ==> r0.slots[k] == #[trigger] r1.slots[k],
647 self.meta_slot_paddr() is Some ==> frame_to_index(self.meta_slot_paddr().unwrap())
648 != changed_idx,
649 self.is_frame() && self.parent_level > 1 ==> {
653 let pa = self.frame.unwrap().mapped_pa;
654 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
655 forall|j: usize|
656 0 < j < nr_pages ==> {
657 let sub_idx = #[trigger] frame_to_index((pa + j * PAGE_SIZE) as usize);
658 sub_idx != changed_idx || r1.slot_owners[sub_idx].usage
659 == crate::specs::mm::frame::meta_owners::PageUsage::MMIO || (
660 r1.slots.contains_key(sub_idx)
661 && r1.slot_owners[sub_idx].inner_perms.ref_count.value()
662 != REF_COUNT_UNUSED
663 && r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0)
664 }
665 },
666 ensures
667 self.metaregion_sound(r1),
668 {
669 if self.is_node() {
670 let slot_idx = self.node.unwrap().slot_index;
671 let outer_idx = frame_to_index(self.meta_slot_paddr().unwrap());
672 assert(r0.slots.contains_key(slot_idx));
673 assert(slot_idx != changed_idx);
674 assert(r1.slot_owners[slot_idx] == r0.slot_owners[slot_idx]);
675 assert(self.node.unwrap().meta_perm_of(r1) == self.node.unwrap().meta_perm_of(r0));
676 }
677 }
678
679 pub proof fn metaregion_sound_paths_in_pt_changed(
682 self,
683 r0: MetaRegionOwners,
684 r1: MetaRegionOwners,
685 changed_idx: usize,
686 )
687 requires
688 self.inv(),
689 r0.inv(),
690 self.metaregion_sound(r0),
691 r0.slots == r1.slots,
692 r0.slot_owners.dom() =~= r1.slot_owners.dom(),
693 forall|i: usize|
695 #![trigger r1.slot_owners[i]]
696 i != changed_idx ==> r0.slot_owners[i] == r1.slot_owners[i],
697 r1.slot_owners[changed_idx].inner_perms == r0.slot_owners[changed_idx].inner_perms,
699 r1.slot_owners[changed_idx].self_addr == r0.slot_owners[changed_idx].self_addr,
700 r1.slot_owners[changed_idx].usage == r0.slot_owners[changed_idx].usage,
701 self.is_node() && self.meta_slot_paddr() is Some && frame_to_index(
703 self.meta_slot_paddr().unwrap(),
704 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt == set![self.path],
705 self.is_frame() && self.meta_slot_paddr() is Some && frame_to_index(
707 self.meta_slot_paddr().unwrap(),
708 ) == changed_idx ==> r1.slot_owners[changed_idx].paths_in_pt.contains(self.path),
709 self.is_frame() && self.parent_level > 1 ==> {
712 let pa = self.frame.unwrap().mapped_pa;
713 let sub_level = (self.parent_level - 1) as PagingLevel;
714 forall|j: usize|
715 0 < j < NR_ENTRIES ==> {
716 let sub_idx = #[trigger] frame_to_index(
717 (pa + j * page_size(sub_level)) as usize,
718 );
719 sub_idx != changed_idx || r1.slot_owners[changed_idx].paths_in_pt.is_empty()
720 }
721 },
722 ensures
723 self.metaregion_sound(r1),
724 {
725 if self.meta_slot_paddr() is Some {
726 let eidx = frame_to_index(self.meta_slot_paddr().unwrap());
727 if self.is_frame() {
730 if eidx == changed_idx {
731 assert(r1.slot_owners[eidx].inner_perms == r0.slot_owners[eidx].inner_perms);
732 } else {
733 assert(r1.slot_owners[eidx] == r0.slot_owners[eidx]);
734 }
735 if self.parent_level > 1 {
738 let pa = self.frame.unwrap().mapped_pa;
739 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
740 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
741 assert forall|j: usize|
742 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
743 0 < j < nr_pages implies {
744 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
745 &&& r1.slots.contains_key(sub_idx)
746 &&& r1.slot_owners[sub_idx].usage
747 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
748 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value()
749 != REF_COUNT_UNUSED
750 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
751 }
752 } by {
753 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
754 assert(r0.slots.contains_key(sub_idx));
756 if sub_idx == changed_idx {
757 assert(r1.slot_owners[sub_idx].inner_perms
758 == r0.slot_owners[sub_idx].inner_perms);
759 assert(r1.slot_owners[sub_idx].usage == r0.slot_owners[sub_idx].usage);
760 } else {
761 assert(r1.slot_owners[sub_idx] == r0.slot_owners[sub_idx]);
762 }
763 }
764 }
765 }
766 }
767 }
768
769 pub proof fn same_paddr_implies_same_path(self, other: Self, regions: MetaRegionOwners)
772 requires
773 self.meta_slot_paddr() is Some,
774 self.meta_slot_paddr() == other.meta_slot_paddr(),
775 regions.slot_owners[frame_to_index(self.meta_slot_paddr().unwrap())].paths_in_pt
776 == set![self.path],
777 regions.slot_owners[frame_to_index(self.meta_slot_paddr().unwrap())].paths_in_pt
778 == set![other.path],
779 ensures
780 self.path == other.path,
781 {
782 assert(set![self.path].contains(other.path));
783 }
784
785 pub proof fn metaregion_sound_rc_value_changed(self, r0: MetaRegionOwners, r1: MetaRegionOwners)
788 requires
789 self.inv(),
790 r0.inv(),
791 self.metaregion_sound(r0),
792 self.meta_slot_paddr() is Some,
793 r0.slots == r1.slots,
794 ({
795 let idx = frame_to_index(self.meta_slot_paddr().unwrap());
796 &&& r1.slot_owners[idx].inner_perms.ref_count.id()
797 == r0.slot_owners[idx].inner_perms.ref_count.id()
798 &&& r1.slot_owners[idx].inner_perms.ref_count.value()
799 != crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED
800 &&& r1.slot_owners[idx].inner_perms.ref_count.value()
801 > 0
802 &&& r1.slot_owners[idx].inner_perms.ref_count.value() <= REF_COUNT_MAX
804 &&& r1.slot_owners[idx].inner_perms.storage
805 == r0.slot_owners[idx].inner_perms.storage
806 &&& r1.slot_owners[idx].inner_perms.vtable_ptr
807 == r0.slot_owners[idx].inner_perms.vtable_ptr
808 &&& r1.slot_owners[idx].inner_perms.in_list
809 == r0.slot_owners[idx].inner_perms.in_list
810 &&& r1.slot_owners[idx].self_addr == r0.slot_owners[idx].self_addr
811 &&& r1.slot_owners[idx].paths_in_pt == r0.slot_owners[idx].paths_in_pt
812 }),
813 forall|i: usize|
815 #![trigger r1.slot_owners[i]]
816 i != frame_to_index(self.meta_slot_paddr().unwrap()) && r0.slot_owners.contains_key(
817 i,
818 ) ==> r0.slot_owners[i] == r1.slot_owners[i],
819 ensures
820 self.metaregion_sound(r1),
821 {
822 if self.is_frame() && self.parent_level > 1 {
823 let pa = self.frame.unwrap().mapped_pa;
824 let nr_pages = page_size(self.parent_level) / PAGE_SIZE;
825 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
826 assert forall|j: usize|
827 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
828 0 < j < nr_pages implies {
829 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
830 &&& r1.slots.contains_key(sub_idx)
831 &&& r1.slot_owners[sub_idx].usage
832 != crate::specs::mm::frame::meta_owners::PageUsage::MMIO ==> {
833 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
834 &&& r1.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
835 }
836 } by {
837 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
838 assert(r0.slots.contains_key(sub_idx));
839 let pa_plus_int: int = pa as int + (j as int) * (PAGE_SIZE as int);
840 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
841 self.parent_level);
842 assert((j as int) * (PAGE_SIZE as int) < (nr_pages as int) * (PAGE_SIZE as int))
843 by {
844 vstd::arithmetic::mul::lemma_mul_strict_inequality(
845 j as int,
846 nr_pages as int,
847 PAGE_SIZE as int,
848 );
849 };
850 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_div_mul_eq(
851 self.parent_level,
852 );
853 assert(pa_plus_int < MAX_PADDR);
854 vstd::arithmetic::div_mod::lemma_div_multiples_vanish_quotient(
856 j as int,
857 pa as int,
858 PAGE_SIZE as int,
859 );
860 assert(self_idx as int == pa as int / PAGE_SIZE as int);
861 assert(sub_idx != self_idx);
862 assert(r0.slot_owners.contains_key(sub_idx));
863 assert(r0.slot_owners[sub_idx] == r1.slot_owners[sub_idx]);
864 }
865 }
866 }
867
868 pub proof fn nodes_different_paths_different_addrs(self, other: Self, regions: MetaRegionOwners)
871 requires
872 self.is_node(),
873 other.is_node(),
874 self.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(
875 self.meta_slot_paddr().unwrap(),
876 )].paths_in_pt == set![self.path],
877 other.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(
878 other.meta_slot_paddr().unwrap(),
879 )].paths_in_pt == set![other.path],
880 self.path != other.path,
881 ensures
882 self.node.unwrap().meta_addr_self() != other.node.unwrap().meta_addr_self(),
883 {
884 let self_addr = self.node.unwrap().meta_addr_self();
885 let other_addr = other.node.unwrap().meta_addr_self();
886 let self_idx = frame_to_index(meta_to_frame(self_addr));
887 let other_idx = frame_to_index(meta_to_frame(other_addr));
888
889 if self_addr == other_addr {
890 assert(regions.slot_owners[self_idx].paths_in_pt == set![self.path]);
891 assert(regions.slot_owners[other_idx].paths_in_pt == set![other.path]);
892 assert(set![self.path].contains(other.path));
893 assert(self.path == other.path);
894 assert(false); }
896 }
897
898 pub proof fn nodes_different_path_lengths_neq_slot(self, other: Self, regions: MetaRegionOwners)
905 requires
906 self.is_node(),
907 other.is_node(),
908 self.metaregion_sound(regions),
909 other.metaregion_sound(regions),
910 self.path.len() != other.path.len(),
911 ensures
912 self.meta_slot_paddr_neq(other),
913 {
914 let self_idx = frame_to_index(self.meta_slot_paddr().unwrap());
915 let other_idx = frame_to_index(other.meta_slot_paddr().unwrap());
916 if self_idx == other_idx {
917 assert(regions.slot_owners[self_idx].paths_in_pt == set![self.path]);
918 assert(regions.slot_owners[other_idx].paths_in_pt == set![other.path]);
919 assert(set![self.path].contains(other.path));
920 assert(self.path == other.path);
921 assert(false);
922 }
923 }
924}
925
926impl<C: PageTableConfig> EntryOwner<C> {
927 pub open spec fn inv_base(self) -> bool {
930 &&& self.node is Some ==> {
931 &&& self.frame is None
932 &&& self.locked is None
933 &&& self.borrowed is None
934 &&& self.node.unwrap().inv()
935 &&& !self.absent
936 &&& self.parent_level == self.node.unwrap().level + 1
937 }
938 &&& self.frame is Some ==> {
939 &&& self.node is None
940 &&& self.locked is None
941 &&& self.borrowed is None
942 &&& !self.absent
943 &&& 1 <= self.parent_level < NR_LEVELS
948 &&& self.frame.unwrap().mapped_pa % PAGE_SIZE == 0
949 &&& self.frame.unwrap().mapped_pa < MAX_PADDR
950 &&& self.frame.unwrap().size == page_size(self.parent_level)
951 &&& self.frame.unwrap().mapped_pa % page_size(self.parent_level) == 0
952 &&& self.frame.unwrap().mapped_pa + page_size(self.parent_level) <= MAX_PADDR
953 }
954 &&& self.locked is Some ==> {
955 &&& self.frame is None
956 &&& self.node is None
957 &&& self.borrowed is None
958 &&& !self.absent
959 }
960 &&& self.borrowed is Some ==> {
961 &&& self.node is None
962 &&& self.frame is None
963 &&& self.locked is None
964 &&& !self.absent
965 }
966 &&& self.path.inv()
967 }
968
969 pub open spec fn set_in_scope(self, in_scope: bool) -> Self {
970 EntryOwner { in_scope, ..self }
971 }
972}
973
974impl<C: PageTableConfig> Inv for EntryOwner<C> {
975 open spec fn inv(self) -> bool {
976 &&& !self.in_scope
977 &&& self.inv_base()
978 }
979}
980
981impl<C: PageTableConfig> View for EntryOwner<C> {
982 type V = EntryView<C>;
983
984 #[verifier::external_body]
985 open spec fn view(&self) -> <Self as View>::V {
986 if let Some(frame) = self.frame {
987 EntryView::Leaf {
988 leaf: LeafPageTableEntryView {
989 map_va: vaddr(self.path) as int,
990 map_to_pa: frame.mapped_pa as int,
993 level: self.path.len() as u8,
994 prop: frame.prop,
995 phantom: PhantomData,
996 },
997 }
998 } else if let Some(node) = self.node {
999 EntryView::Intermediate {
1000 node: IntermediatePageTableEntryView {
1001 map_va: vaddr(self.path) as int,
1002 map_to_pa: meta_to_frame(node.meta_addr_self()) as int,
1005 level: self.path.len() as u8,
1006 phantom: PhantomData,
1007 },
1008 }
1009 } else if let Some(view) = self.locked {
1010 EntryView::LockedSubtree { views: view@ }
1011 } else {
1012 EntryView::Absent
1013 }
1014 }
1015}
1016
1017impl<C: PageTableConfig> InvView for EntryOwner<C> {
1018 proof fn view_preserves_inv(self) {
1019 }
1023}
1024
1025impl<'a, 'rcu, C: PageTableConfig> OwnerOf for Entry<'a, 'rcu, C> {
1026 type Owner = EntryOwner<C>;
1027
1028 open spec fn wf(self, owner: Self::Owner) -> bool {
1029 &&& self.idx < NR_ENTRIES
1030 &&& owner.match_pte(self.pte, owner.parent_level)
1031 &&& self.pte.paddr() % PAGE_SIZE == 0
1032 &&& self.pte.paddr() < MAX_PADDR
1033 }
1034}
1035
1036}