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.slots.contains_key(frame_to_index(new_child.meta_slot_paddr()->0)),
109 regions0.slot_owners[frame_to_index(
110 new_child.meta_slot_paddr()->0,
111 )].inner_perms.ref_count.value() == REF_COUNT_UNUSED,
112 !crate::specs::mm::frame::meta_owners::is_mmio_paddr(new_child.meta_slot_paddr()->0),
116 Self::metaregion_sound_neq_preserved(old_child, new_child, regions0, regions1),
117 ensures
118 Self::metaregion_sound_preserved(regions0, regions1),
119 {
120 broadcast use crate::specs::mm::frame::meta_owners::axiom_mmio_usage_iff_mmio_paddr;
121
122 let new_idx = frame_to_index(new_child.meta_slot_paddr().unwrap());
123 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
124 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
125
126 assert(old_child.meta_slot_paddr() is None);
127
128 assert forall|entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
129 entry.inv() && f(entry, path) implies #[trigger] g(entry, path) by {
130 if entry.meta_slot_paddr() is Some && entry.is_node() {
131 EntryOwner::<C>::lemma_active_entry_not_in_free_pool(entry, regions0, new_idx);
132 }
133 };
140 }
141
142 pub open spec fn path_tracked_pred_preserved(
143 regions0: MetaRegionOwners,
144 regions1: MetaRegionOwners,
145 ) -> bool {
146 OwnerSubtree::implies(
147 PageTableOwner::<C>::path_tracked_pred(regions0),
148 PageTableOwner::<C>::path_tracked_pred(regions1),
149 )
150 }
151
152 pub open spec fn new_owner_compatible(
153 self,
154 new_child: Child<C>,
155 old_owner: EntryOwner<C>,
156 new_owner: EntryOwner<C>,
157 regions: MetaRegionOwners,
158 ) -> bool {
159 &&& old_owner.path == new_owner.path
160 &&& old_owner.parent_level == new_owner.parent_level
161 &&& new_owner.is_node() ==> {
162 &&& regions.slots.contains_key(frame_to_index(new_owner.meta_slot_paddr()->0))
163 &&& regions.slot_owners[frame_to_index(
164 new_owner.meta_slot_paddr()->0,
165 )].inner_perms.ref_count.value() != REF_COUNT_UNUSED
166 }
167 }
168
169 pub open spec fn parent_perms_preserved(
170 self,
171 parent_owner0: NodeOwner<C>,
172 parent_owner1: NodeOwner<C>,
173 ) -> bool {
174 &&& forall|i: int|
175 0 <= i < NR_ENTRIES ==> i != self.idx ==> parent_owner0.children_perm.value()[i]
176 == parent_owner1.children_perm.value()[i]
177 &&& parent_owner1.slot_index == parent_owner0.slot_index
178 &&& parent_owner1.level == parent_owner0.level
179 &&& parent_owner1.tree_level == parent_owner0.tree_level
180 &&& parent_owner1.meta_own.nr_children.id() == parent_owner0.meta_own.nr_children.id()
181 &&& parent_owner1.meta_own.stray == parent_owner0.meta_own.stray
182 }
183}
184
185}