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