ostd/specs/mm/page_table/cursor/
va_lemmas.rs1use vstd::prelude::*;
12use vstd_extra::{arithmetic::nat_align_down, ghost_tree::*, ownership::*};
13
14use crate::specs::{
15 arch::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE},
16 mm::page_table::{
17 Mapping,
18 cursor::{
19 owners::{CursorContinuation, CursorOwner},
20 page_size_lemmas::{
21 lemma_page_size_divides, lemma_page_size_ge_base, lemma_page_size_spec_values,
22 },
23 },
24 lemma_align_down_indices, lemma_inc_slot_indices, lemma_pte_index_bound,
25 lemma_same_node_pte_indices_match,
26 owners::*,
27 pte_index_spec, vaddr_replace_pte_index_spec, vaddr_upper_bits_spec,
28 },
29};
30
31use crate::arch::mm::PagingConsts;
32use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr, page_size, page_table::*};
33use crate::specs::task::InAtomicMode;
34use core::ops::Range;
35
36verus! {
37
38broadcast use group_ghost_tree_lemmas;
39
40impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
41 pub open spec fn zero_below_level(self) -> Self
42 recommends
43 1 <= self.level <= C::NR_LEVELS(),
44 {
45 Self {
46 va: nat_align_down(self.va as nat, page_size::<C>(self.level) as nat) as Vaddr,
47 ..self
48 }
49 }
50
51 pub open spec fn cur_va(self) -> Vaddr {
52 self.va
53 }
54
55 pub open spec fn prefix_vaddr(self) -> Vaddr {
56 self.prefix
57 }
58
59 pub open spec fn cur_va_range(self) -> Range<Vaddr> {
60 let size = page_size::<PagingConsts>(self.level);
61 let start = nat_align_down(self.cur_va() as nat, size as nat) as Vaddr;
62 Range { start, end: (start + size) as Vaddr }
63 }
64
65 pub open spec fn set_va_in_node(self, new_va: Vaddr) -> Self {
66 let old_cont = self.continuations[self.level - 1];
67 Self {
68 va: new_va,
69 continuations: self.continuations.insert(
70 self.level - 1,
71 CursorContinuation { idx: pte_index_spec::<C>(new_va, self.level), ..old_cont },
72 ),
73 popped_too_high: false,
76 ..self
77 }
78 }
79
80 pub proof fn do_zero_below_level(tracked &mut self)
81 requires
82 old(self).inv(),
83 old(self).level <= old(self).guard_level,
84 ensures
85 *final(self) == old(self).zero_below_level(),
86 final(self).inv(),
87 {
88 let ghost old_self = *self;
89 C::lemma_paging_consts_properties();
90 lemma_align_down_indices::<C>(old_self.va, old_self.level);
91 self.va = old_self.zero_below_level().va;
92
93 old_self.lemma_locked_range_span();
94 lemma_page_size_ge_base::<PagingConsts>(old_self.level as PagingLevel);
95 lemma_page_size_ge_base::<PagingConsts>(old_self.guard_level as PagingLevel);
96 lemma_page_size_divides::<PagingConsts>(
97 old_self.level as PagingLevel,
98 old_self.guard_level as PagingLevel,
99 );
100 let ghost old_va_val = old_self.va as nat;
101 let ghost prefix_va_val = old_self.prefix as nat;
102 let ghost ps = page_size::<PagingConsts>(old_self.level as PagingLevel) as nat;
103 let ghost guard_ps = page_size::<PagingConsts>(old_self.guard_level as PagingLevel) as nat;
104 let ghost start = old_self.locked_range().start as nat;
105
106 vstd_extra::arithmetic::lemma_nat_align_down_monotone(prefix_va_val, ps, guard_ps);
107 vstd_extra::arithmetic::lemma_mod_0_add(start as int, guard_ps as int, ps as int);
108
109 vstd_extra::arithmetic::lemma_nat_align_down_sound(old_va_val, ps);
110 if !self.popped_too_high && (self.in_locked_range() || self.level < self.guard_level) {
111 if self.level == self.guard_level {
112 let new_va_val = self.va as nat;
113 let diff = (new_va_val - start) as nat;
114 vstd::arithmetic::div_mod::lemma_mod_equivalence(
115 new_va_val as int,
116 start as int,
117 ps as int,
118 );
119 vstd::arithmetic::div_mod::lemma_small_mod(diff, ps);
120 }
121 }
122 }
123
124 pub proof fn zero_preserves_all_but_va(self)
125 ensures
126 self.zero_below_level().level == self.level,
127 self.zero_below_level().continuations == self.continuations,
128 self.zero_below_level().guard_level == self.guard_level,
129 self.zero_below_level().prefix == self.prefix,
130 self.zero_below_level().popped_too_high == self.popped_too_high,
131 {
132 }
133
134 pub proof fn lemma_inc_index_va(self)
136 requires
137 self.inv(),
138 self.in_locked_range(),
139 self.index() + 1 < NR_ENTRIES,
140 ensures
141 self.inc_index().va == self.va + page_size::<C>(self.level),
142 {
143 C::lemma_paging_consts_properties();
144 self.lemma_cur_pte_index();
145 lemma_inc_slot_indices::<C>(self.va, self.level);
146 reveal(vaddr_replace_pte_index_spec);
147 vstd::arithmetic::mul::lemma_mul_basics(page_size::<C>(self.level) as int);
148 }
149
150 pub proof fn inc_and_zero_increases_va(self)
152 requires
153 self.inv(),
154 self.in_locked_range(),
155 self.index() + 1 < NR_ENTRIES,
156 ensures
157 self.inc_index().zero_below_level().va > self.va,
158 self.inc_index().zero_below_level().va == self@.align_up_spec(
159 page_size::<PagingConsts>(self.level),
160 ),
161 {
162 C::lemma_paging_consts_properties();
163 self.lemma_inc_index_va();
164 lemma_page_size_ge_base::<PagingConsts>(self.level);
165 let ps = page_size::<PagingConsts>(self.level) as nat;
166 let va = self.va as nat;
167 vstd_extra::arithmetic::lemma_nat_align_down_sound(va, ps);
168 vstd::arithmetic::div_mod::lemma_mod_add_multiples_vanish(va as int, ps as int);
169 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(va as int, ps as int);
170 }
171
172 pub proof fn cur_va_in_subtree_range(self)
174 requires
175 self.inv(),
176 self.in_locked_range(),
177 ensures
178 vaddr_of::<C>(self.cur_subtree().value().path) <= self.cur_va() < vaddr_of::<C>(
179 self.cur_subtree().value().path,
180 ) + page_size::<PagingConsts>(self.level),
181 vaddr_of::<C>(self.cur_subtree().value().path) == nat_align_down(
182 self.cur_va() as nat,
183 page_size::<PagingConsts>(self.level) as nat,
184 ),
185 {
186 self.cur_va_in_cont_child_range(self.level - 1);
187 }
188
189 pub proof fn lemma_locked_range_vaddr_prefix_match(self, new_va: Vaddr)
191 requires
192 self.inv(),
193 new_va % C::BASE_PAGE_SIZE() == 0,
194 vaddr_upper_bits_spec::<C>(new_va) == vaddr_upper_bits_spec::<C>(self.prefix_vaddr()),
195 self.locked_range().start <= new_va < self.locked_range().end,
196 ensures
197 pte_index_spec::<C>(new_va, self.guard_level) == pte_index_spec::<C>(
198 self.prefix,
199 self.guard_level,
200 ),
201 forall|i: int|
202 self.guard_level - 1 <= i < C::NR_LEVELS() ==> (#[trigger] pte_index_spec::<C>(
203 new_va,
204 (i + 1) as PagingLevel,
205 )) == pte_index_spec::<C>(self.prefix_vaddr(), (i + 1) as PagingLevel),
206 {
207 C::lemma_paging_consts_properties();
208 self.lemma_locked_range_span();
209 let gl = self.guard_level;
210 if gl == 1 {
211 lemma_page_size_spec_values();
212 let ps = C::BASE_PAGE_SIZE() as int;
213 let diff = new_va - self.prefix;
214 vstd::arithmetic::div_mod::lemma_mod_equivalence(new_va as int, self.prefix as int, ps);
215 vstd::arithmetic::div_mod::lemma_small_mod(diff as nat, ps as nat);
216 assert(new_va == self.prefix);
217 } else {
218 lemma_same_node_pte_indices_match::<C>(
219 new_va,
220 self.prefix,
221 self.prefix,
222 (gl - 1) as PagingLevel,
223 );
224 }
225 }
226
227 pub proof fn lemma_cur_pte_index(self)
231 requires
232 self.inv(),
233 self.in_locked_range(),
234 ensures
235 1 <= self.level <= C::NR_LEVELS(),
236 pte_index_spec::<C>(self.cur_va(), self.level) == self.continuations[self.level
237 - 1].idx,
238 pte_index_spec::<C>(self.cur_va(), self.level) < NR_ENTRIES,
239 {
240 C::lemma_paging_consts_properties();
241 lemma_pte_index_bound::<C>(self.cur_va(), self.level);
242 }
243
244 pub proof fn tracked_set_vaddr_in_node(tracked &mut self, new_va: Vaddr)
247 requires
248 old(self).inv(),
249 new_va % C::BASE_PAGE_SIZE() == 0,
250 vaddr_upper_bits_spec::<C>(new_va) == vaddr_upper_bits_spec::<C>(old(self).cur_va()),
251 forall|i: int|
252 old(self).level <= i < C::NR_LEVELS() ==> (#[trigger] pte_index_spec::<C>(
253 new_va,
254 (i + 1) as PagingLevel,
255 )) == pte_index_spec::<C>(old(self).cur_va(), (i + 1) as PagingLevel),
256 old(self).locked_range().start <= new_va < old(self).locked_range().end,
257 old(self).level <= old(self).guard_level,
258 ensures
259 *final(self) == old(self).set_va_in_node(new_va),
260 final(self).inv(),
261 {
262 let ghost old_self = *self;
263 C::lemma_paging_consts_properties();
264 lemma_pte_index_bound::<C>(new_va, old_self.level);
265 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
266 cont.idx = pte_index_spec::<C>(new_va, old_self.level);
267 self.continuations.tracked_insert(self.level - 1, cont);
268 self.va = new_va;
269 self.popped_too_high = false;
270 assert(self.continuations == old_self.continuations.insert(old_self.level - 1, cont));
271 old_self.lemma_locked_range_vaddr_prefix_match(new_va);
272 if old_self.level < old_self.guard_level {
273 old_self.lemma_prefix_in_locked_range();
274 }
275 }
276}
277
278impl<'rcu, C: PageTableConfig, A: InAtomicMode> Cursor<'rcu, C, A> {
279 pub proof fn lemma_pte_index_matches_owner(self, owner: CursorOwner<'rcu, C>)
282 requires
283 self.wf(owner),
284 owner.inv(),
285 owner.in_locked_range(),
286 ensures
287 1 <= self.level <= C::NR_LEVELS(),
288 pte_index_spec::<C>(self.va, self.level) == owner.continuations[owner.level - 1].idx,
289 pte_index_spec::<C>(self.va, self.level) < NR_ENTRIES,
290 {
291 owner.lemma_cur_pte_index();
292 }
293}
294
295}