1use vstd::prelude::*;
32use vstd_extra::ownership::*;
33
34use crate::specs::{
35 arch::*,
36 mm::{
37 frame::{
38 mapping::{frame_to_index, index_to_frame, max_meta_slots},
39 meta_owners::PageUsage,
40 meta_region_owners::MetaRegionOwners,
41 },
42 page_table::cursor::owners::CursorOwner,
43 },
44};
45
46use super::{frame::frame_drop_embedded, tracked_segment_entry_new, SegmentEntry};
47use crate::mm::{
48 frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
49 vm_space::UserPtConfig,
50 Paddr,
51};
52use core::ops::Range;
53
54verus! {
55
56pub axiom fn segment_from_unused_embedded(
76 tracked regions: &mut MetaRegionOwners,
77 range: Range<Paddr>,
78) -> (res: Option<()>)
79 requires
80 old(regions).inv(),
81 range.start % PAGE_SIZE == 0,
82 range.end % PAGE_SIZE == 0,
83 range.start < range.end,
84 range.end <= MAX_PADDR,
85 forall|paddr: Paddr|
88 #![trigger frame_to_index(paddr)]
89 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
90 ==> old(regions).slot_owner(paddr)
91 .ref_count() == REF_COUNT_UNUSED,
92 forall|paddr: Paddr|
93 #![trigger frame_to_index(paddr)]
94 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
95 ==> old(regions).contains(frame_to_index(paddr)),
96 ensures
97 final(regions).inv(),
98 final(regions).slots == old(regions).slots,
100 res is Some ==> forall|paddr: Paddr|
103 #![trigger frame_to_index(paddr)]
104 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
105 ==> {
106 let idx = frame_to_index(paddr);
107 let so = final(regions).slot_owners[idx];
108 &&& so.usage is Frame
109 &&& so.ref_count() == 1
110 &&& so.paths_in_pt.is_empty()
111 &&& so.in_list_perm.value() == 0
112 &&& so.storage_perm().is_init()
113 },
114 res is Some ==> forall|i: int|
116 #![trigger final(regions).slot_owners[i]]
117 i < max_meta_slots()
118 && !(range.start <= index_to_frame(i)
119 < range.end)
120 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
121 res is Some ==> forall|i: int|
126 #![trigger final(regions).slot_owners[i]]
127 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
128 regions,
129 ).slot_owners[i],
130 res is None ==> *final(regions) == *old(regions),
132 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
135 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
136;
137
138pub proof fn lemma_segment_drop_embedded(
155 tracked regions: &mut MetaRegionOwners,
156 range: Range<Paddr>,
157)
158 requires
159 old(regions).inv(),
160 range.start % PAGE_SIZE == 0,
161 range.end % PAGE_SIZE == 0,
162 range.start < range.end,
163 range.end <= MAX_PADDR,
164 forall|paddr: Paddr|
168 #![trigger frame_to_index(paddr)]
169 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
170 ==> {
171 let so = old(regions).slot_owner(paddr);
172 &&& so.ref_count() >= 1
173 &&& so.ref_count()
174 <= REF_COUNT_MAX
175 &&& so.usage is Frame
176 &&& so.ref_count() == 1
180 ==> so.paths_in_pt.is_empty()
181 },
182 ensures
183 final(regions).inv(),
184 final(regions).slots == old(regions).slots,
185 forall|paddr: Paddr|
188 #![trigger frame_to_index(paddr)]
189 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
190 ==> {
191 let idx = frame_to_index(paddr);
192 let so_old = old(regions).slot_owners[idx];
193 let so_new = final(regions).slot_owners[idx];
194 &&& so_new.usage == so_old.usage
195 &&& so_new.paths_in_pt == so_old.paths_in_pt
196 &&& so_new.slot_vaddr == so_old.slot_vaddr
197 &&& so_new.in_list_perm == so_old.in_list_perm
198 &&& so_old.ref_count() == 1
199 ==> so_new.ref_count() == REF_COUNT_UNUSED
200 &&& so_old.ref_count() > 1
201 ==> so_new.ref_count()
202 == (so_old.ref_count() - 1) as u64
203 },
204 forall|i: int|
206 #![trigger final(regions).slot_owners[i]]
207 i < max_meta_slots()
208 && !(range.start <= index_to_frame(i)
209 < range.end)
210 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
211 forall|i: int|
216 #![trigger final(regions).slot_owners[i]]
217 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
218 regions,
219 ).slot_owners[i],
220 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
221 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
222 decreases range.end - range.start,
223{
224 assert(regions.slot_owners.contains_key(frame_to_index(range.start)));
225 frame_drop_embedded(regions, range.start);
226
227 if range.start + PAGE_SIZE < range.end {
228 let ghost tail: Range<Paddr> = Range {
229 start: (range.start + PAGE_SIZE) as Paddr,
230 end: range.end,
231 };
232 lemma_segment_drop_embedded(regions, tail);
233 }
234}
235
236pub proof fn segment_next_embedded(
252 tracked regions: &mut MetaRegionOwners,
253 paddr: Paddr,
254)
255 requires
256 old(regions).inv(),
257 valid_frame_paddr(paddr),
258 old(regions).contains(frame_to_index(paddr)),
259 old(regions).slot_owner(paddr)
260 .ref_count() >= 1,
261 old(regions).slot_owner(paddr)
262 .ref_count()
263 <= REF_COUNT_MAX,
264 old(regions).slot_owner(paddr).usage
265 is Frame,
266 ensures
267 final(regions).inv(),
268 final(regions).slots == old(regions).slots,
269 {
271 let idx = frame_to_index(paddr);
272 let so_old = old(regions).slot_owners[idx];
273 let so_new = final(regions).slot_owners[idx];
274 &&& so_new.ref_count_perm == so_old.ref_count_perm
275 &&& so_new.usage == so_old.usage
276 &&& so_new.slot_vaddr == so_old.slot_vaddr
277 &&& so_new.paths_in_pt == so_old.paths_in_pt
278 &&& so_new.in_list_perm == so_old.in_list_perm
279 &&& so_new.storage_perm() == so_old.storage_perm()
280 &&& so_new.vtable_ptr_perm() == so_old.vtable_ptr_perm()
281 },
282 forall|i: int| #![trigger final(regions).slot_owners[i]]
284 i != frame_to_index(paddr)
285 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
286 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
287 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
288{
289}
290
291pub(super) proof fn from_unused_step(
299 tracked regions: &mut MetaRegionOwners,
300 range: Range<Paddr>,
301) -> (tracked res: Option<SegmentEntry>)
302 requires
303 old(regions).inv(),
304 range.start % PAGE_SIZE == 0,
305 range.end % PAGE_SIZE == 0,
306 range.start < range.end,
307 range.end <= MAX_PADDR,
308 forall|paddr: Paddr|
309 #![trigger frame_to_index(paddr)]
310 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
311 ==> old(regions).slot_owner(paddr)
312 .ref_count() == REF_COUNT_UNUSED,
313 forall|paddr: Paddr|
314 #![trigger frame_to_index(paddr)]
315 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
316 ==> old(regions).contains(frame_to_index(paddr)),
317 ensures
318 final(regions).inv(),
319 final(regions).slots == old(regions).slots,
320 res matches Some(e) ==> e.range == range,
321 res is Some ==> forall|paddr: Paddr|
322 #![trigger frame_to_index(paddr)]
323 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
324 ==> {
325 let idx = frame_to_index(paddr);
326 let so = final(regions).slot_owners[idx];
327 &&& so.usage is Frame
328 &&& so.ref_count() == 1
329 &&& so.paths_in_pt.is_empty()
330 },
331 res is Some ==> forall|i: int|
332 #![trigger final(regions).slot_owners[i]]
333 i < max_meta_slots()
334 && !(range.start <= index_to_frame(i)
335 < range.end)
336 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
337 res is Some ==> forall|i: int|
339 #![trigger final(regions).slot_owners[i]]
340 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
341 regions,
342 ).slot_owners[i],
343 res is None ==> *final(regions) == *old(regions),
344 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
345 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
346{
347 let ghost outcome = segment_from_unused_embedded(regions, range);
348 match outcome {
349 Option::Some(()) => Option::Some(tracked_segment_entry_new(range)),
350 Option::None => Option::None,
351 }
352}
353
354pub(super) proof fn drop_step(
358 tracked regions: &mut MetaRegionOwners,
359 tracked entry: SegmentEntry,
360)
361 requires
362 old(regions).inv(),
363 entry.range.start % PAGE_SIZE == 0,
364 entry.range.end % PAGE_SIZE == 0,
365 entry.range.start < entry.range.end,
366 entry.range.end <= MAX_PADDR,
367 forall|paddr: Paddr|
368 #![trigger old(regions).slot_owner(paddr)]
369 (entry.range.start <= paddr < entry.range.end
370 && paddr % PAGE_SIZE == 0) ==> {
371 let so = old(regions).slot_owner(paddr);
372 &&& so.ref_count() >= 1
373 &&& so.ref_count()
374 <= REF_COUNT_MAX
375 &&& so.usage is Frame
376 &&& so.ref_count() == 1
377 ==> so.paths_in_pt.is_empty()
378 },
379 ensures
380 final(regions).inv(),
381 final(regions).slots == old(regions).slots,
382 forall|paddr: Paddr|
383 #![trigger frame_to_index(paddr)]
384 (entry.range.start <= paddr < entry.range.end
385 && paddr % PAGE_SIZE == 0) ==> {
386 let idx = frame_to_index(paddr);
387 let so_old = old(regions).slot_owners[idx];
388 let so_new = final(regions).slot_owners[idx];
389 &&& so_new.usage == so_old.usage
390 &&& so_new.paths_in_pt == so_old.paths_in_pt
391 &&& so_new.slot_vaddr == so_old.slot_vaddr
392 &&& so_new.in_list_perm == so_old.in_list_perm
393 &&& so_old.ref_count() == 1
394 ==> so_new.ref_count() == REF_COUNT_UNUSED
395 &&& so_old.ref_count() > 1
396 ==> so_new.ref_count()
397 == (so_old.ref_count() - 1) as u64
398 },
399 forall|i: int|
400 #![trigger final(regions).slot_owners[i]]
401 i < max_meta_slots()
402 && !(entry.range.start <= index_to_frame(i)
403 < entry.range.end)
404 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
405 forall|i: int|
407 #![trigger final(regions).slot_owners[i]]
408 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
409 regions,
410 ).slot_owners[i],
411 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
412 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
413{
414 lemma_segment_drop_embedded(regions, entry.range);
415}
416
417pub axiom fn segment_clone_embedded(
418 tracked regions: &mut MetaRegionOwners,
419 range: Range<Paddr>,
420)
421 requires
422 old(regions).inv(),
423 range.start % PAGE_SIZE == 0,
424 range.end % PAGE_SIZE == 0,
425 range.start < range.end,
426 range.end <= MAX_PADDR,
427 forall|paddr: Paddr|
430 #![trigger frame_to_index(paddr)]
431 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
432 ==> {
433 let so = old(regions).slot_owner(paddr);
434 &&& so.usage is Frame
435 &&& so.ref_count() >= 1
436 &&& so.ref_count() + 1 <= REF_COUNT_MAX
437 },
438 ensures
439 final(regions).inv(),
440 final(regions).slots =~= old(regions).slots,
441 forall|paddr: Paddr|
443 #![trigger frame_to_index(paddr)]
444 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
445 ==> {
446 let idx = frame_to_index(paddr);
447 let so_old = old(regions).slot_owners[idx];
448 let so_new = final(regions).slot_owners[idx];
449 &&& so_new.ref_count()
450 == (so_old.ref_count() + 1) as u64
451 &&& so_new.usage == so_old.usage
452 &&& so_new.slot_vaddr == so_old.slot_vaddr
453 &&& so_new.paths_in_pt == so_old.paths_in_pt
454 &&& so_new.in_list_perm == so_old.in_list_perm
455 &&& so_new.storage_perm() == so_old.storage_perm()
456 &&& so_new.vtable_ptr_perm() == so_old.vtable_ptr_perm()
457 },
458 forall|i: int|
460 #![trigger final(regions).slot_owners[i]]
461 i < max_meta_slots()
462 && !(range.start <= index_to_frame(i)
463 < range.end)
464 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
465 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
466 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
467;
468
469}