ostd/specs/mm/page_table/cursor/
page_table_cursor_specs.rs1use vstd::prelude::*;
2
3use vstd::set_lib::*;
4
5use vstd_extra::ownership::*;
6
7use crate::arch::mm::PagingConsts;
8use crate::mm::page_prop::PageProperty;
9use crate::mm::page_table::*;
10use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr};
11use crate::specs::arch::NR_ENTRIES;
12use crate::specs::mm::page_table::cursor::owners::*;
13use crate::specs::mm::page_table::*;
14use vstd_extra::arithmetic::*;
15
16use core::ops::Range;
17
18verus! {
19
20impl<C: PageTableConfig> PageTableOwner<C> {
21 pub uninterp spec fn new_cursor_owner_spec<'rcu>(self) -> (Self, CursorOwner<'rcu, C>);
22}
23
24impl<C: PageTableConfig> CursorView<C> {
29 pub open spec fn item_into_mapping(va: Vaddr, item: C::Item) -> Mapping {
30 let (paddr, level, prop) = C::item_into_raw_spec(item);
31 let size = page_size(level);
32 Mapping {
33 va_range: va as int..va + size,
34 pa_range: paddr..(paddr + size) as Paddr,
35 page_size: size,
36 property: prop,
37 }
38 }
39
40 pub open spec fn present(self) -> bool {
44 self.mappings.filter(|m: Mapping| m.va_range.start <= self.cur_va < m.va_range.end).len()
45 > 0
46 }
47
48 pub open spec fn query_mapping(self) -> Mapping
49 recommends
50 self.present(),
51 {
52 self.mappings.filter(|m: Mapping| m.va_range.start <= self.cur_va < m.va_range.end).choose()
53 }
54
55 pub open spec fn query(self, paddr: Paddr, size: usize, prop: PageProperty) -> bool {
56 let m = self.query_mapping();
57 m.pa_range.start == paddr && m.page_size == size && m.property == prop
58 }
59
60 pub open spec fn query_range(self) -> Range<int> {
61 self.query_mapping().va_range
62 }
63
64 pub open spec fn cur_slot_range(self, size: usize) -> Range<int> {
68 let start = nat_align_down(self.cur_va as nat, size as nat) as int;
69 start..start + size
70 }
71
72 pub open spec fn query_item_spec(self, item: C::Item) -> Option<Range<Vaddr>>
75 recommends
76 self.present(),
77 {
78 let (paddr, level, prop) = C::item_into_raw_spec(item);
79 let size = page_size(level);
80 if self.query(paddr, size, prop) {
81 let r = self.query_range();
82 Some(r.start as Vaddr..r.end as Vaddr)
83 } else {
84 None
85 }
86 }
87
88 pub open spec fn find_next_impl_spec(
93 self,
94 len: usize,
95 find_unmap_subtree: bool,
96 split_huge: bool,
97 ) -> (Self, Option<Mapping>) {
98 let mappings_in_range = self.mappings.filter(
99 |m: Mapping| self.cur_va <= m.va_range.start < self.cur_va + len,
100 );
101
102 if mappings_in_range.len() > 0 {
103 let mapping = mappings_in_range.find_unique_minimal(
104 |m: Mapping, n: Mapping| m.va_range.start < n.va_range.start,
105 );
106 let view = CursorView { cur_va: mapping.va_range.end as Vaddr, ..self };
107 (view, Some(mapping))
108 } else {
109 let view = CursorView { cur_va: (self.cur_va + len) as Vaddr, ..self };
110 (view, None)
111 }
112 }
113
114 pub open spec fn find_next_spec(self, len: usize) -> (Self, Option<Vaddr>) {
118 let (cursor, mapping) = self.find_next_impl_spec(len, false, false);
119 if mapping is Some {
120 (cursor, Some(mapping->0.va_range.start as Vaddr))
121 } else {
122 (cursor, None)
123 }
124 }
125
126 pub open spec fn jump_spec(self, va: usize) -> Self {
128 CursorView { cur_va: va as Vaddr, ..self }
129 }
130
131 pub open spec fn align_up_spec(self, size: usize) -> Vaddr {
138 (nat_align_down(self.cur_va as nat, size as nat) + size as nat) as Vaddr
139 }
140
141 pub open spec fn split_index(m: Mapping, new_size: usize, n: usize) -> Mapping {
142 Mapping {
143 va_range: m.va_range.start + n * new_size..m.va_range.start + (n + 1) * new_size,
144 pa_range: (m.pa_range.start + n * new_size) as usize..(m.pa_range.start + (n + 1)
145 * new_size) as usize,
146 page_size: new_size,
147 property: m.property,
148 }
149 }
150
151 pub open spec fn split_if_mapped_huge_spec(self, new_size: usize) -> Self {
152 let m = self.query_mapping();
153 let size = m.page_size;
154 let new_mappings = Set::<int>::range(0int, (size / new_size) as int).map(
155 |n: int| Self::split_index(m, new_size, n as usize),
156 );
157 CursorView { cur_va: self.cur_va, mappings: self.mappings - set![m] + new_mappings, ..self }
158 }
159
160 pub open spec fn split_while_huge(self, size: usize) -> Self
161 decreases self.query_mapping().page_size,
162 when self.inv()
163 {
164 if self.present() {
165 let m = self.query_mapping();
166 if m.page_size > size {
167 let new_size = m.page_size / NR_ENTRIES;
168 let new_self = self.split_if_mapped_huge_spec(new_size);
169 proof {
170 let f = self.mappings.filter(
171 |m2: Mapping| m2.va_range.start <= self.cur_va < m2.va_range.end,
172 );
173 vstd::set::lemma_set_choose_len(f);
174 assert(self.mappings.contains(m));
175 assert(m.inv());
176 assert(m.page_size % (m.page_size / 512usize) == 0) by {
177 if m.page_size == 4096 {
178 assert(4096usize % (4096usize / 512usize) == 0) by (compute_only);
179 } else if m.page_size == 2097152 {
180 assert(2097152usize % (2097152usize / 512usize) == 0) by (compute_only);
181 } else {
182 assert(1073741824usize % (1073741824usize / 512usize) == 0)
183 by (compute_only);
184 }
185 };
186 Self::split_if_mapped_huge_spec_preserves_present(self, new_size);
187 Self::split_if_mapped_huge_spec_decreases_page_size(self, new_size);
188 }
189 new_self.split_while_huge(size)
190 } else {
191 self
192 }
193 } else {
194 self
195 }
196 }
197
198 pub open spec fn remove_subtree(self, size: usize) -> Set<Mapping> {
199 let start = nat_align_down(self.cur_va as nat, size as nat) as Vaddr;
200 let subtree = self.mappings.filter(|m: Mapping| start <= m.va_range.start < start + size);
201 self.mappings - subtree
202 }
203
204 pub open spec fn map_spec(self, paddr: Paddr, size: usize, prop: PageProperty) -> Self {
208 let new = Mapping {
209 va_range: self.cur_slot_range(size),
210 pa_range: paddr..(paddr + size) as usize,
211 page_size: size,
212 property: prop,
213 };
214 let split_self = self.split_while_huge(size);
215 CursorView {
216 cur_va: split_self.align_up_spec(size),
217 mappings: split_self.remove_subtree(size) + set![new],
218 ..split_self
219 }
220 }
221
222 pub open spec fn map_simple(self, paddr: Paddr, size: usize, prop: PageProperty) -> Self {
223 let new = Mapping {
224 va_range: self.cur_slot_range(size),
225 pa_range: paddr..(paddr + size) as usize,
226 page_size: size,
227 property: prop,
228 };
229 CursorView { cur_va: self.cur_va, mappings: self.mappings + set![new], ..self }
230 }
231
232 pub open spec fn unmap_spec(self, len: usize, new_view: Self, num_unmapped: usize) -> bool {
241 let start = self.cur_va;
242 let end = (self.cur_va + len) as Vaddr;
243 &&& new_view.cur_va
245 >= end
246 &&& forall|m: Mapping| #[trigger]
250 self.mappings.contains(m) && (m.va_range.end <= start || m.va_range.start >= end)
251 ==> new_view.mappings.contains(
252 m,
253 )
254 &&& forall|m: Mapping|
259 new_view.mappings.contains(m) && start <= m.va_range.start < end ==> exists|
260 parent: Mapping,
261 | #[trigger]
262 self.mappings.contains(parent) && parent.va_range.start < start
263 && parent.va_range.start <= m.va_range.start && m.va_range.end
264 <= parent.va_range.end && m.pa_range.start == (parent.pa_range.start + (
265 m.va_range.start - parent.va_range.start)) as Paddr && m.property
266 == parent.property
267 &&& forall|m: Mapping| #[trigger]
270 new_view.mappings.contains(m) ==> self.mappings.contains(m) || exists|parent: Mapping|
271 #[trigger]
272 self.mappings.contains(parent) && parent.va_range.start <= m.va_range.start
273 && m.va_range.end <= parent.va_range.end && m.pa_range.start == (
274 parent.pa_range.start + (m.va_range.start - parent.va_range.start)) as Paddr
275 && m.property == parent.property
276 }
277
278 pub open spec fn protect_spec(
285 self,
286 len: usize,
287 op: spec_fn(PageProperty) -> PageProperty,
288 target_page_size: usize,
289 ) -> (Self, Option<Range<Vaddr>>) {
290 let (find_cursor, next) = self.find_next_impl_spec(len, false, true);
291 if next is Some {
292 let found = next->0;
293 let at_found = CursorView { cur_va: found.va_range.start as Vaddr, ..self };
295 let split_view = at_found.split_while_huge(target_page_size);
296 let split_mapping = split_view.query_mapping();
298 let new_mapping = Mapping { property: op(split_mapping.property), ..split_mapping };
299 let new_cursor = CursorView {
300 cur_va: split_mapping.va_range.end as Vaddr,
301 mappings: split_view.mappings - set![split_mapping] + set![new_mapping],
302 ..self
303 };
304 (
305 new_cursor,
306 Some(split_mapping.va_range.start as Vaddr..split_mapping.va_range.end as Vaddr),
307 )
308 } else {
309 (find_cursor, None)
310 }
311 }
312}
313
314}