1use vstd::prelude::*;
16
17use vstd_extra::{ghost_tree::*, ownership::*};
18
19use crate::specs::{
20 arch::*,
21 mm::{
22 frame::{
23 mapping::frame_to_index, meta_owners::PageUsage, meta_region_owners::MetaRegionOwners,
24 },
25 page_table::{
26 Mapping,
27 cursor::owners::{CursorContinuation, CursorOwner},
28 node::entry_owners::EntryOwner,
29 owners::{OwnerSubtree, PageTableOwner, vaddr_of},
30 },
31 },
32};
33
34use crate::mm::{frame::meta::REF_COUNT_UNUSED, page_size, page_table::*};
35
36verus! {
37
38impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
39 pub open spec fn no_node_at_idx(self, idx: int) -> bool {
47 &&& self.map_full_tree(
48 |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
49 e.is_node() && e.meta_slot_paddr() is Some ==> frame_to_index(
50 e.meta_slot_paddr()->0,
51 ) != idx,
52 )
53 &&& forall|i: int|
54 #![trigger self.continuations[i]]
55 self.level - 1 <= i < NR_LEVELS ==> {
56 let e = self.continuations[i].entry_own;
57 e.is_node() && e.meta_slot_paddr() is Some ==> frame_to_index(
58 e.meta_slot_paddr()->0,
59 ) != idx
60 }
61 }
62
63 pub proof fn and_map_full_tree(
69 self,
70 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
71 guard: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
72 )
73 requires
74 self.inv(),
75 self.map_full_tree(f),
76 self.map_full_tree(guard),
77 ensures
78 self.map_full_tree(|e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| f(e, p) && guard(e, p)),
79 {
80 let combined = |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| f(e, p) && guard(e, p);
81 assert forall|i: int|
82 #![trigger self.continuations[i]]
83 self.level - 1 <= i < NR_LEVELS implies self.continuations[i].map_children(
84 combined,
85 ) by {
86 let cont = self.continuations[i];
87 reveal(CursorContinuation::inv_children);
88 assert forall|j: int|
89 #![trigger cont.children[j]]
90 0 <= j < cont.children.len()
91 && cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
92 cont.path().push_tail(j),
93 combined,
94 ) by {
95 cont.inv_children_unroll(j);
96 OwnerSubtree::lemma_subtree_satisfies_implies_and(
97 cont.children[j].unwrap(),
98 cont.path().push_tail(j),
99 f,
100 guard,
101 combined,
102 );
103 };
104 };
105 }
106
107 pub proof fn no_node_at_idx_from_slot_key(self, regions: MetaRegionOwners, changed_idx: int)
117 requires
118 self.inv(),
119 regions.inv(),
120 self.metaregion_sound(regions),
121 regions.slots.contains_key(changed_idx),
122 regions.slot_owners[changed_idx].usage !is PageTable,
123 ensures
124 self.no_node_at_idx(changed_idx),
125 {
126 let msp = PageTableOwner::<C>::metaregion_sound_pred(regions);
127 let target = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
128 e.is_node() && e.meta_slot_paddr() is Some ==> frame_to_index(
129 e.meta_slot_paddr().unwrap(),
130 ) != changed_idx;
131
132 self.map_children_implies(msp, target);
133
134 assert forall|i: int|
135 #![trigger self.continuations[i]]
136 self.level - 1 <= i < NR_LEVELS implies {
137 let e = self.continuations[i].entry_own;
138 e.is_node() && e.meta_slot_paddr() is Some ==> frame_to_index(
139 e.meta_slot_paddr().unwrap(),
140 ) != changed_idx
141 } by {
142 let entry = self.continuations[i].entry_own;
143 if entry.is_node() && entry.meta_slot_paddr() is Some {
144 let idx = frame_to_index(entry.meta_slot_paddr().unwrap());
145 if idx == changed_idx {
146 assert(false);
147 }
148 }
149 };
150 }
151
152 pub proof fn metaregion_preserved_under_path_insert(
156 self,
157 regions0: MetaRegionOwners,
158 regions1: MetaRegionOwners,
159 changed_idx: int,
160 new_path: TreePath<NR_ENTRIES>,
161 )
162 requires
163 self.inv(),
164 self.metaregion_sound(regions0),
165 regions0.inv(),
166 regions0.slot_owners.contains_key(changed_idx),
167 regions1.slots == regions0.slots,
168 regions1.slot_owners.dom() =~= regions0.slot_owners.dom(),
169 forall|i: int|
170 #![trigger regions1.slot_owners[i]]
171 i != changed_idx ==> regions0.slot_owners[i] == regions1.slot_owners[i],
172 regions1.slot_owners[changed_idx].inner_perms
173 == regions0.slot_owners[changed_idx].inner_perms,
174 regions1.slot_owners[changed_idx].slot_vaddr
175 == regions0.slot_owners[changed_idx].slot_vaddr,
176 regions1.slot_owners[changed_idx].usage == regions0.slot_owners[changed_idx].usage,
177 regions1.slot_owners[changed_idx].paths_in_pt
178 == regions0.slot_owners[changed_idx].paths_in_pt.insert(new_path),
179 self.no_node_at_idx(changed_idx),
180 ensures
181 self.metaregion_sound(regions1),
182 {
183 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
184 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
185 let guard = |entry: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
186 entry.is_node() && entry.meta_slot_paddr() is Some ==> frame_to_index(
187 entry.meta_slot_paddr().unwrap(),
188 ) != changed_idx;
189 let f_strong = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
190 f(entry, path) && guard(entry, path);
191
192 self.and_map_full_tree(f, guard);
193 self.map_children_implies(f_strong, g);
194
195 assert forall|i: int|
196 #![trigger self.continuations[i]]
197 self.level - 1 <= i
198 < NR_LEVELS implies self.continuations[i].entry_own.metaregion_sound(regions1) by {
199 let cont_entry = self.continuations[i].entry_own;
200 if cont_entry.meta_slot_paddr() is Some {
201 cont_entry.metaregion_sound_one_slot_changed(regions0, regions1, changed_idx);
203 }
204 };
205 }
206
207 pub open spec fn path_removable_at_idx(
217 self,
218 idx: int,
219 removed_path: TreePath<NR_ENTRIES>,
220 ) -> bool {
221 &&& self.map_full_tree(
222 |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
223 e.meta_slot_paddr() is Some && frame_to_index(e.meta_slot_paddr()->0) == idx
224 ==> !e.is_node() && (e.is_frame() ==> e.path != removed_path),
225 )
226 &&& forall|i: int|
227 #![trigger self.continuations[i]]
228 self.level - 1 <= i < NR_LEVELS ==> {
229 let e = self.continuations[i].entry_own;
230 e.meta_slot_paddr() is Some && frame_to_index(e.meta_slot_paddr()->0) == idx
231 ==> !e.is_node() && (e.is_frame() ==> e.path != removed_path)
232 }
233 }
234
235 pub open spec fn no_frame_with_path(self, removed_path: TreePath<NR_ENTRIES>) -> bool {
242 &&& self.map_full_tree(
243 |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>| e.is_frame() ==> e.path != removed_path,
244 )
245 &&& forall|i: int|
246 #![trigger self.continuations[i]]
247 self.level - 1 <= i < NR_LEVELS ==> {
248 let e = self.continuations[i].entry_own;
249 e.is_frame() ==> e.path != removed_path
250 }
251 }
252
253 pub proof fn no_frame_with_path_from_no_view_mapping(self, removed_path: TreePath<NR_ENTRIES>)
267 requires
268 self.inv(),
269 forall|m: Mapping|
270 #![trigger self@.mappings.contains(m)]
271 self@.mappings.contains(m) ==> m.va_range.start != vaddr_of::<C>(removed_path),
272 ensures
273 self.no_frame_with_path(removed_path),
274 {
275 broadcast use CursorContinuation::group_lemmas;
276
277 let g = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
278 e.is_frame() ==> e.path != removed_path;
279
280 assert forall|i: int|
283 #![trigger self.continuations[i]]
284 self.level - 1 <= i < NR_LEVELS implies self.continuations[i].map_children(g) by {
285 self.inv_continuation(i);
286 let cont = self.continuations[i];
287 reveal(CursorContinuation::inv_children);
288 assert forall|j: int|
289 #![trigger cont.children[j]]
290 0 <= j < cont.children.len()
291 && cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
292 cont.path().push_tail(j),
293 g,
294 ) by {
295 cont.inv_children_unroll(j);
296 cont.pt_inv_children_unroll(j);
297 cont.inv_children_rel_unroll(j);
298 let child = cont.children[j].unwrap();
299 let child_path = cont.path().push_tail(j);
300 PageTableOwner::<C>::pt_inv_implies_path_correct(child, child_path);
304 assert forall|m: Mapping|
306 #![trigger self@.mappings.contains(m)]
307 PageTableOwner(child).view_rec(child_path).contains(
308 m,
309 ) implies self@.mappings.contains(m) by {
310 self.lemma_view_mappings_intro(m, i);
311 };
312 PageTableOwner(child).no_frame_with_path_rec(
314 child_path,
315 removed_path,
316 self@.mappings,
317 );
318 };
319 };
320
321 assert forall|i: int|
323 #![trigger self.continuations[i]]
324 self.level - 1 <= i < NR_LEVELS implies {
325 let e = self.continuations[i].entry_own;
326 e.is_frame() ==> e.path != removed_path
327 } by {
328 self.inv_continuation(i);
329 };
330 }
331
332 pub proof fn path_removable_from_no_node_and_no_frame_path(
339 self,
340 idx: int,
341 removed_path: TreePath<NR_ENTRIES>,
342 )
343 requires
344 self.inv(),
345 self.no_node_at_idx(idx),
346 self.no_frame_with_path(removed_path),
347 ensures
348 self.path_removable_at_idx(idx, removed_path),
349 {
350 let nn = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
351 e.is_node() && e.meta_slot_paddr() is Some ==> frame_to_index(
352 e.meta_slot_paddr().unwrap(),
353 ) != idx;
354 let nf = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
355 e.is_frame() ==> e.path != removed_path;
356 let r = |e: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
357 e.meta_slot_paddr() is Some && frame_to_index(e.meta_slot_paddr().unwrap()) == idx
358 ==> !e.is_node() && (e.is_frame() ==> e.path != removed_path);
359
360 self.and_map_full_tree(nn, nf);
363 self.map_children_implies(
364 |e: EntryOwner<C>, p: TreePath<NR_ENTRIES>| nn(e, p) && nf(e, p),
365 r,
366 );
367
368 assert forall|i: int|
370 #![trigger self.continuations[i]]
371 self.level - 1 <= i < NR_LEVELS implies {
372 let e = self.continuations[i].entry_own;
373 e.meta_slot_paddr() is Some && frame_to_index(e.meta_slot_paddr().unwrap()) == idx
374 ==> !e.is_node() && (e.is_frame() ==> e.path != removed_path)
375 } by {
376 let e = self.continuations[i].entry_own;
377 }
378 }
379
380 pub proof fn metaregion_preserved_under_path_remove(
390 self,
391 regions0: MetaRegionOwners,
392 regions1: MetaRegionOwners,
393 changed_idx: int,
394 removed_path: TreePath<NR_ENTRIES>,
395 )
396 requires
397 self.inv(),
398 self.metaregion_sound(regions0),
399 regions0.inv(),
400 regions0.slot_owners.contains_key(changed_idx),
401 regions1.slots == regions0.slots,
402 regions1.slot_owners.dom() =~= regions0.slot_owners.dom(),
403 forall|i: int|
404 #![trigger regions1.slot_owners[i]]
405 i != changed_idx ==> regions0.slot_owners[i] == regions1.slot_owners[i],
406 regions1.slot_owners[changed_idx].inner_perms
407 == regions0.slot_owners[changed_idx].inner_perms,
408 regions1.slot_owners[changed_idx].slot_vaddr
409 == regions0.slot_owners[changed_idx].slot_vaddr,
410 regions1.slot_owners[changed_idx].usage == regions0.slot_owners[changed_idx].usage,
411 regions1.slot_owners[changed_idx].paths_in_pt
412 == regions0.slot_owners[changed_idx].paths_in_pt.remove(removed_path),
413 self.path_removable_at_idx(changed_idx, removed_path),
414 ensures
415 self.metaregion_sound(regions1),
416 {
417 let f = PageTableOwner::<C>::metaregion_sound_pred(regions0);
418 let g = PageTableOwner::<C>::metaregion_sound_pred(regions1);
419 let guard = |entry: EntryOwner<C>, _p: TreePath<NR_ENTRIES>|
420 entry.meta_slot_paddr() is Some && frame_to_index(entry.meta_slot_paddr().unwrap())
421 == changed_idx ==> !entry.is_node() && (entry.is_frame() ==> entry.path
422 != removed_path);
423 let f_strong = |entry: EntryOwner<C>, path: TreePath<NR_ENTRIES>|
424 f(entry, path) && guard(entry, path);
425
426 self.and_map_full_tree(f, guard);
427 self.map_children_implies(f_strong, g);
428
429 assert forall|i: int|
430 #![trigger self.continuations[i]]
431 self.level - 1 <= i
432 < NR_LEVELS implies self.continuations[i].entry_own.metaregion_sound(regions1) by {
433 let cont_entry = self.continuations[i].entry_own;
434 if cont_entry.meta_slot_paddr() is Some {
435 let eidx = frame_to_index(cont_entry.meta_slot_paddr().unwrap());
436 if eidx != changed_idx {
437 cont_entry.metaregion_sound_one_slot_changed(regions0, regions1, changed_idx);
438 } else {
439 if cont_entry.is_frame() {
440 cont_entry.frame_sub_pages_valid_preserved_at_own_slot(regions0, regions1);
441 }
442 }
443 }
444 };
445 }
446
447 pub proof fn take_next_remove_path_preserves_metaregion(
450 self,
451 owner_before_replace: Self,
452 regions0: MetaRegionOwners,
453 regions1: MetaRegionOwners,
454 removed_idx: int,
455 removed_path: TreePath<NR_ENTRIES>,
456 target: Mapping,
457 )
458 requires
459 self.inv(),
460 owner_before_replace.inv(),
461 owner_before_replace.in_locked_range(),
462 self.metaregion_sound(regions0),
463 regions0.inv(),
464 regions0.slot_owners.contains_key(removed_idx),
465 regions0.slots.contains_key(removed_idx),
466 regions0.slot_owners[removed_idx].usage !is PageTable,
467 self@.mappings == owner_before_replace@.mappings - PageTableOwner(
468 owner_before_replace.cur_subtree(),
469 )@.mappings,
470 PageTableOwner(owner_before_replace.cur_subtree())@.mappings == set![target],
471 owner_before_replace.cur_subtree().value().path == removed_path,
472 regions1.slots == regions0.slots,
473 regions1.slot_owners.dom() =~= regions0.slot_owners.dom(),
474 forall|i: int|
475 #![trigger regions1.slot_owners[i]]
476 i != removed_idx ==> regions0.slot_owners[i] == regions1.slot_owners[i],
477 regions1.slot_owners[removed_idx].inner_perms
478 == regions0.slot_owners[removed_idx].inner_perms,
479 regions1.slot_owners[removed_idx].slot_vaddr
480 == regions0.slot_owners[removed_idx].slot_vaddr,
481 regions1.slot_owners[removed_idx].usage == regions0.slot_owners[removed_idx].usage,
482 regions1.slot_owners[removed_idx].paths_in_pt
483 == regions0.slot_owners[removed_idx].paths_in_pt.remove(removed_path),
484 ensures
485 self.metaregion_sound(regions1),
486 {
487 self.no_node_at_idx_from_slot_key(regions0, removed_idx);
488
489 owner_before_replace.cur_subtree_eq_filtered_mappings_path();
490
491 let ghost sv = vaddr_of::<C>(removed_path) as int;
492 let ghost sz = page_size(owner_before_replace.level) as int;
493 assert(sz > 0) by {
494 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_ge_page_size(
495 owner_before_replace.level,
496 );
497 };
498 assert forall|mm: Mapping| #[trigger] self@.mappings.contains(mm) implies mm.va_range.start
499 != sv by {};
500
501 self.no_frame_with_path_from_no_view_mapping(removed_path);
502 self.path_removable_from_no_node_and_no_frame_path(removed_idx, removed_path);
503 self.metaregion_preserved_under_path_remove(regions0, regions1, removed_idx, removed_path);
504 }
505}
506
507}