ostd/specs/mm/page_table/node/
entry_owners.rs1use 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::mapping::{frame_to_index, meta_to_frame};
10use crate::mm::frame::meta::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::meta_region_owners::MetaRegionOwners;
18use crate::specs::mm::page_table::node::entry_view::*;
19use crate::specs::mm::page_table::*;
20use core::marker::PhantomData;
21
22verus! {
23
24pub tracked struct FrameEntryOwner {
25 pub mapped_pa: usize,
26 pub size: usize,
27 pub prop: PageProperty,
28}
29
30pub tracked struct EntryOwner<C: PageTableConfig> {
31 pub node: Option<NodeOwner<C>>,
32 pub frame: Option<FrameEntryOwner>,
33 pub locked: Option<Ghost<Seq<FrameView<C>>>>,
34 pub absent: bool,
35 pub in_scope: bool,
36 pub path: TreePath<NR_ENTRIES>,
37 pub parent_level: PagingLevel,
38}
39
40impl<C: PageTableConfig> EntryOwner<C> {
41 pub open spec fn is_node(self) -> bool {
42 self.node is Some
43 }
44
45 pub open spec fn is_frame(self) -> bool {
46 self.frame is Some
47 }
48
49 pub open spec fn is_locked(self) -> bool {
50 self.locked is Some
51 }
52
53 pub open spec fn is_absent(self) -> bool {
54 self.absent
55 }
56
57 pub open spec fn new_absent_spec(path: TreePath<NR_ENTRIES>, parent_level: PagingLevel) -> Self {
58 EntryOwner {
59 node: None,
60 frame: None,
61 locked: None,
62 absent: true,
63 in_scope: true,
64 path,
65 parent_level,
66 }
67 }
68
69 pub open spec fn new_frame_spec(paddr: Paddr, path: TreePath<NR_ENTRIES>, parent_level: PagingLevel, prop: PageProperty) -> Self {
70 EntryOwner {
71 node: None,
72 frame: Some(FrameEntryOwner { mapped_pa: paddr, size: page_size(parent_level), prop }),
73 locked: None,
74 absent: false,
75 in_scope: true,
76 path,
77 parent_level,
78 }
79 }
80
81 pub open spec fn new_node_spec(node: NodeOwner<C>, path: TreePath<NR_ENTRIES>) -> Self {
82 EntryOwner {
83 node: Some(node),
84 frame: None,
85 locked: None,
86 absent: false,
87 in_scope: true,
88 path,
89 parent_level: (node.level + 1) as PagingLevel,
90 }
91 }
92
93 pub axiom fn new_absent(path: TreePath<NR_ENTRIES>, parent_level: PagingLevel) -> tracked Self
94 returns Self::new_absent_spec(path, parent_level);
95
96 pub axiom fn new_frame(paddr: Paddr, path: TreePath<NR_ENTRIES>, parent_level: PagingLevel, prop: PageProperty) -> tracked Self
97 returns Self::new_frame_spec(paddr, path, parent_level, prop);
98
99 pub axiom fn new_node(node: NodeOwner<C>, path: TreePath<NR_ENTRIES>) -> tracked Self
100 returns Self::new_node_spec(node, path);
101
102 pub open spec fn match_pte(self, pte: C::E, parent_level: PagingLevel) -> bool {
103 &&& pte.paddr() % PAGE_SIZE == 0
104 &&& pte.paddr() < MAX_PADDR
105 &&& !pte.is_present() ==> {
106 self.is_absent()
107 }
108 &&& pte.is_present() && !pte.is_last(parent_level) ==> {
109 &&& self.is_node()
110 &&& meta_to_frame(self.node.unwrap().meta_perm.addr()) == pte.paddr()
111 }
112 &&& pte.is_present() && pte.is_last(parent_level) ==> {
113 &&& self.is_frame()
114 &&& self.frame.unwrap().mapped_pa == pte.paddr()
115 &&& self.frame.unwrap().prop == pte.prop()
116 }
117 }
118
119 pub proof fn absent_match_pte(owner: Self, pte: C::E, parent_level: PagingLevel)
121 requires
122 owner.is_absent(),
123 pte == C::E::new_absent_spec(),
124 pte.paddr() % PAGE_SIZE == 0,
125 pte.paddr() < MAX_PADDR,
126 ensures
127 owner.match_pte(pte, parent_level),
128 {
129 C::E::new_properties();
130 assert(!pte.is_present());
131 if pte.is_present() && !pte.is_last(parent_level) {
132 assert(pte.is_present());
133 assert(!pte.is_present());
134 }
135 if pte.is_present() && pte.is_last(parent_level) {
136 assert(pte.is_present());
137 assert(!pte.is_present());
138 }
139 }
140
141 pub open spec fn expected_raw_count(self) -> usize {
142 if self.in_scope {
143 0
144 } else {
145 1
146 }
147 }
148
149 pub open spec fn relate_region(self, regions: MetaRegionOwners) -> bool {
150 if self.is_node() {
151 let idx = frame_to_index(self.meta_slot_paddr().unwrap());
152 &&& regions.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED
153 &&& regions.slot_owners[idx].raw_count == self.expected_raw_count()
154 &&& regions.slot_owners[idx].self_addr == self.node.unwrap().meta_perm.addr()
155 &&& self.node.unwrap().meta_perm.points_to.value().wf(regions.slot_owners[idx])
156 &&& regions.slot_owners[idx].path_if_in_pt is Some ==>
157 regions.slot_owners[idx].path_if_in_pt.unwrap() == self.path
158 } else if self.is_frame() {
159 regions.slot_owners[frame_to_index(self.meta_slot_paddr().unwrap())].path_if_in_pt is Some ==>
160 regions.slot_owners[frame_to_index(self.meta_slot_paddr().unwrap())].path_if_in_pt.unwrap() == self.path
161 } else {
162 true
163 }
164 }
165
166 pub axiom fn get_path(self) -> tracked TreePath<NR_ENTRIES>
167 returns self.path;
168
169 pub open spec fn meta_slot_paddr(self) -> Option<Paddr> {
170 if self.is_node() {
171 Some(meta_to_frame(self.node.unwrap().meta_perm.addr()))
172 } else if self.is_frame() {
173 Some(self.frame.unwrap().mapped_pa)
174 } else {
175 None
176 }
177 }
178
179 pub open spec fn meta_slot_paddr_neq(self, other: Self) -> bool {
180 self.meta_slot_paddr() is Some ==>
181 other.meta_slot_paddr() is Some ==>
182 self.meta_slot_paddr().unwrap() != other.meta_slot_paddr().unwrap()
183 }
184
185 pub proof fn nodes_different_paths_different_addrs(
188 self,
189 other: Self,
190 regions: MetaRegionOwners,
191 )
192 requires
193 self.is_node(),
194 other.is_node(),
195 self.relate_region(regions),
196 self.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(self.meta_slot_paddr().unwrap())].path_if_in_pt is Some,
197 other.meta_slot_paddr() is Some ==> regions.slot_owners[frame_to_index(other.meta_slot_paddr().unwrap())].path_if_in_pt is Some,
198 other.relate_region(regions),
199 self.path != other.path,
200 ensures
201 self.node.unwrap().meta_perm.addr() != other.node.unwrap().meta_perm.addr(),
202 {
203 let self_addr = self.node.unwrap().meta_perm.addr();
204 let other_addr = other.node.unwrap().meta_perm.addr();
205 let self_idx = frame_to_index(meta_to_frame(self_addr));
206 let other_idx = frame_to_index(meta_to_frame(other_addr));
207
208 if self_addr == other_addr {
209 assert(regions.slot_owners[self_idx].path_if_in_pt == Some(self.path));
210 assert(regions.slot_owners[other_idx].path_if_in_pt == Some(other.path));
211assert(self.path == other.path);
213 assert(false); }
215 }
216}
217
218impl<C: PageTableConfig> Inv for EntryOwner<C> {
219 open spec fn inv(self) -> bool {
220 &&& self.node is Some ==> {
221 &&& self.frame is None
222 &&& self.locked is None
223 &&& self.node.unwrap().inv()
224 &&& !self.absent
225 }
226 &&& self.frame is Some ==> {
227 &&& self.node is None
228 &&& self.locked is None
229 &&& !self.absent
230 &&& self.frame.unwrap().mapped_pa % PAGE_SIZE == 0
231 &&& self.frame.unwrap().mapped_pa < MAX_PADDR
232 &&& self.frame.unwrap().size == page_size(self.parent_level)
233 }
234 &&& self.locked is Some ==> {
235 &&& self.frame is None
236 &&& self.node is None
237 &&& !self.absent
238 }
239 &&& self.path.inv()
240 }
241}
242
243impl<C: PageTableConfig> View for EntryOwner<C> {
244 type V = EntryView<C>;
245
246 #[verifier::external_body]
247 open spec fn view(&self) -> <Self as View>::V {
248 if let Some(frame) = self.frame {
249 EntryView::Leaf {
250 leaf: LeafPageTableEntryView {
251 map_va: vaddr(self.path) as int,
252 map_to_pa: frame.mapped_pa as int,
255 level: self.path.len() as u8,
256 prop: frame.prop,
257 phantom: PhantomData,
258 },
259 }
260 } else if let Some(node) = self.node {
261 EntryView::Intermediate {
262 node: IntermediatePageTableEntryView {
263 map_va: vaddr(self.path) as int,
264 map_to_pa: meta_to_frame(node.meta_perm.addr()) as int,
267 level: self.path.len() as u8,
268 phantom: PhantomData,
269 },
270 }
271 } else if let Some(view) = self.locked {
272 EntryView::LockedSubtree { views: view@ }
273 } else {
274 EntryView::Absent
275 }
276 }
277}
278
279impl<C: PageTableConfig> InvView for EntryOwner<C> {
280 proof fn view_preserves_inv(self) {
281 admit()
282 }
283}
284
285impl<'rcu, C: PageTableConfig> OwnerOf for Entry<'rcu, C> {
286 type Owner = EntryOwner<C>;
287
288 open spec fn wf(self, owner: Self::Owner) -> bool {
289 &&& self.idx < NR_ENTRIES
290 &&& owner.match_pte(self.pte, owner.parent_level)
291 &&& self.pte.paddr() % PAGE_SIZE == 0
292 &&& self.pte.paddr() < MAX_PADDR
293 }
294}
295
296}