ostd/specs/mm/page_table/node/
entry.rs1use vstd::prelude::*;
2
3use vstd_extra::{ghost_tree::*, ownership::*};
4
5use crate::specs::{
6 arch::NR_ENTRIES,
7 mm::{
8 frame::{mapping::frame_to_index, meta_region_owners::MetaRegionOwners},
9 page_table::*,
10 },
11};
12
13use crate::mm::{frame::meta::REF_COUNT_UNUSED, page_table::*};
14
15verus! {
16
17impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
18 pub open spec fn invariants(self, owner: EntryOwner<C>, regions: MetaRegionOwners) -> bool {
19 &&& owner.inv()
20 &&& regions.inv()
21 &&& self.wf(owner)
22 &&& owner.metaregion_sound(regions)
23 }
24
25 pub open spec fn node_matching(
26 self,
27 owner: EntryOwner<C>,
28 parent_owner: NodeOwner<C>,
29 guard: PageTableGuard<'rcu, C>,
30 ) -> bool {
31 &&& parent_owner.level == owner.parent_level
32 &&& parent_owner.inv()
33 &&& guard.inner.inner@.ptr.addr() == parent_owner.meta_vaddr()
34 &&& guard.inner.inner@.wf(parent_owner)
35 &&& owner.match_pte(parent_owner.children_perm.value()[self.idx as int], owner.parent_level)
36 }
37
38 pub open spec fn metaregion_sound_preserved(
39 regions0: MetaRegionOwners,
40 regions1: MetaRegionOwners,
41 ) -> bool {
42 OwnerSubtree::implies(
43 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions0),
44 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions1),
45 )
46 }
47
48 pub open spec fn replace_nonpanic_condition(
49 parent_owner: NodeOwner<C>,
50 new_owner: EntryOwner<C>,
51 ) -> bool {
52 if new_owner.is_node() {
53 parent_owner.level - 1 == new_owner.node().level
54 } else if new_owner.is_frame() {
55 parent_owner.level == new_owner.parent_level
56 } else {
57 true
58 }
59 }
60
61 pub open spec fn metaregion_sound_neq_preserved(
62 old_entry_owner: EntryOwner<C>,
63 new_entry_owner: EntryOwner<C>,
64 regions0: MetaRegionOwners,
65 regions1: MetaRegionOwners,
66 ) -> bool {
67 OwnerSubtree::implies(
68 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
69 entry.meta_slot_paddr_neq(old_entry_owner) && entry.meta_slot_paddr_neq(
70 new_entry_owner,
71 ) && entry.metaregion_sound(regions0),
72 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions1),
73 )
74 }
75
76 pub open spec fn metaregion_sound_neq_old_preserved(
81 old_entry_owner: EntryOwner<C>,
82 regions0: MetaRegionOwners,
83 regions1: MetaRegionOwners,
84 ) -> bool {
85 OwnerSubtree::implies(
86 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
87 entry.meta_slot_paddr_neq(old_entry_owner) && entry.metaregion_sound(regions0),
88 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.metaregion_sound(regions1),
89 )
90 }
91
92 pub proof fn alloc_if_none_metaregion_sound_preserved(
98 old_child: EntryOwner<C>,
99 new_child: EntryOwner<C>,
100 regions0: MetaRegionOwners,
101 regions1: MetaRegionOwners,
102 )
103 requires
104 old_child.is_absent(),
105 old_child.inv(),
106 new_child.is_node(),
107 regions0.inv(),
108 regions0.contains(frame_to_index(new_child.meta_slot_paddr()->0)),
109 regions0.slot_owner(new_child.meta_slot_paddr()->0).ref_count() == REF_COUNT_UNUSED,
110 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(new_child.meta_slot_paddr()->0),
114 Self::metaregion_sound_neq_preserved(old_child, new_child, regions0, regions1),
115 ensures
116 Self::metaregion_sound_preserved(regions0, regions1),
117 {
118 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
119
120 let new_idx = frame_to_index(new_child.meta_slot_paddr().unwrap());
121 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
122 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
123
124 assert(old_child.meta_slot_paddr() is None);
125
126 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
127 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
128 if entry.meta_slot_paddr() is Some && entry.is_node() {
129 EntryOwner::<C>::lemma_active_entry_not_in_free_pool(entry, regions0, new_idx);
130 }
131 };
138 }
139
140 pub open spec fn path_tracked_pred_preserved(
141 regions0: MetaRegionOwners,
142 regions1: MetaRegionOwners,
143 ) -> bool {
144 OwnerSubtree::implies(
145 PageTableOwner::<C>::path_tracked_pred(regions0),
146 PageTableOwner::<C>::path_tracked_pred(regions1),
147 )
148 }
149
150 pub open spec fn new_owner_compatible(
151 self,
152 new_child: Child<C>,
153 old_owner: EntryOwner<C>,
154 new_owner: EntryOwner<C>,
155 regions: MetaRegionOwners,
156 ) -> bool {
157 &&& old_owner.path == new_owner.path
158 &&& old_owner.parent_level == new_owner.parent_level
159 &&& new_owner.is_node() ==> {
160 &&& regions.contains(frame_to_index(new_owner.meta_slot_paddr()->0))
161 &&& regions.slot_owner(new_owner.meta_slot_paddr()->0).ref_count() != REF_COUNT_UNUSED
162 }
163 }
164
165 pub open spec fn parent_perms_preserved(
166 self,
167 parent_owner0: NodeOwner<C>,
168 parent_owner1: NodeOwner<C>,
169 ) -> bool {
170 &&& forall|i: int|
171 0 <= i < NR_ENTRIES ==> i != self.idx ==> parent_owner0.children_perm.value()[i]
172 == parent_owner1.children_perm.value()[i]
173 &&& parent_owner1.slot_index == parent_owner0.slot_index
174 &&& parent_owner1.level == parent_owner0.level
175 &&& parent_owner1.tree_level == parent_owner0.tree_level
176 &&& parent_owner1.meta_own.nr_children.id() == parent_owner0.meta_own.nr_children.id()
177 &&& parent_owner1.meta_own.stray == parent_owner0.meta_own.stray
178 }
179}
180
181}