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