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::*,
16 mm::page_table::{
17 cursor::{
18 owners::{CursorContinuation, CursorOwner},
19 page_size_lemmas::*,
20 },
21 owners::*,
22 *,
23 },
24};
25
26use crate::arch::mm::PagingConsts;
27use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr, page_size, page_table::*};
28use crate::specs::task::InAtomicMode;
29use core::ops::Range;
30
31verus! {
32
33broadcast use group_ghost_tree_lemmas;
34
35impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
36 pub open spec fn zero_below_level(self) -> Self
37 recommends
38 1 <= self.level <= C::NR_LEVELS(),
39 {
40 Self {
41 va: nat_align_down(self.va as nat, page_size::<C>(self.level) as nat) as Vaddr,
42 ..self
43 }
44 }
45
46 pub open spec fn cur_va(self) -> Vaddr {
47 self.va
48 }
49
50 pub open spec fn prefix_vaddr(self) -> Vaddr {
51 self.prefix
52 }
53
54 pub open spec fn cur_va_range(self) -> Range<Vaddr> {
55 let size = page_size::<PagingConsts>(self.level);
56 let start = nat_align_down(self.cur_va() as nat, size as nat) as Vaddr;
57 Range { start, end: (start + size) as Vaddr }
58 }
59
60 pub open spec fn set_va_in_node(self, new_va: Vaddr) -> Self {
61 let old_cont = self.continuations[self.level - 1];
62 Self {
63 va: new_va,
64 continuations: self.continuations.insert(
65 self.level - 1,
66 CursorContinuation { idx: pte_index_spec::<C>(new_va, self.level), ..old_cont },
67 ),
68 popped_too_high: false,
71 ..self
72 }
73 }
74
75 pub proof fn lemma_inc_index_va(self)
77 requires
78 self.inv(),
79 self.in_barrier_va(),
80 self.index() + 1 < NR_ENTRIES,
81 ensures
82 self.inc_index().va == self.va + page_size::<C>(self.level),
83 {
84 C::lemma_paging_consts_properties();
85 C::axiom_current_paging_consts_hardcoded();
86 self.lemma_cur_pte_index();
87 lemma_inc_slot_indices::<C>(self.va, self.level);
88 reveal(vaddr_replace_pte_index_spec);
89 vstd::arithmetic::mul::lemma_mul_basics(page_size::<C>(self.level) as int);
90 }
91
92 pub proof fn inc_and_zero_increases_va(self)
94 requires
95 self.inv(),
96 self.in_barrier_va(),
97 self.index() + 1 < NR_ENTRIES,
98 ensures
99 self.inc_index().zero_below_level().va > self.va,
100 self.inc_index().zero_below_level().va == self@.align_up_spec(
101 page_size::<PagingConsts>(self.level),
102 ),
103 {
104 C::lemma_paging_consts_properties();
105 C::axiom_current_paging_consts_hardcoded();
106 self.lemma_inc_index_va();
107 lemma_page_size_ge_base::<PagingConsts>(self.level);
108 let ps = page_size::<PagingConsts>(self.level) as nat;
109 let va = self.va as nat;
110 vstd_extra::arithmetic::lemma_nat_align_down_sound(va, ps);
111 vstd::arithmetic::div_mod::lemma_mod_add_multiples_vanish(va as int, ps as int);
112 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(va as int, ps as int);
113 }
114
115 pub proof fn cur_va_in_subtree_range(self)
117 requires
118 self.inv(),
119 self.in_barrier_va(),
120 ensures
121 vaddr_of::<C>(self.cur_subtree().value().path) <= self.cur_va() < vaddr_of::<C>(
122 self.cur_subtree().value().path,
123 ) + page_size::<PagingConsts>(self.level),
124 vaddr_of::<C>(self.cur_subtree().value().path) == nat_align_down(
125 self.cur_va() as nat,
126 page_size::<PagingConsts>(self.level) as nat,
127 ),
128 {
129 self.cur_va_in_cont_child_range(self.level - 1);
130 }
131
132 pub proof fn lemma_locked_range_vaddr_prefix_match(self, new_va: Vaddr)
134 requires
135 self.inv(),
136 new_va % C::BASE_PAGE_SIZE() == 0,
137 vaddr_leading_part_spec::<C>(new_va) == vaddr_leading_part_spec::<C>(
138 self.prefix_vaddr(),
139 ),
140 self.locked_range().start <= new_va < self.locked_range().end,
141 ensures
142 forall|i: int|
143 self.guard_level <= i < C::NR_LEVELS() ==> (#[trigger] pte_index_spec::<C>(
144 new_va,
145 (i + 1) as PagingLevel,
146 )) == pte_index_spec::<C>(self.prefix, (i + 1) as PagingLevel),
147 {
148 C::lemma_paging_consts_properties();
149 C::axiom_current_paging_consts_hardcoded();
150 self.lemma_locked_range_span();
151 if self.guard_level < C::NR_LEVELS() {
152 lemma_same_node_pte_indices_match::<C>(
153 new_va,
154 self.prefix,
155 self.prefix,
156 self.guard_level,
157 );
158 }
159 }
160
161 pub proof fn lemma_cur_pte_index(self)
165 requires
166 self.inv(),
167 self.in_barrier_va(),
168 ensures
169 1 <= self.level <= C::NR_LEVELS(),
170 pte_index_spec::<C>(self.cur_va(), self.level) == self.continuations[self.level
171 - 1].idx,
172 pte_index_spec::<C>(self.cur_va(), self.level) < NR_ENTRIES,
173 {
174 C::lemma_paging_consts_properties();
175 C::axiom_current_paging_consts_hardcoded();
176 lemma_pte_index_bound::<C>(self.cur_va(), self.level);
177 }
178
179 pub proof fn tracked_set_vaddr_in_node(tracked &mut self, new_va: Vaddr)
182 requires
183 old(self).inv(),
184 new_va % C::BASE_PAGE_SIZE() == 0,
185 vaddr_leading_part_spec::<C>(new_va) == vaddr_leading_part_spec::<C>(
186 old(self).cur_va(),
187 ),
188 forall|i: int|
189 old(self).level <= i < C::NR_LEVELS() ==> (#[trigger] pte_index_spec::<C>(
190 new_va,
191 (i + 1) as PagingLevel,
192 )) == old(self).continuations[i].idx,
193 old(self).locked_range().start <= new_va < old(self).locked_range().end,
194 old(self).set_va_in_node(new_va).in_barrier_va(),
195 old(self).level <= old(self).guard_level,
196 ensures
197 *final(self) == old(self).set_va_in_node(new_va),
198 final(self).inv(),
199 {
200 let ghost old_self = *self;
201 C::lemma_paging_consts_properties();
202 C::axiom_current_paging_consts_hardcoded();
203 lemma_pte_index_bound::<C>(new_va, old_self.level);
204 let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
205 cont.idx = pte_index_spec::<C>(new_va, old_self.level);
206 self.continuations.tracked_insert(self.level - 1, cont);
207 self.va = new_va;
208 self.popped_too_high = false;
209 assert(self.continuations == old_self.continuations.insert(old_self.level - 1, cont));
210 old_self.lemma_locked_range_vaddr_prefix_match(new_va);
211 old_self.lemma_barrier_va_bounds(new_va);
212 }
213}
214
215impl<'rcu, C: PageTableConfig, A: InAtomicMode> Cursor<'rcu, C, A> {
216 pub proof fn lemma_pte_index_matches_owner(self, owner: CursorOwner<'rcu, C>)
219 requires
220 self.wf(owner),
221 owner.inv(),
222 owner.in_barrier_va(),
223 ensures
224 1 <= self.level <= C::NR_LEVELS(),
225 pte_index_spec::<C>(self.va, self.level) == owner.continuations[owner.level - 1].idx,
226 pte_index_spec::<C>(self.va, self.level) < NR_ENTRIES,
227 {
228 owner.lemma_cur_pte_index();
229 }
230}
231
232}