ostd/specs/mm/page_table/cursor/
va_lemmas.rs1use vstd::prelude::*;
12
13use core::ops::Range;
14
15use vstd_extra::ghost_tree::*;
16use vstd_extra::ownership::*;
17
18use crate::mm::page_table::*;
19use crate::mm::{Paddr, PagingLevel, Vaddr};
20use crate::specs::arch::mm::{NR_ENTRIES, NR_LEVELS};
21use crate::specs::mm::page_table::AbstractVaddr;
22use crate::specs::mm::page_table::Mapping;
23use crate::specs::mm::page_table::cursor::owners::{CursorContinuation, CursorOwner};
24use crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size;
25use crate::specs::mm::page_table::owners::*;
26use vstd_extra::arithmetic::{nat_align_down, nat_align_up};
27
28verus! {
29
30impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
31 pub open spec fn zero_below_level_rec(self, level: PagingLevel) -> Self
33 decreases self.level - level,
34 {
35 if self.level <= level {
36 self
37 } else {
38 Self {
39 va: AbstractVaddr { index: self.va.index.insert(level - 1, 0), ..self.va },
40 ..self.zero_below_level_rec((level + 1) as u8)
41 }
42 }
43 }
44
45 pub open spec fn zero_below_level(self) -> Self
46 recommends
47 1 <= self.level <= NR_LEVELS,
48 {
49 Self { va: self.va.align_down(self.level as int), ..self }
50 }
51
52 pub open spec fn cur_va(self) -> Vaddr {
53 self.va.to_vaddr()
54 }
55
56 pub open spec fn cur_va_range(self) -> Range<AbstractVaddr> {
57 let start = self.va.align_down(self.level as int);
58 let end = self.va.align_up(self.level as int);
59 Range { start, end }
60 }
61
62 pub open spec fn set_va(self, new_va: AbstractVaddr) -> Self {
63 Self { va: new_va, ..self }
64 }
65
66 pub open spec fn set_va_in_node(self, new_va: AbstractVaddr) -> Self {
67 let old_cont = self.continuations[self.level - 1];
68 Self {
69 va: new_va,
70 continuations: self.continuations.insert(
71 self.level - 1,
72 CursorContinuation { idx: new_va.index[self.level - 1] as usize, ..old_cont },
73 ),
74 popped_too_high: false,
77 ..self
78 }
79 }
80
81 pub proof fn zero_below_level_rec_preserves_above(self, level: PagingLevel)
83 ensures
84 forall|lv: int|
85 lv >= self.level ==> self.zero_below_level_rec(level).va.index[lv]
86 == #[trigger] self.va.index[lv],
87 decreases self.level - level,
88 {
89 if self.level > level {
90 self.zero_below_level_rec_preserves_above((level + 1) as u8);
91 }
92 }
93
94 pub proof fn zero_below_level_va(self)
96 requires
97 1 <= self.level <= NR_LEVELS,
98 ensures
99 self.zero_below_level().va == self.va.align_down(self.level as int),
100 {
101 }
102
103 pub proof fn zero_preserves_above(self)
104 requires
105 self.va.inv(),
106 1 <= self.level <= NR_LEVELS,
107 ensures
108 forall|lv: int|
109 self.level <= lv < NR_LEVELS ==> self.zero_below_level().va.index[lv]
110 == #[trigger] self.va.index[lv],
111 {
112 self.va.align_down_shape(self.level as int);
113 }
114
115 pub axiom fn do_zero_below_level(tracked &mut self)
116 requires
117 old(self).inv(),
118 ensures
119 *final(self) == old(self).zero_below_level(),
120 final(self).inv(),
121 ;
122
123 pub proof fn zero_rec_preserves_all_but_va(self, level: PagingLevel)
124 ensures
125 self.zero_below_level_rec(level).level == self.level,
126 self.zero_below_level_rec(level).continuations == self.continuations,
127 self.zero_below_level_rec(level).guard_level == self.guard_level,
128 self.zero_below_level_rec(level).prefix == self.prefix,
129 self.zero_below_level_rec(level).popped_too_high == self.popped_too_high,
130 decreases self.level - level,
131 {
132 if self.level > level {
133 self.zero_rec_preserves_all_but_va((level + 1) as u8);
134 }
135 }
136
137 pub proof fn zero_preserves_all_but_va(self)
138 ensures
139 self.zero_below_level().level == self.level,
140 self.zero_below_level().continuations == self.continuations,
141 self.zero_below_level().guard_level == self.guard_level,
142 self.zero_below_level().prefix == self.prefix,
143 self.zero_below_level().popped_too_high == self.popped_too_high,
144 {
145 self.zero_rec_preserves_all_but_va(1u8);
146 }
147
148 pub proof fn inc_and_zero_increases_va(self)
150 requires
151 self.inv(),
152 self.in_locked_range(),
153 self.index() + 1 < NR_ENTRIES,
154 ensures
155 self.inc_index().zero_below_level().va.to_vaddr() > self.va.to_vaddr(),
156 {
157 let inc = self.inc_index();
160 inc.zero_preserves_all_but_va();
161 inc.zero_below_level_va();
162 assert(inc.va.inv()) by {
163 assert forall|i: int| 0 <= i < NR_LEVELS implies inc.va.index.contains_key(i) && 0
164 <= #[trigger] inc.va.index[i] && inc.va.index[i] < NR_ENTRIES by {
165 if i != self.level - 1 {
166 assert(inc.va.index[i] == self.va.index[i]);
167 }
168 };
169 };
170 let ps = page_size(self.level as PagingLevel) as nat;
171 let self_va = self.va.to_vaddr() as nat;
172 lemma_page_size_ge_page_size(self.level as PagingLevel);
173
174 assert(self.va.index[self.level - 1] == self.continuations[self.level - 1].idx);
176 self.va.index_increment_adds_page_size(self.level as int);
177 let inc_va = inc.va.to_vaddr() as nat;
178 assert(inc_va == self_va + ps);
179
180 inc.va.align_down_concrete(self.level as int);
183 let new_va = vstd_extra::arithmetic::nat_align_down(inc_va, ps);
184 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(new_va as Vaddr);
185 assert(self_va + ps == ps * 1 + self_va) by (nonlinear_arith);
191 vstd::arithmetic::div_mod::lemma_mod_multiples_vanish(1int, self_va as int, ps as int);
192
193 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(self_va as int, ps as int);
197 vstd::arithmetic::div_mod::lemma_mod_bound(self_va as int, ps as int);
198 let ad = vstd_extra::arithmetic::nat_align_down(self_va, ps);
199 assert(ad + ps > self_va) by {
200 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va, ps);
201 };
202 assert(new_va == ad + ps) by {
203 vstd_extra::arithmetic::lemma_nat_align_down_sound(self_va, ps);
204 vstd_extra::arithmetic::lemma_nat_align_down_sound(inc_va, ps);
205 };
206 }
207
208 pub proof fn cur_va_range_reflects_view(self)
210 requires
211 self.inv(),
212 self.in_locked_range(),
213 !self.popped_too_high,
214 self.cur_entry_owner().is_frame(),
215 ensures
216 self.cur_va_range().start.reflect(self@.query_range().start as Vaddr),
217 self.cur_va_range().end.reflect(self@.query_range().end as Vaddr),
218 {
219 self.cur_subtree_inv();
220 self.cur_va_in_subtree_range();
221 self.view_preserves_inv();
222 self.cur_entry_frame_present();
223 let subtree = self.cur_subtree();
224 let path = subtree.value.path;
225 let frame = self.cur_entry_owner().frame.unwrap();
226 let pt_level = INC_LEVELS - path.len();
227 let cont = self.continuations[self.level - 1];
228
229 cont.path().push_tail_property_len(cont.idx as usize);
230 assert(cont.level() == self.level) by {
231 if self.level == 1 {
232 } else if self.level == 2 {
233 } else if self.level == 3 {
234 } else {
235 }
236 };
237 assert(pt_level == self.level);
238
239 let ps = page_size(self.level as PagingLevel);
240 let m = Mapping {
241 va_range: Range {
242 start: vaddr_of::<C>(path) as int,
243 end: vaddr_of::<C>(path) as int + ps as int,
244 },
245 pa_range: Range { start: frame.mapped_pa, end: (frame.mapped_pa + ps) as Paddr },
246 page_size: ps,
247 property: frame.prop,
248 };
249 assert(PageTableOwner(subtree).view_rec(path) =~= set![m]);
250 assert(self.view_mappings().contains(m));
251 assert(m.inv());
252
253 self.cur_va_in_subtree_range();
254 crate::specs::mm::page_table::owners::lemma_vaddr_of_eq_int::<C>(path);
255 assert(m.va_range.start <= self@.cur_va < m.va_range.end);
256
257 let filtered = self@.mappings.filter(
258 |m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end,
259 );
260 assert(filtered.contains(m));
261 vstd::set::axiom_set_intersect_finite::<Mapping>(
262 self@.mappings,
263 Set::new(|m2: Mapping| m2.va_range.start <= self@.cur_va < m2.va_range.end),
264 );
265 vstd::set::axiom_set_choose_len(filtered);
266 let qm = self@.query_mapping();
267 assert(filtered.contains(qm));
268 assert(qm == m) by {
269 if qm != m {
270 assert(self@.mappings.contains(qm));
271 assert(self@.mappings.contains(m));
272 assert(!(qm.va_range.end <= m.va_range.start || m.va_range.end
273 <= qm.va_range.start));
274 }
275 };
276
277 let cur_va = self.va.to_vaddr() as nat;
278 let ps_nat = ps as nat;
279 self.va.align_down_concrete(self.level as int);
280 lemma_page_size_ge_page_size(self.level as PagingLevel);
281 vstd_extra::arithmetic::lemma_nat_align_down_sound(cur_va, ps_nat);
282
283 assert(vaddr_of::<C>(path) as int % ps as int == 0);
288 assert(vaddr_of::<C>(path) <= cur_va < vaddr_of::<C>(path) + ps);
289 assert(nat_align_down(cur_va, ps_nat) == vaddr_of::<C>(path) as nat) by {
290 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(cur_va as int, ps as int);
291 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(
292 vaddr_of::<C>(path) as int,
293 ps as int,
294 );
295 vstd::arithmetic::div_mod::lemma_div_is_ordered(
296 vaddr_of::<C>(path) as int,
297 cur_va as int,
298 ps as int,
299 );
300 let q_cur = cur_va as int / ps as int;
301 let q_path = vaddr_of::<C>(path) as int / ps as int;
302 assert(q_path * ps as int == vaddr_of::<C>(path) as int);
303 vstd::arithmetic::mul::lemma_mul_inequality(q_path, q_cur, ps as int);
304 if q_path < q_cur {
305 vstd::arithmetic::mul::lemma_mul_inequality(q_path + 1, q_cur, ps as int);
306 vstd::arithmetic::mul::lemma_mul_is_distributive_add_other_way(
307 ps as int,
308 q_path,
309 1int,
310 );
311 assert(false);
312 }
313 };
314 assert(nat_align_down(cur_va, ps_nat) + ps_nat == (vaddr_of::<C>(path) + ps) as nat);
315 self.locked_range_page_aligned();
316 self.va.to_vaddr_bounded();
317 self.in_locked_range_level_le_guard_level();
318 self.va_plus_page_size_no_overflow(self.level as PagingLevel);
319 self.va.align_up_advances_general(self.level as int);
320 assert(self.va.align_up(self.level as int).to_vaddr() as nat == (vaddr_of::<C>(path)
321 + ps) as nat);
322
323 AbstractVaddr::from_vaddr_to_vaddr_roundtrip(nat_align_down(cur_va, ps_nat) as Vaddr);
324 AbstractVaddr::from_vaddr_to_vaddr_roundtrip((vaddr_of::<C>(path) + ps) as Vaddr);
325
326 self.va.align_up(self.level as int).reflect_to_vaddr();
327 }
328
329 pub proof fn cur_va_in_subtree_range(self)
333 requires
334 self.inv(),
335 self.in_locked_range(),
336 ensures
337 vaddr(self.cur_subtree().value.path) as int + self.va.leading_bits
338 * 0x1_0000_0000_0000int <= self.cur_va() as int,
339 (self.cur_va() as int) < vaddr(self.cur_subtree().value.path) as int
340 + self.va.leading_bits * 0x1_0000_0000_0000int + page_size(
341 self.level as PagingLevel,
342 ) as int,
343 {
344 let L = self.level as int;
345 let cont = self.continuations[L - 1];
346 let subtree_path = cont.path().push_tail(cont.idx as usize);
347 let va_path = self.va.to_path(L - 1);
348
349 self.va.to_path_len(L - 1);
350 cont.path().push_tail_property_len(cont.idx as usize);
351 assert(cont.level() == self.level) by {
352 if L == 1 {
353 } else if L == 2 {
354 } else if L == 3 {
355 } else {
356 }
357 };
358
359 assert forall|i: int| 0 <= i < subtree_path.len() implies subtree_path.index(i)
360 == va_path.index(i) by {
361 self.va.to_path_index(L - 1, i);
362 if L == 4 {
363 cont.path().push_tail_property_index(cont.idx as usize);
364 } else if L == 3 {
365 cont.path().push_tail_property_index(cont.idx as usize);
366 self.continuations[3].path().push_tail_property_index(
367 self.continuations[3].idx as usize,
368 );
369 } else if L == 2 {
370 cont.path().push_tail_property_index(cont.idx as usize);
371 self.continuations[2].path().push_tail_property_index(
372 self.continuations[2].idx as usize,
373 );
374 self.continuations[3].path().push_tail_property_index(
375 self.continuations[3].idx as usize,
376 );
377 } else {
378 cont.path().push_tail_property_index(cont.idx as usize);
379 self.continuations[1].path().push_tail_property_index(
380 self.continuations[1].idx as usize,
381 );
382 self.continuations[2].path().push_tail_property_index(
383 self.continuations[2].idx as usize,
384 );
385 self.continuations[3].path().push_tail_property_index(
386 self.continuations[3].idx as usize,
387 );
388 }
389 };
390
391 self.va.to_path_inv(L - 1);
392 self.cur_subtree_inv();
393 AbstractVaddr::rec_vaddr_eq_if_indices_eq(subtree_path, va_path, 0);
394 self.va.vaddr_range_from_path(L - 1);
395 }
396
397 pub axiom fn tracked_set_va(tracked &mut self, new_va: AbstractVaddr)
399 requires
400 forall|i: int|
401 #![auto]
402 old(self).level - 1 <= i < NR_LEVELS ==> new_va.index[i] == old(self).va.index[i],
403 forall|i: int|
404 #![auto]
405 old(self).guard_level - 1 <= i < NR_LEVELS ==> new_va.index[i] == old(
406 self,
407 ).prefix.index[i],
408 ensures
409 *final(self) == old(self).set_va(new_va),
410 ;
411
412 pub axiom fn tracked_set_va_in_node(tracked &mut self, new_va: AbstractVaddr)
416 requires
417 old(self).inv(),
418 new_va.inv(),
419 forall|i: int|
420 #![auto]
421 old(self).level <= i < NR_LEVELS ==> new_va.index[i] == old(self).va.index[i],
422 old(self).locked_range().start <= new_va.to_vaddr() < old(self).locked_range().end,
423 old(self).level <= old(self).guard_level,
429 ensures
430 *final(self) == old(self).set_va_in_node(new_va),
431 final(self).inv(),
432 ;
433}
434
435}