1use vstd::prelude::*;
31use vstd_extra::ownership::*;
32
33use crate::specs::{
34 arch::*,
35 mm::{
36 frame::{mapping::*, meta_owners::PageUsage, meta_region_owners::MetaRegionOwners},
37 page_table::cursor::owners::CursorOwner,
38 },
39};
40
41use super::{frame::frame_drop_embedded, tracked_segment_entry_new, SegmentEntry};
42use crate::mm::{
43 frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED},
44 vm_space::UserPtConfig,
45 Paddr,
46};
47use core::ops::Range;
48
49verus! {
50
51pub axiom fn segment_from_unused_embedded(
71 tracked regions: &mut MetaRegionOwners,
72 range: Range<Paddr>,
73) -> (res: Option<()>)
74 requires
75 old(regions).inv(),
76 range.start % PAGE_SIZE == 0,
77 range.end % PAGE_SIZE == 0,
78 range.start < range.end,
79 range.end <= MAX_PADDR,
80 forall|paddr: Paddr|
83 #![trigger frame_to_index(paddr)]
84 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
85 ==> old(regions).slot_owner(paddr)
86 .ref_count() == REF_COUNT_UNUSED,
87 forall|paddr: Paddr|
88 #![trigger frame_to_index(paddr)]
89 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
90 ==> old(regions).contains(frame_to_index(paddr)),
91 ensures
92 final(regions).inv(),
93 final(regions).slots == old(regions).slots,
95 res is Some ==> forall|paddr: Paddr|
98 #![trigger frame_to_index(paddr)]
99 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
100 ==> {
101 let idx = frame_to_index(paddr);
102 let so = final(regions).slot_owners[idx];
103 &&& so.usage is Frame
104 &&& so.ref_count() == 1
105 &&& so.paths_in_pt.is_empty()
106 &&& so.in_list_perm.value() == 0
107 &&& so.storage_perm().is_init()
108 },
109 res is Some ==> forall|i: int|
111 #![trigger final(regions).slot_owners[i]]
112 i < max_meta_slots()
113 && !(range.start <= index_to_frame(i)
114 < range.end)
115 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
116 res is Some ==> forall|i: int|
121 #![trigger final(regions).slot_owners[i]]
122 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
123 regions,
124 ).slot_owners[i],
125 res is None ==> *final(regions) == *old(regions),
127 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
130 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
131;
132
133pub proof fn lemma_segment_drop_embedded(
150 tracked regions: &mut MetaRegionOwners,
151 range: Range<Paddr>,
152)
153 requires
154 old(regions).inv(),
155 range.start % PAGE_SIZE == 0,
156 range.end % PAGE_SIZE == 0,
157 range.start < range.end,
158 range.end <= MAX_PADDR,
159 forall|paddr: Paddr|
163 #![trigger frame_to_index(paddr)]
164 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
165 ==> {
166 let so = old(regions).slot_owner(paddr);
167 &&& so.ref_count() >= 1
168 &&& so.ref_count()
169 <= REF_COUNT_MAX
170 &&& so.usage is Frame
171 &&& so.ref_count() == 1
175 ==> so.paths_in_pt.is_empty()
176 },
177 ensures
178 final(regions).inv(),
179 final(regions).slots == old(regions).slots,
180 forall|paddr: Paddr|
183 #![trigger frame_to_index(paddr)]
184 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
185 ==> {
186 let idx = frame_to_index(paddr);
187 let so_old = old(regions).slot_owners[idx];
188 let so_new = final(regions).slot_owners[idx];
189 &&& so_new.usage == so_old.usage
190 &&& so_new.paths_in_pt == so_old.paths_in_pt
191 &&& so_new.slot_vaddr == so_old.slot_vaddr
192 &&& so_new.in_list_perm == so_old.in_list_perm
193 &&& so_old.ref_count() == 1
194 ==> so_new.ref_count() == REF_COUNT_UNUSED
195 &&& so_old.ref_count() > 1
196 ==> so_new.ref_count()
197 == (so_old.ref_count() - 1) as u64
198 },
199 forall|i: int|
201 #![trigger final(regions).slot_owners[i]]
202 i < max_meta_slots()
203 && !(range.start <= index_to_frame(i)
204 < range.end)
205 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
206 forall|i: int|
211 #![trigger final(regions).slot_owners[i]]
212 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
213 regions,
214 ).slot_owners[i],
215 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
216 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
217 decreases range.end - range.start,
218{
219 assert(regions.slot_owners.contains_key(frame_to_index(range.start)));
220 frame_drop_embedded(regions, range.start);
221
222 if range.start + PAGE_SIZE < range.end {
223 let ghost tail: Range<Paddr> = Range {
224 start: (range.start + PAGE_SIZE) as Paddr,
225 end: range.end,
226 };
227 lemma_segment_drop_embedded(regions, tail);
228 }
229}
230
231pub proof fn segment_next_embedded(
247 tracked regions: &mut MetaRegionOwners,
248 paddr: Paddr,
249)
250 requires
251 old(regions).inv(),
252 valid_frame_paddr(paddr),
253 old(regions).slot_owner(paddr)
254 .ref_count() >= 1,
255 old(regions).slot_owner(paddr)
256 .ref_count()
257 <= REF_COUNT_MAX,
258 old(regions).slot_owner(paddr).usage
259 is Frame,
260 ensures
261 final(regions).inv(),
262 final(regions).slots == old(regions).slots,
263 {
265 let idx = frame_to_index(paddr);
266 let so_old = old(regions).slot_owners[idx];
267 let so_new = final(regions).slot_owners[idx];
268 &&& so_new.ref_count_perm == so_old.ref_count_perm
269 &&& so_new.usage == so_old.usage
270 &&& so_new.slot_vaddr == so_old.slot_vaddr
271 &&& so_new.paths_in_pt == so_old.paths_in_pt
272 &&& so_new.in_list_perm == so_old.in_list_perm
273 &&& so_new.storage_perm() == so_old.storage_perm()
274 &&& so_new.vtable_ptr_perm() == so_old.vtable_ptr_perm()
275 },
276 forall|i: int| #![trigger final(regions).slot_owners[i]]
278 i != frame_to_index(paddr)
279 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
280 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
281 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
282{
283}
284
285pub(super) proof fn from_unused_step(
293 tracked regions: &mut MetaRegionOwners,
294 range: Range<Paddr>,
295) -> (tracked res: Option<SegmentEntry>)
296 requires
297 old(regions).inv(),
298 range.start % PAGE_SIZE == 0,
299 range.end % PAGE_SIZE == 0,
300 range.start < range.end,
301 range.end <= MAX_PADDR,
302 forall|paddr: Paddr|
303 #![trigger frame_to_index(paddr)]
304 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
305 ==> old(regions).slot_owner(paddr)
306 .ref_count() == REF_COUNT_UNUSED,
307 forall|paddr: Paddr|
308 #![trigger frame_to_index(paddr)]
309 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
310 ==> old(regions).contains(frame_to_index(paddr)),
311 ensures
312 final(regions).inv(),
313 final(regions).slots == old(regions).slots,
314 res matches Some(e) ==> e.range == range,
315 res is Some ==> forall|paddr: Paddr|
316 #![trigger frame_to_index(paddr)]
317 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
318 ==> {
319 let idx = frame_to_index(paddr);
320 let so = final(regions).slot_owners[idx];
321 &&& so.usage is Frame
322 &&& so.ref_count() == 1
323 &&& so.paths_in_pt.is_empty()
324 },
325 res is Some ==> forall|i: int|
326 #![trigger final(regions).slot_owners[i]]
327 i < max_meta_slots()
328 && !(range.start <= index_to_frame(i)
329 < range.end)
330 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
331 res is Some ==> forall|i: int|
333 #![trigger final(regions).slot_owners[i]]
334 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
335 regions,
336 ).slot_owners[i],
337 res is None ==> *final(regions) == *old(regions),
338 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
339 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
340{
341 let ghost outcome = segment_from_unused_embedded(regions, range);
342 match outcome {
343 Option::Some(()) => Option::Some(tracked_segment_entry_new(range)),
344 Option::None => Option::None,
345 }
346}
347
348pub(super) proof fn drop_step(
352 tracked regions: &mut MetaRegionOwners,
353 tracked entry: SegmentEntry,
354)
355 requires
356 old(regions).inv(),
357 entry.range.start % PAGE_SIZE == 0,
358 entry.range.end % PAGE_SIZE == 0,
359 entry.range.start < entry.range.end,
360 entry.range.end <= MAX_PADDR,
361 forall|paddr: Paddr|
362 #![trigger old(regions).slot_owner(paddr)]
363 (entry.range.start <= paddr < entry.range.end
364 && paddr % PAGE_SIZE == 0) ==> {
365 let so = old(regions).slot_owner(paddr);
366 &&& so.ref_count() >= 1
367 &&& so.ref_count()
368 <= REF_COUNT_MAX
369 &&& so.usage is Frame
370 &&& so.ref_count() == 1
371 ==> so.paths_in_pt.is_empty()
372 },
373 ensures
374 final(regions).inv(),
375 final(regions).slots == old(regions).slots,
376 forall|paddr: Paddr|
377 #![trigger frame_to_index(paddr)]
378 (entry.range.start <= paddr < entry.range.end
379 && paddr % PAGE_SIZE == 0) ==> {
380 let idx = frame_to_index(paddr);
381 let so_old = old(regions).slot_owners[idx];
382 let so_new = final(regions).slot_owners[idx];
383 &&& so_new.usage == so_old.usage
384 &&& so_new.paths_in_pt == so_old.paths_in_pt
385 &&& so_new.slot_vaddr == so_old.slot_vaddr
386 &&& so_new.in_list_perm == so_old.in_list_perm
387 &&& so_old.ref_count() == 1
388 ==> so_new.ref_count() == REF_COUNT_UNUSED
389 &&& so_old.ref_count() > 1
390 ==> so_new.ref_count()
391 == (so_old.ref_count() - 1) as u64
392 },
393 forall|i: int|
394 #![trigger final(regions).slot_owners[i]]
395 i < max_meta_slots()
396 && !(entry.range.start <= index_to_frame(i)
397 < entry.range.end)
398 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
399 forall|i: int|
401 #![trigger final(regions).slot_owners[i]]
402 !old(regions).slots.contains_key(i) ==> final(regions).slot_owners[i] == old(
403 regions,
404 ).slot_owners[i],
405 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
406 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
407{
408 lemma_segment_drop_embedded(regions, entry.range);
409}
410
411pub axiom fn segment_clone_embedded(
412 tracked regions: &mut MetaRegionOwners,
413 range: Range<Paddr>,
414)
415 requires
416 old(regions).inv(),
417 range.start % PAGE_SIZE == 0,
418 range.end % PAGE_SIZE == 0,
419 range.start < range.end,
420 range.end <= MAX_PADDR,
421 forall|paddr: Paddr|
424 #![trigger frame_to_index(paddr)]
425 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
426 ==> {
427 let so = old(regions).slot_owner(paddr);
428 &&& so.usage is Frame
429 &&& so.ref_count() >= 1
430 &&& so.ref_count() + 1 <= REF_COUNT_MAX
431 },
432 ensures
433 final(regions).inv(),
434 final(regions).slots =~= old(regions).slots,
435 forall|paddr: Paddr|
437 #![trigger frame_to_index(paddr)]
438 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
439 ==> {
440 let idx = frame_to_index(paddr);
441 let so_old = old(regions).slot_owners[idx];
442 let so_new = final(regions).slot_owners[idx];
443 &&& so_new.ref_count()
444 == (so_old.ref_count() + 1) as u64
445 &&& so_new.usage == so_old.usage
446 &&& so_new.slot_vaddr == so_old.slot_vaddr
447 &&& so_new.paths_in_pt == so_old.paths_in_pt
448 &&& so_new.in_list_perm == so_old.in_list_perm
449 &&& so_new.storage_perm() == so_old.storage_perm()
450 &&& so_new.vtable_ptr_perm() == so_old.vtable_ptr_perm()
451 },
452 forall|i: int|
454 #![trigger final(regions).slot_owners[i]]
455 i < max_meta_slots()
456 && !(range.start <= index_to_frame(i)
457 < range.end)
458 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
459 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
460 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
461;
462
463}