ostd/specs/mm/page_table/cursor/
cursor_fn_lemmas.rs1use vstd::arithmetic::power2::pow2;
10use vstd::prelude::*;
11
12use vstd_extra::ghost_tree::*;
13use vstd_extra::ownership::*;
14
15use vstd_extra::arithmetic::{
16 lemma_nat_align_down_monotone, lemma_nat_align_down_sound, lemma_nat_align_down_within_block,
17 lemma_nat_align_up_sound,
18};
19
20use crate::mm::page_table::*;
21use crate::mm::{PagingLevel, Vaddr};
22use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS};
23use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
24use crate::specs::mm::page_table::cursor::owners::{CursorOwner, CursorContinuation};
25use crate::specs::mm::page_table::cursor::page_size_lemmas::{
26 lemma_page_size_divides, lemma_page_size_ge_page_size,
27};
28use crate::specs::mm::page_table::owners::*;
29use crate::specs::mm::page_table::AbstractVaddr;
30use crate::specs::mm::page_table::Mapping;
31use crate::specs::mm::page_table::{nat_align_down, nat_align_up};
32
33use core::ops::Range;
34
35verus! {
36
37impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
38
39 pub proof fn protect_preserves_cursor_inv_metaregion(
42 self,
43 other: Self,
44 regions: MetaRegionOwners,
45 )
46 requires
47 self.inv(),
48 self.metaregion_sound(regions),
49 self.cur_entry_owner().is_frame(),
50 other.cur_entry_owner().is_frame(),
51 other.cur_entry_owner().inv(),
52 other.cur_entry_owner().frame.unwrap().mapped_pa == self.cur_entry_owner().frame.unwrap().mapped_pa,
54 other.cur_entry_owner().path == self.cur_entry_owner().path,
55 other.cur_entry_owner().parent_level == self.cur_entry_owner().parent_level,
56 self.level == other.level,
58 self.guard_level == other.guard_level,
59 self.va == other.va,
60 self.prefix == other.prefix,
61 self.popped_too_high == other.popped_too_high,
62 forall|i: int| self.level <= i < NR_LEVELS ==>
64 #[trigger] self.continuations[i] == other.continuations[i],
65 other.continuations[self.level - 1].inv(),
67 other.continuations[self.level - 1].all_some(),
68 other.continuations[self.level - 1].idx == self.continuations[self.level - 1].idx,
69 other.continuations[self.level - 1].entry_own.parent_level
70 == self.continuations[self.level - 1].entry_own.parent_level,
71 other.continuations[self.level - 1].guard_perm.value().inner.inner@.ptr.addr()
72 == self.continuations[self.level - 1].guard_perm.value().inner.inner@.ptr.addr(),
73 other.continuations[self.level - 1].path()
74 == self.continuations[self.level - 1].path(),
75 other.continuations.dom() =~= self.continuations.dom(),
76 forall |j: int| 0 <= j < NR_ENTRIES
77 && j != self.continuations[self.level - 1].idx as int ==>
78 #[trigger] other.continuations[self.level - 1].children[j]
79 == self.continuations[self.level - 1].children[j],
80 ({
81 let new_child = other.continuations[self.level - 1].children[
82 other.continuations[self.level - 1].idx as int].unwrap();
83 let new_path = other.continuations[self.level - 1].path()
84 .push_tail(other.continuations[self.level - 1].idx as usize);
85 new_child.tree_predicate_map(new_path,
86 PageTableOwner::<C>::metaregion_sound_pred(regions))
87 }),
88 other.continuations[self.level - 1].entry_own.metaregion_sound(regions),
89 ensures
90 other.inv(),
91 other.metaregion_sound(regions),
92 {
93 other.map_branch_none_inv_holds(self);
94
95 let f = PageTableOwner::<C>::metaregion_sound_pred(regions);
96 let L = self.level as int;
97 let idx = self.continuations[L - 1].idx as int;
98
99 assert forall |i: int| #![trigger other.continuations[i]]
100 other.level - 1 <= i < NR_LEVELS
101 implies
102 other.continuations[i].map_children(f)
103 by {
104 if i > L - 1 {
105 assert(other.continuations[i] == self.continuations[i]);
106 assert(self.continuations[i].map_children(f));
107 } else {
108 assert(i == L - 1);
109 let o_cont = other.continuations[L - 1];
110 let s_cont = self.continuations[L - 1];
111 reveal(CursorContinuation::inv_children);
112 assert forall |j: int| #![trigger o_cont.children[j]]
113 0 <= j < o_cont.children.len() && o_cont.children[j] is Some
114 implies
115 o_cont.children[j].unwrap()
116 .tree_predicate_map(o_cont.path().push_tail(j as usize), f)
117 by {
118 if j != idx {
119 assert(o_cont.children[j] == s_cont.children[j]);
120 s_cont.inv_children_unroll(j);
121 }
122 };
123 }
124 };
125
126 assert forall |i: int| #![trigger other.continuations[i]]
127 other.level - 1 <= i < NR_LEVELS
128 implies
129 other.continuations[i].entry_own.metaregion_sound(regions)
130 by {
131 if i > L - 1 {
132 assert(other.continuations[i] == self.continuations[i]);
133 self.inv_continuation(i);
134 }
135 };
136 }
137
138 pub proof fn map_branch_none_inv_holds(self, owner0: Self)
139 requires
140 owner0.inv(),
141 self.level == owner0.level,
142 self.va == owner0.va,
143 self.guard_level == owner0.guard_level,
144 self.prefix == owner0.prefix,
145 self.popped_too_high == owner0.popped_too_high,
146 forall|i: int| self.level <= i < NR_LEVELS ==>
148 #[trigger] self.continuations[i] == owner0.continuations[i],
149 self.continuations[self.level - 1].inv(),
151 self.continuations[self.level - 1].all_some(),
152 self.continuations[self.level - 1].idx == owner0.continuations[owner0.level - 1].idx,
153 self.continuations[self.level - 1].entry_own.parent_level
154 == owner0.continuations[owner0.level - 1].entry_own.parent_level,
155 self.continuations[self.level - 1].guard_perm.value().inner.inner@.ptr.addr()
157 == owner0.continuations[owner0.level - 1].guard_perm.value().inner.inner@.ptr.addr(),
158 self.continuations[self.level - 1].path()
159 == owner0.continuations[owner0.level - 1].path(),
160 self.va.index[self.level - 1] == self.continuations[self.level - 1].idx,
161 self.continuations.dom() =~= owner0.continuations.dom(),
163 ensures
164 self.inv()
165 {
166 let L = self.level as int;
167 assert(self.continuations[L - 1].level() == self.level) by {
168 assert(self.continuations[L - 1].path() == owner0.continuations[L - 1].path());
169 if L == 1 {} else if L == 2 {} else if L == 3 {} else {}
170 };
171 assert(self.continuations.contains_key(L - 1)) by {
172 if L == 1 {} else if L == 2 {} else if L == 3 {} else {}
173 };
174 }
175
176 pub proof fn map_branch_none_no_new_mappings(self, owner0: Self)
178 requires
179 owner0.inv(),
180 self.inv(),
181 self.level == owner0.level,
182 self.va == owner0.va,
183 forall|i: int| self.level <= i < NR_LEVELS ==>
184 #[trigger] self.continuations[i] == owner0.continuations[i],
185 owner0.continuations[owner0.level - 1].children[
187 owner0.continuations[owner0.level - 1].idx as int] is Some,
188 owner0.continuations[owner0.level - 1].children[
189 owner0.continuations[owner0.level - 1].idx as int].unwrap().value.is_absent(),
190 self.continuations[self.level - 1].children[
191 self.continuations[self.level - 1].idx as int] is Some,
192 self.continuations[self.level - 1].children[
193 self.continuations[self.level - 1].idx as int].unwrap().value.is_node(),
194 self.continuations[self.level - 1].path()
196 == owner0.continuations[owner0.level - 1].path(),
197 forall|j: int| 0 <= j < NR_ENTRIES
198 && j != owner0.continuations[owner0.level - 1].idx as int ==>
199 #[trigger] self.continuations[self.level - 1].children[j]
200 == owner0.continuations[owner0.level - 1].children[j],
201 PageTableOwner(self.continuations[self.level - 1].children[
203 self.continuations[self.level - 1].idx as int].unwrap())
204 .view_rec(self.continuations[self.level - 1].path()
205 .push_tail(self.continuations[self.level - 1].idx as usize))
206 =~= Set::<Mapping>::empty(),
207 ensures
208 self.view_mappings() =~= owner0.view_mappings()
209 {
210 let L = self.level as int;
211 let cont = self.continuations[L - 1];
212 let cont0 = owner0.continuations[L - 1];
213 let idx = cont0.idx as int;
214
215 assert(cont.view_mappings() =~= cont0.view_mappings()) by {
216 cont0.inv_children_unroll(idx);
217 PageTableOwner(cont0.children[idx].unwrap())
218 .view_rec_absent_empty(cont0.path().push_tail(idx as usize));
219 assert forall |m: Mapping| cont.view_mappings().contains(m)
220 implies cont0.view_mappings().contains(m) by {
221 let j = choose|j:int| 0 <= j < cont.children.len()
222 && #[trigger] cont.children[j] is Some
223 && PageTableOwner(cont.children[j].unwrap())
224 .view_rec(cont.path().push_tail(j as usize)).contains(m);
225 if j != idx { assert(cont.children[j] == cont0.children[j]); }
226 };
227 assert forall |m: Mapping| cont0.view_mappings().contains(m)
228 implies cont.view_mappings().contains(m) by {
229 let j = choose|j:int| 0 <= j < cont0.children.len()
230 && #[trigger] cont0.children[j] is Some
231 && PageTableOwner(cont0.children[j].unwrap())
232 .view_rec(cont0.path().push_tail(j as usize)).contains(m);
233 if j != idx { assert(cont0.children[j] == cont.children[j]); }
234 };
235 };
236 }
237
238 pub proof fn map_branch_none_cur_entry_absent(self)
244 requires
245 self.inv(),
246 forall|i: int| 0 <= i < NR_ENTRIES ==>
248 #[trigger] self.continuations[self.level - 1].children[i] is Some &&
249 self.continuations[self.level - 1].children[i].unwrap().value.is_absent(),
250 ensures
251 self.cur_entry_owner().is_absent(),
252 {
253 }
254
255 pub proof fn cursor_path_nesting(self, i: int, j: int)
256 requires
257 self.inv(),
258 self.level - 1 <= j < i,
259 i < NR_LEVELS,
260 ensures
261 self.continuations[j].path().len() as int > self.continuations[i].path().len() as int,
262 self.continuations[j].path().index(self.continuations[i].path().len() as int)
263 == self.continuations[i].idx,
264 {
265 if i == 3 && j == 2 {
266 self.continuations[3].path().push_tail_property_index(self.continuations[3].idx as usize);
267 self.continuations[3].path().push_tail_property_len(self.continuations[3].idx as usize);
268 } else if i == 3 && j == 1 {
269 let p3 = self.continuations[3].path();
270 let p2 = self.continuations[2].path();
271 let idx3 = self.continuations[3].idx as usize;
272 let idx2 = self.continuations[2].idx as usize;
273 p3.push_tail_property_index(idx3);
274 p3.push_tail_property_len(idx3);
275 p2.push_tail_property_index(idx2);
276 p2.push_tail_property_len(idx2);
277 assert(p3.len() < p2.len());
278 assert(self.continuations[1].path() == p2.push_tail(idx2));
279 assert(p2.push_tail(idx2).index(p3.len() as int) == p2.index(p3.len() as int));
280 } else if i == 3 && j == 0 {
281 let p3 = self.continuations[3].path();
282 let p2 = self.continuations[2].path();
283 let p1 = self.continuations[1].path();
284 let idx3 = self.continuations[3].idx as usize;
285 let idx2 = self.continuations[2].idx as usize;
286 let idx1 = self.continuations[1].idx as usize;
287 p3.push_tail_property_index(idx3);
288 p3.push_tail_property_len(idx3);
289 p2.push_tail_property_index(idx2);
290 p2.push_tail_property_len(idx2);
291 p1.push_tail_property_index(idx1);
292 p1.push_tail_property_len(idx1);
293 assert(p3.len() < p2.len());
294 assert(p3.len() < p1.len());
295 assert(p1.push_tail(idx1).index(p3.len() as int) == p1.index(p3.len() as int));
296 assert(p2.push_tail(idx2).index(p3.len() as int) == p2.index(p3.len() as int));
297 } else if i == 2 && j == 1 {
298 self.continuations[2].path().push_tail_property_index(self.continuations[2].idx as usize);
299 self.continuations[2].path().push_tail_property_len(self.continuations[2].idx as usize);
300 } else if i == 2 && j == 0 {
301 let p2 = self.continuations[2].path();
302 let p1 = self.continuations[1].path();
303 let idx2 = self.continuations[2].idx as usize;
304 let idx1 = self.continuations[1].idx as usize;
305 p2.push_tail_property_index(idx2);
306 p2.push_tail_property_len(idx2);
307 p1.push_tail_property_index(idx1);
308 p1.push_tail_property_len(idx1);
309 assert(p2.len() < p1.len());
310 assert(self.continuations[0].path() == p1.push_tail(idx1));
311 assert(p1.push_tail(idx1).index(p2.len() as int) == p1.index(p2.len() as int));
312 assert(p1 == p2.push_tail(idx2));
313 assert(p2.push_tail(idx2).index(p2.len() as int) == idx2);
314 } else if i == 1 && j == 0 {
315 self.continuations[1].path().push_tail_property_index(self.continuations[1].idx as usize);
316 self.continuations[1].path().push_tail_property_len(self.continuations[1].idx as usize);
317 }
318 }
319
320 pub proof fn lemma_page_size_spec_5_eq_pow2_48()
321 ensures
322 page_size_spec(5) == pow2(48nat) as usize,
323 {
324 crate::specs::arch::paging_consts::lemma_nr_subpage_per_huge_eq_nr_entries();
325 vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
326 vstd::arithmetic::power2::lemma2_to64();
327 vstd::arithmetic::power2::lemma2_to64_rest();
328 vstd::arithmetic::power2::lemma_pow2_adds(12nat, 36nat);
329 }
330
331 pub proof fn jump_not_in_node_level_lt_guard_minus_one(
332 self,
333 level: PagingLevel,
334 va: Vaddr,
335 node_start: Vaddr,
336 )
337 requires
338 self.inv(),
339 self.locked_range().start <= va < self.locked_range().end,
340 1 <= level,
341 level + 1 <= self.guard_level,
342 self.locked_range().start <= node_start,
343 node_start + page_size((level + 1) as PagingLevel) <= self.locked_range().end,
344 !(node_start <= va && va < node_start + page_size((level + 1) as PagingLevel)),
345 ensures
346 level + 1 < self.guard_level,
347 {
348 if level + 1 == self.guard_level {
349 let pv = self.prefix.to_vaddr() as nat;
350 let ps = page_size(self.guard_level as PagingLevel) as nat;
351 self.prefix.align_down_concrete(self.guard_level as int);
352 self.prefix.align_up_concrete(self.guard_level as int);
353 self.prefix.align_diff(self.guard_level as int);
354 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(pv, ps) as Vaddr);
355 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_up(pv, ps) as Vaddr);
356 }
357 }
358}
359
360}