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::mapping::frame_to_index;
7use crate::mm::page_table::*;
8use crate::specs::arch::mm::NR_ENTRIES;
9use crate::specs::mm::frame::meta_owners::REF_COUNT_UNUSED;
10use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
11use crate::specs::mm::page_table::*;
12
13verus! {
14
15impl<'rcu, C: PageTableConfig> Entry<'rcu, C> {
16 pub open spec fn invariants(self, owner: EntryOwner<C>, regions: MetaRegionOwners) -> bool {
17 &&& owner.inv()
18 &&& regions.inv()
19 &&& self.wf(owner)
20 &&& owner.relate_region(regions)
21 }
22
23 pub open spec fn node_matching(self, owner: EntryOwner<C>, parent_owner: NodeOwner<C>, guard_perm: GuardPerm<'rcu, C>) -> bool {
24 &&& parent_owner.level == owner.parent_level
25 &&& parent_owner.inv()
26 &&& guard_perm.addr() == self.node.addr()
27 &&& guard_perm.is_init()
28 &&& guard_perm.value().inner.inner@.ptr.addr() == parent_owner.meta_perm.addr()
29 &&& guard_perm.value().inner.inner@.ptr.addr() == parent_owner.meta_perm.points_to.addr()
30 &&& guard_perm.value().inner.inner@.wf(parent_owner)
31 &&& parent_owner.meta_perm.is_init()
32 &&& parent_owner.meta_perm.wf(&parent_owner.meta_perm.inner_perms)
33 &&& owner.match_pte(parent_owner.children_perm.value()[self.idx as int], owner.parent_level)
34 }
35
36 pub open spec fn relate_region_preserved(regions0: MetaRegionOwners, regions1: MetaRegionOwners) -> bool {
37 OwnerSubtree::implies(
38 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.relate_region(regions0),
39 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>| entry.relate_region(regions1),
40 )
41 }
42
43 pub open spec fn replace_panic_condition(
44 parent_owner: NodeOwner<C>,
45 new_owner: EntryOwner<C>,
46 ) -> bool {
47 if new_owner.is_node() {
48 parent_owner.level - 1 == new_owner.node.unwrap().level
49 } else if new_owner.is_frame() {
50 parent_owner.level == new_owner.parent_level
51 } else {
52 true
53 }
54 }
55
56 pub open spec fn relate_region_neq_preserved(
57 old_entry_owner: EntryOwner<C>,
58 new_entry_owner: EntryOwner<C>,
59 regions0: MetaRegionOwners,
60 regions1: MetaRegionOwners,
61 ) -> bool {
62 OwnerSubtree::implies(
63 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
64 entry.meta_slot_paddr_neq(old_entry_owner)
65 && entry.meta_slot_paddr_neq(new_entry_owner)
66 && entry.relate_region(regions0),
67 |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
68 entry.relate_region(regions1),
69 )
70 }
71
72 pub proof fn alloc_if_none_relate_region_preserved(
81 old_child: EntryOwner<C>,
82 new_child: EntryOwner<C>,
83 regions0: MetaRegionOwners,
84 regions1: MetaRegionOwners,
85 )
86 requires
87 old_child.is_absent(),
88 old_child.inv(),
89 new_child.is_node(),
90 regions0.inv(),
91 regions0.slots.contains_key(frame_to_index(new_child.meta_slot_paddr().unwrap())),
92 Self::relate_region_neq_preserved(old_child, new_child, regions0, regions1),
93 ensures
94 Self::relate_region_preserved(regions0, regions1),
95 {
96 let new_idx = frame_to_index(new_child.meta_slot_paddr().unwrap());
97 let f = PageTableOwner::<C>::relate_region_pred(regions0);
100 let g = PageTableOwner::<C>::relate_region_pred(regions1);
101 assert(Self::relate_region_preserved(regions0, regions1)) by {
102 assert(OwnerSubtree::implies(f, g)) by {
103 assert forall |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
104 entry.inv() && f(entry, path) implies
105 #[trigger] g(entry, path)
106 by {
107 assert(old_child.meta_slot_paddr() is None) by {
110 assert(!old_child.is_node());
111 assert(!old_child.is_frame());
112 };
113 assert(entry.meta_slot_paddr_neq(old_child));
114
115 assert(entry.meta_slot_paddr_neq(new_child)) by {
118 if entry.meta_slot_paddr() is Some {
119 EntryOwner::<C>::active_entry_not_in_free_pool(entry, regions0, new_idx);
121 assert(frame_to_index(entry.meta_slot_paddr().unwrap()) != new_idx);
122 if entry.meta_slot_paddr().unwrap() == new_child.meta_slot_paddr().unwrap() {
125 assert(frame_to_index(entry.meta_slot_paddr().unwrap())
126 == frame_to_index(new_child.meta_slot_paddr().unwrap()));
127 assert(false);
128 }
129 }
130 };
131
132 assert(entry.meta_slot_paddr_neq(old_child)
136 && entry.meta_slot_paddr_neq(new_child)
137 && entry.relate_region(regions0));
138 };
139 };
140 };
141 }
142
143 pub open spec fn path_tracked_pred_preserved(regions0: MetaRegionOwners, regions1: MetaRegionOwners) -> 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(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 &&& old_owner.meta_slot_paddr_neq(new_owner)
159 &&& new_owner.in_scope
160 &&& new_owner.is_node() ==> {
161 &&& regions.slots.contains_key(frame_to_index(new_owner.meta_slot_paddr().unwrap()))
162 &&& regions.slot_owners[frame_to_index(new_owner.meta_slot_paddr().unwrap())].inner_perms.ref_count.value() !=
163 REF_COUNT_UNUSED
164 }
165 }
166
167 pub open spec fn parent_perms_preserved(self,
168 parent_owner0: NodeOwner<C>,
169 parent_owner1: NodeOwner<C>,
170 guard_perm0: GuardPerm<'rcu, C>,
171 guard_perm1: GuardPerm<'rcu, C>)
172 -> bool {
173 &&& guard_perm0.addr() == guard_perm1.addr()
174 &&& guard_perm0.value().inner.inner@.ptr.addr() == guard_perm1.value().inner.inner@.ptr.addr()
175 &&& forall|i: int| 0 <= i < NR_ENTRIES ==> i != self.idx ==>
176 parent_owner0.children_perm.value()[i] == parent_owner1.children_perm.value()[i]
177 }
178}
179
180}