1use vstd::modes::tracked_swap;
4use vstd::prelude::*;
5use vstd::proph::ProphecyGhost;
6
7use vstd::std_specs::iter::{IteratorSpec, IteratorSpecImpl};
8use vstd_extra::assert;
9use vstd_extra::cast_ptr::*;
10use vstd_extra::drop_tracking::*;
11use vstd_extra::ownership::*;
12use vstd_extra::panic::may_panic;
13use vstd_extra::prelude::*;
14
15use crate::mm::page_table::RCClone;
16use crate::mm::{PagingLevel, Vaddr, frame::MetaSlot, paddr_to_vaddr};
17use crate::specs::arch::*;
18use crate::specs::mm::frame::{
19 mapping::{frame_to_index, group_page_meta, meta_addr},
20 meta_owners::*,
21 meta_region_owners::MetaRegionOwners,
22 segment::*,
23};
24
25use core::{fmt::Debug, ops::Range};
26
27use super::{
28 Frame, Paddr,
29 meta::mapping::frame_to_meta,
30 meta::{AnyFrameMeta, GetFrameError},
31};
32use crate::mm::frame::{meta::REF_COUNT_MAX, untyped::AnyUFrameMeta};
33
34verus! {
35
36#[repr(transparent)]
50pub struct Segment<M: AnyFrameMeta + ?Sized> {
51 pub range: Range<Paddr>,
53 pub _marker: core::marker::PhantomData<M>,
54}
55
56pub type USegment = Segment<dyn AnyUFrameMeta>;
82
83impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> RCClone for Segment<M> {
99 open spec fn clone_requires(self, perm: MetaRegionOwners) -> bool {
100 &&& self.inv()
101 &&& perm.inv()
102 &&& forall|pa: Paddr|
103 #![trigger frame_to_index(pa)]
104 (self.start_paddr() <= pa < self.end_paddr() && pa % PAGE_SIZE == 0) ==> {
105 let idx = frame_to_index(pa);
106 &&& perm.slots.contains_key(idx)
107 &&& has_safe_slot(pa)
108 &&& perm.slot_owners[idx].inner_perms.ref_count.value() > 0
109 &&& perm.slot_owners[idx].inner_perms.ref_count.value() + 1
110 < super::meta::REF_COUNT_MAX
111 &&& !MetaSlot::inc_ref_count_panic_cond(perm.slot_owners[idx].inner_perms.ref_count)
112 }
113 }
114
115 open spec fn clone_ensures(
116 self,
117 old_perm: MetaRegionOwners,
118 new_perm: MetaRegionOwners,
119 res: Self,
120 ) -> bool {
121 &&& res.range() == self.range()
122 &&& res.inv()
123 &&& new_perm.inv()
124 &&& new_perm.frame_obligations =~= old_perm.frame_obligations
129 }
130
131 #[verifier::loop_isolation(false)]
132 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self) {
133 let mut paddr = self.range.start;
134
135 loop
136 invariant
137 perm.inv(),
138 self.inv(),
139 perm.slots == old(perm).slots,
140 perm.slot_owners.dom() == old(perm).slot_owners.dom(),
141 perm.frame_obligations == old(perm).frame_obligations,
142 self.range.start <= paddr <= self.range.end,
143 paddr % PAGE_SIZE == 0,
144 paddr <= MAX_PADDR,
145 forall|pa: Paddr|
146 #![trigger frame_to_index(pa)]
147 (paddr <= pa < self.range.end && pa % PAGE_SIZE == 0) ==> {
148 let idx = frame_to_index(pa);
149 &&& perm.slots.contains_key(idx)
150 &&& has_safe_slot(pa)
151 &&& perm.slot_owners[idx].inner_perms.ref_count.value() > 0
152 &&& perm.slot_owners[idx].inner_perms.ref_count.value() + 1
153 < super::meta::REF_COUNT_MAX
154 &&& !MetaSlot::inc_ref_count_panic_cond(
155 perm.slot_owners[idx].inner_perms.ref_count,
156 )
157 },
158 decreases self.range.end - paddr,
159 {
160 if paddr >= self.range.end {
161 break;
162 }
163 unsafe {
164 #[verus_spec(with Tracked(perm))]
165 crate::mm::frame::inc_frame_ref_count(paddr)
166 };
167
168 paddr = paddr + PAGE_SIZE;
169 }
170
171 Self { range: self.range.start..self.range.end, _marker: core::marker::PhantomData }
172 }
173}
174
175#[verus_verify]
176impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
177 #[verus_spec(r =>
208 with
209 Tracked(regions): Tracked<&mut MetaRegionOwners>,
210 -> owner: Tracked<Option<SegmentOwner<M>>>,
211 requires
212 old(regions).inv(),
213 forall|paddr_in: Paddr|
214 (range.start <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0) ==> {
215 &&& metadata_fn.requires((paddr_in,))
216 },
217 forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
218 metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> paddr_in == paddr_out,
219 !(range.end <= MAX_PADDR ==> range.start < range.end) ==> may_panic(),
220 ensures
221 final(regions).inv(),
222 r is Err ==> final(regions).frame_obligations == old(regions).frame_obligations,
223 (range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0)
224 ==> r == Err::<Self, _>(GetFrameError::NotAligned),
225 (range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0 && range.end > MAX_PADDR)
226 ==> r == Err::<Self, _>(GetFrameError::OutOfBound),
227 r matches Ok(seg) ==> {
228 &&& seg.start_paddr() == range.start
229 &&& seg.end_paddr() == range.end
230 &&& seg.start_paddr() < seg.end_paddr()
231 &&& crate::specs::mm::frame::segment::seg_obligations_minted(
232 *old(regions),
233 *final(regions),
234 range.start,
235 crate::specs::mm::frame::segment::seg_nframes(range),
236 )
237 &&& owner@ matches Some(owner) && {
238 &&& seg.inv()
239 &&& seg.wf(&owner)
240 }
241 &&& forall|paddr: Paddr|
242 #![trigger frame_to_index(paddr)]
243 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
244 ==> final(regions).slots.contains_key(frame_to_index(paddr))
245 &&& range.start < range.end <= MAX_PADDR
246 },
247 )]
248 pub fn from_unused(range: Range<Paddr>, metadata_fn: impl Fn(Paddr) -> (Paddr, M)) -> (res:
249 Result<Self, GetFrameError>) {
250 proof_decl! {
251 let tracked mut owner: Option<SegmentOwner<M>> = None;
252 let tracked mut addrs = Seq::<usize>::tracked_empty();
253 }
254
255 if range.start % PAGE_SIZE != 0 || range.end % PAGE_SIZE != 0 {
256 return {
257 proof_with!(|= Tracked(owner));
258 Err(GetFrameError::NotAligned)
259 };
260 }
261 if range.end > MAX_PADDR {
262 return {
263 proof_with!(|= Tracked(owner));
264 Err(GetFrameError::OutOfBound)
265 };
266 }
267 assert!(range.start < range.end);
268
269 let mut segment = Self {
270 range: range.start..range.start,
271 _marker: core::marker::PhantomData,
272 };
273
274 let mut i = 0;
275 let addr_len = (range.end - range.start) / PAGE_SIZE;
276
277 while i < addr_len
278 invariant
279 i <= addr_len,
280 i == addrs.len(),
281 range.start % PAGE_SIZE == 0,
282 range.end % PAGE_SIZE == 0,
283 range.end <= MAX_PADDR,
284 range.start <= range.start + i * PAGE_SIZE <= range.end,
285 range.end == range.start + addr_len * PAGE_SIZE,
286 addr_len == (range.end - range.start) / PAGE_SIZE as int,
287 i <= addr_len,
288 forall|paddr_in: Paddr|
289 (range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE
290 == 0) ==> {
291 &&& metadata_fn.requires((paddr_in,))
292 },
293 forall|paddr_in: Paddr, paddr_out: Paddr, m: M|
294 range.start + i * PAGE_SIZE <= paddr_in < range.end && paddr_in % PAGE_SIZE == 0
295 && metadata_fn.ensures((paddr_in,), (paddr_out, m)) ==> paddr_in
296 == paddr_out,
297 forall|j: int|
298 #![trigger addrs[j]]
299 0 <= j < addrs.len() ==> {
300 let idx = frame_to_index(addrs[j]);
301 &&& regions.slots.contains_key(idx)
302 &&& regions.slot_owners.contains_key(idx)
303 &&& regions.slot_owners[idx].slot_vaddr == meta_addr(idx)
304 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
305 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
306 <= crate::mm::frame::meta::REF_COUNT_MAX
307 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
308 &&& addrs[j] % PAGE_SIZE == 0
309 &&& addrs[j] < MAX_PADDR
310 &&& addrs[j] == range.start + (j as u64) * PAGE_SIZE
311 },
312 regions.inv(),
313 regions.frame_obligations == old(regions).frame_obligations,
314 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
315 segment.range.start == range.start,
316 segment.range.end == range.start + i * PAGE_SIZE,
317 ensures
318 i == addr_len,
319 decreases addr_len - i,
320 {
321 let paddr_in = range.start + i * PAGE_SIZE;
322 let (paddr, meta) = metadata_fn(paddr_in);
323
324 let ghost regions_pre = *regions;
325 let res = #[verus_spec(with Tracked(regions))]
326 Frame::<M>::from_unused(paddr, meta);
327 let frame = match res {
328 Ok(f) => f,
329 Err(e) => {
330 let mut p = range.start;
331 let ghost mut k: int = 0;
332 while p < segment.range.end
333 invariant
334 regions.inv(),
335 regions.frame_obligations == old(regions).frame_obligations,
336 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
337 range.start % PAGE_SIZE == 0,
338 i == addrs.len(),
339 segment.range.end == range.start + i * PAGE_SIZE,
340 segment.range.end <= MAX_PADDR,
341 range.start <= p <= segment.range.end,
342 p == range.start + k * PAGE_SIZE,
343 p % PAGE_SIZE == 0,
344 0 <= k <= i,
345 forall|j: int|
346 #![trigger addrs[j]]
347 k <= j < addrs.len() ==> {
348 let idx = frame_to_index(addrs[j]);
349 &&& regions.slots.contains_key(idx)
350 &&& regions.slot_owners.contains_key(idx)
351 &&& regions.slot_owners[idx].slot_vaddr == meta_addr(idx)
352 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
353 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
354 <= crate::mm::frame::meta::REF_COUNT_MAX
355 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
356 &&& addrs[j] % PAGE_SIZE == 0
357 &&& addrs[j] < MAX_PADDR
358 &&& addrs[j] == range.start + (j as u64) * PAGE_SIZE
359 },
360 decreases segment.range.end - p,
361 {
362 let ghost reclaim_pre = *regions;
363 let ghost idx_k = frame_to_index(p);
364 proof {
365 broadcast use group_page_meta;
366
367 assert(addrs[k] == p);
368 assert(meta_addr(idx_k) == frame_to_meta(p));
369 assert(regions.slots.contains_key(idx_k));
370 }
371 proof_decl! {
372 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<
373 usize,
374 >;
375 }
376 let frame = unsafe {
377 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
378 Frame::<M>::from_raw(p)
379 };
380 frame.drop(Tracked(regions), Tracked(from_raw_obl));
381 proof {
382 assert forall|j: int|
383 #![trigger addrs[j]]
384 (k + 1) <= j < addrs.len() implies ({
385 let idx = frame_to_index(addrs[j]);
386 &&& regions.slots.contains_key(idx)
387 &&& regions.slot_owners.contains_key(idx)
388 &&& regions.slot_owners[idx] == reclaim_pre.slot_owners[idx]
389 }) by {
390 assert(addrs[j] != p);
391 crate::specs::mm::frame::mapping::lemma_frame_to_index_injective(
392 addrs[j],
393 p,
394 );
395 };
396 }
397 p = p + PAGE_SIZE;
398 proof {
399 k = k + 1;
400 }
401 }
402 return {
403 proof_with!(|= Tracked(owner));
404 Err(e)
405 };
406 },
407 };
408
409 let _ = ManuallyDrop::new(frame, Tracked(regions));
410 segment.range.end = paddr + PAGE_SIZE;
411 proof {
412 broadcast use group_page_meta;
413
414 regions.inv_implies_correct_addr(paddr);
415 let idx = frame_to_index(paddr);
416 axiom_mmio_usage_iff_mmio_paddr(regions.slot_owners[idx]);
417 axiom_mmio_usage_iff_mmio_paddr(regions_pre.slot_owners[idx]);
418 assert(regions_pre.slot_owners[idx].paths_in_pt.is_empty());
419 assert(regions.slot_owners[idx].paths_in_pt
420 == regions_pre.slot_owners[idx].paths_in_pt);
421 assert(regions.frame_obligations == regions_pre.frame_obligations);
422 addrs.tracked_push(paddr);
423 }
424
425 i += 1;
426 }
427
428 proof {
429 assert(regions.frame_obligations == old(regions).frame_obligations);
439 crate::specs::mm::frame::segment::tracked_mint_seg_obligations(
440 regions,
441 range.start,
442 addr_len as int,
443 );
444 owner = Some(SegmentOwner { range, _marker: core::marker::PhantomData });
445
446 assert forall|addr: usize|
447 #![trigger frame_to_index(addr)]
448 range.start <= addr < range.end && addr % PAGE_SIZE == 0 implies {
449 regions.slots.contains_key(frame_to_index(addr))
450 } by {
451 let j = (addr - range.start) / PAGE_SIZE as int;
452 assert(addrs[j as int] == addr);
453 }
454 }
455
456 proof_with!(|= Tracked(owner));
457 Ok(segment)
458 }
459
460 #[verus_spec(r =>
483 with
484 Tracked(regions): Tracked<&mut MetaRegionOwners>,
485 Tracked(owner): Tracked<SegmentOwner<M>>,
486 requires
487 old(regions).inv(),
488 owner.inv(),
489 range == owner.range,
490 owner.relate_regions(*old(regions)),
491 ensures
492 r.range() == range,
493 r.inv(),
494 r.wf(&owner),
495 final(regions).inv(),
496 *final(regions) == *old(regions),
497 )]
498 pub(crate) unsafe fn from_raw(range: Range<Paddr>) -> Self {
499 Self { range, _marker: core::marker::PhantomData }
500 }
501}
502
503#[verus_verify]
504impl<M: AnyFrameMeta + ?Sized> Segment<M> {
505 #[verus_verify(dual_spec)]
507 #[verus_spec(
508 returns
509 self.start_paddr(),
510 )]
511 pub fn start_paddr(&self) -> Paddr {
512 self.range.start
513 }
514
515 #[verus_verify(dual_spec)]
517 #[verus_spec(
518 returns
519 self.end_paddr(),
520 )]
521 pub fn end_paddr(&self) -> Paddr {
522 self.range.end
523 }
524
525 #[verus_verify(dual_spec)]
527 #[verus_spec(r =>
528 requires
529 self.inv(),
530 ensures
531 r == self.end_paddr() - self.start_paddr(),
532 returns
533 self.size()
534 )]
535 pub fn size(&self) -> usize {
536 self.range.end - self.range.start
537 }
538
539 pub open spec fn range(&self) -> Range<Paddr> {
540 self.start_paddr()..self.end_paddr()
541 }
542}
543
544#[verus_verify]
545impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Segment<M> {
546 #[verus_spec(r =>
564 with
565 Tracked(owner): Tracked<SegmentOwner<M>>,
566 Tracked(regions): Tracked<&mut MetaRegionOwners>,
567 -> result_owners: (Tracked<SegmentOwner<M>>, Tracked<SegmentOwner<M>>),
568 requires
569 self.invariants(&owner, *old(regions)),
570 offset % PAGE_SIZE != 0 ==> may_panic(),
571 !(0 < offset && offset < self.size()) ==> may_panic(),
572 ensures
573 final(regions).slots == old(regions).slots,
574 final(regions).slot_owners == old(regions).slot_owners,
575 final(regions).frame_obligations == old(regions).frame_obligations,
576 (r.0, r.1) == self.split_spec(offset),
577 r.0.invariants(&result_owners.0@, *final(regions)),
578 r.1.invariants(&result_owners.1@, *final(regions)),
579 )]
580 #[verifier::spinoff_prover]
581 pub fn split(self, offset: usize) -> (Self, Self) {
582 assert!(offset % PAGE_SIZE == 0);
583 assert!(0 < offset && offset < self.size());
584
585 let ghost old_regions = *regions;
586
587 let old = ManuallyDrop::new(self, Tracked(regions));
588 let at = old.range.start + offset;
589
590 let ghost old_start = old@.start_paddr();
591 let ghost old_end = old@.end_paddr();
592
593 let tracked frame_own1 = SegmentOwner {
594 range: old_start..at,
595 _marker: core::marker::PhantomData,
596 };
597 let tracked frame_own2 = SegmentOwner {
598 range: at..old_end,
599 _marker: core::marker::PhantomData,
600 };
601 proof {
602 assert forall|i: int|
603 #![trigger frame_to_index((frame_own1.range.start + i * PAGE_SIZE) as usize)]
604 0 <= i < crate::specs::mm::frame::segment::seg_nframes(frame_own1.range) implies {
605 let idx = frame_to_index((frame_own1.range.start + i * PAGE_SIZE) as usize);
606 &&& regions.frame_obligations.count(idx) >= 1
607 &&& regions.slot_owners.contains_key(idx)
608 &&& regions.slots.contains_key(idx)
609 &&& regions.slot_owners[idx].slot_vaddr == meta_addr(idx)
610 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
611 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
612 <= crate::mm::frame::meta::REF_COUNT_MAX
613 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
614 &&& regions.slot_owners[idx].usage is Frame
615 } by {
616 owner.relate_regions_at(old_regions, i);
617 }
618 assert forall|i: int|
619 #![trigger frame_to_index((frame_own2.range.start + i * PAGE_SIZE) as usize)]
620 0 <= i < crate::specs::mm::frame::segment::seg_nframes(frame_own2.range) implies {
621 let idx = frame_to_index((frame_own2.range.start + i * PAGE_SIZE) as usize);
622 &&& regions.frame_obligations.count(idx) >= 1
623 &&& regions.slot_owners.contains_key(idx)
624 &&& regions.slots.contains_key(idx)
625 &&& regions.slot_owners[idx].slot_vaddr == meta_addr(idx)
626 &&& regions.slot_owners[idx].inner_perms.ref_count.value() > 0
627 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
628 <= crate::mm::frame::meta::REF_COUNT_MAX
629 &&& regions.slot_owners[idx].paths_in_pt.is_empty()
630 &&& regions.slot_owners[idx].usage is Frame
631 } by {
632 owner.relate_regions_at(old_regions, i + (offset / PAGE_SIZE));
633 }
634
635 assert forall|i: int, j: int|
636 #![trigger frame_to_index((frame_own1.range.start + i * PAGE_SIZE) as usize),
637 frame_to_index((frame_own1.range.start + j * PAGE_SIZE) as usize)]
638 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
639 frame_own1.range,
640 ) implies frame_to_index((frame_own1.range.start + i * PAGE_SIZE) as usize)
641 != frame_to_index((frame_own1.range.start + j * PAGE_SIZE) as usize) by {
642 owner.relate_regions_distinct(old_regions, i, j);
643 }
644 assert forall|i: int, j: int|
645 #![trigger frame_to_index((frame_own2.range.start + i * PAGE_SIZE) as usize),
646 frame_to_index((frame_own2.range.start + j * PAGE_SIZE) as usize)]
647 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
648 frame_own2.range,
649 ) implies frame_to_index((frame_own2.range.start + i * PAGE_SIZE) as usize)
650 != frame_to_index((frame_own2.range.start + j * PAGE_SIZE) as usize) by {
651 owner.relate_regions_distinct(
652 old_regions,
653 i + (offset / PAGE_SIZE) as int,
654 j + (offset / PAGE_SIZE),
655 );
656 }
657 }
658 proof_with!(|= (Tracked(frame_own1), Tracked(frame_own2)));
659 (
660 Self { range: old.range.start..at, _marker: core::marker::PhantomData },
661 Self { range: at..old.range.end, _marker: core::marker::PhantomData },
662 )
663 }
664
665 pub open spec fn page_in_range_saturated(
675 self,
676 range: &Range<usize>,
677 regions: MetaRegionOwners,
678 ) -> bool {
679 exists|j: int|
680 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
681 (range.start as int) / (PAGE_SIZE as int) <= j < (range.end as int) / (PAGE_SIZE as int)
682 && regions.slot_owners[frame_to_index(
683 (self.start_paddr() + j * PAGE_SIZE) as usize,
684 )].inner_perms.ref_count.value() >= REF_COUNT_MAX
685 }
686
687 #[verus_spec(r =>
703 with
704 Tracked(owner): Tracked<&SegmentOwner<M>>,
705 Tracked(regions): Tracked<&mut MetaRegionOwners>,
706 requires
707 self.invariants(owner, *old(regions)),
708 range.start % PAGE_SIZE != 0 ==> may_panic(),
709 range.end % PAGE_SIZE != 0 ==> may_panic(),
710 range.start > range.end ==> may_panic(),
711 self.range.start + range.end > self.range.end ==> may_panic(),
712 self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
713 ensures
714 range.start % PAGE_SIZE == 0,
715 range.end % PAGE_SIZE == 0,
716 range.start <= range.end,
717 self.range.start + range.end <= self.range.end,
718 !self.page_in_range_saturated(range, *old(regions)),
719 r.inv(),
720 r.start_paddr() == self.start_paddr() + range.start,
721 r.end_paddr() == self.start_paddr() + range.end,
722 r.end_paddr() <= self.end_paddr(),
723 final(regions).inv(),
724 final(regions).slots == old(regions).slots,
725 final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
726 final(regions).frame_obligations == old(regions).frame_obligations,
727 )]
728 #[verifier::spinoff_prover]
729 #[verifier::loop_isolation(false)]
730 pub fn slice(&self, range: &Range<usize>) -> Self {
731 assume(self.range.start + range.start <= usize::MAX);
733 assume(self.range.start + range.end <= usize::MAX);
734
735 assert!(range.start % PAGE_SIZE == 0 && range.end % PAGE_SIZE == 0);
736 let start = self.range.start + range.start;
737 let end = self.range.start + range.end;
738 assert!(start <= end && end <= self.range.end);
739
740 let mut paddr = start;
741 let ghost addr_len = (end - start) / PAGE_SIZE as int;
742 let ghost first_perm_idx: int = (range.start / PAGE_SIZE) as int;
743 let ghost last_perm_idx: int = (range.end / PAGE_SIZE) as int;
744 let ghost mut i: int = 0;
745 loop
746 invariant
747 self.page_in_range_saturated(range, *old(regions)) ==> may_panic(),
748 regions.inv(),
749 regions.slots == old(regions).slots,
750 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
751 regions.frame_obligations == old(regions).frame_obligations,
752 paddr == (start + i * PAGE_SIZE) as usize,
753 paddr <= end,
754 0 <= i <= addr_len,
755 paddr < end <==> i < addr_len,
756 first_perm_idx + i <= last_perm_idx,
757 forall|j: int|
758 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
759 first_perm_idx + i <= j < last_perm_idx ==> (
760 *regions).slot_owners[frame_to_index(
761 (self.range.start + j * PAGE_SIZE) as usize,
762 )] == old(regions).slot_owners[frame_to_index(
763 (self.range.start + j * PAGE_SIZE) as usize,
764 )],
765 forall|j: int|
766 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
767 first_perm_idx <= j < first_perm_idx + i ==> old(
768 regions,
769 ).slot_owners[frame_to_index(
770 (self.range.start + j * PAGE_SIZE) as usize,
771 )].inner_perms.ref_count.value() < REF_COUNT_MAX,
772 decreases addr_len - i,
773 {
774 if paddr >= end {
775 break;
776 }
777 let ghost perm_idx: int = first_perm_idx + i;
778
779 proof {
780 owner.relate_regions_at(*old(regions), perm_idx);
781 }
782
783 unsafe {
784 #[verus_spec(with Tracked(regions))]
785 crate::mm::frame::inc_frame_ref_count(paddr)
786 };
787
788 paddr = paddr + PAGE_SIZE;
789
790 proof {
791 i = i + 1;
792 assert forall|j: int|
793 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
794 first_perm_idx + i <= j < last_perm_idx implies (
795 *regions).slot_owners[frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
796 == old(regions).slot_owners[frame_to_index(
797 (self.range.start + j * PAGE_SIZE) as usize,
798 )] by {};
799 }
800 }
801
802 Self { range: start..end, _marker: core::marker::PhantomData }
803 }
804
805 #[verus_spec(r =>
821 with
822 Tracked(regions): Tracked<&mut MetaRegionOwners>,
823 Tracked(owner): Tracked<SegmentOwner<M>>,
824 -> frame_perms: Tracked<SegmentOwner<M>>,
825 requires
826 self.invariants(&owner, *old(regions)),
827 ensures
828 r == self.range(),
829 final(regions).inv(),
830 *final(regions) == *old(regions),
831 frame_perms@ == owner,
832 )]
833 pub(crate) fn into_raw(self) -> Range<Paddr> {
834 let range = self.range.clone();
835 let _ = ManuallyDrop::new(self, Tracked(regions));
836
837 proof_with!(|= Tracked(owner));
838 range
839 }
840
841 #[verifier::inline]
843 pub open spec fn nrpage_spec(&self) -> usize
844 recommends
845 self.inv(),
846 {
847 self.size() / PAGE_SIZE
848 }
849
850 pub closed spec fn split_spec(self, offset: usize) -> (Self, Self)
852 recommends
853 self.inv(),
854 offset % PAGE_SIZE == 0,
855 0 < offset < self.size(),
856 {
857 let at = (self.start_paddr() + offset) as usize;
858 let idx = at / PAGE_SIZE;
859 (
860 Self { range: self.start_paddr()..at, _marker: core::marker::PhantomData },
861 Self { range: at..self.end_paddr(), _marker: core::marker::PhantomData },
862 )
863 }
864}
865
866pub type SegmentIteratorItem<M> = (Frame<M>, Tracked<DropObligation<usize>>);
868
869#[verifier::reject_recursive_types(T)]
872pub tracked struct SegmentIteratorProphecySeq<T> {
873 tracked var: ProphecyGhost<Seq<T>>,
874 ghost done: bool,
875}
876
877impl<T> SegmentIteratorProphecySeq<T> {
878 #[verifier::prophetic]
879 closed spec fn seq(&self) -> Seq<T> {
880 if self.done {
881 Seq::empty()
882 } else {
883 self.var.value()
884 }
885 }
886
887 proof fn new() -> (tracked res: Self)
888 ensures
889 !res.done,
890 {
891 SegmentIteratorProphecySeq { var: ProphecyGhost::new(), done: false }
892 }
893
894 proof fn resolve_cons(tracked &mut self, value: T)
895 requires
896 !old(self).done,
897 ensures
898 !final(self).done,
899 old(self).seq() == seq![value] + final(self).seq(),
900 {
901 let tracked mut var = ProphecyGhost::new();
902 tracked_swap(&mut var, &mut self.var);
903 var.resolve_dependent(&self.var, |tail| seq![value] + tail);
904 }
905
906 proof fn resolve_nil(tracked &mut self)
907 ensures
908 old(self).seq() == Seq::<T>::empty(),
909 final(self).seq() == Seq::<T>::empty(),
910 final(self).done,
911 {
912 if !self.done {
913 let tracked mut var = ProphecyGhost::new();
914 tracked_swap(&mut var, &mut self.var);
915 var.resolve(seq![]);
916 self.done = true;
917 }
918 }
919}
920
921#[verifier::reject_recursive_types(M)]
926pub struct SegmentIterator<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> {
927 segment: &'a Segment<M>,
928 range: Range<Paddr>,
929 tracked_regions: Tracked<&'a mut MetaRegionOwners>,
930 tracked_owner: Tracked<&'a mut SegmentOwner<M>>,
931 tracked_remaining: Tracked<SegmentIteratorProphecySeq<SegmentIteratorItem<M>>>,
932}
933
934#[verus_verify]
935impl<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> SegmentIterator<'a, M> {
936 pub closed spec fn segment_ref(&self) -> &'a Segment<M> {
937 self.segment
938 }
939
940 pub closed spec fn range_spec(&self) -> Range<Paddr> {
941 self.range
942 }
943
944 pub closed spec fn current_segment(&self) -> Segment<M> {
945 Segment { range: self.range.start..self.range.end, _marker: core::marker::PhantomData }
946 }
947
948 #[verifier::prophetic]
949 pub closed spec fn remaining_spec(&self) -> Seq<SegmentIteratorItem<M>> {
950 self.tracked_remaining@.seq()
951 }
952
953 #[verifier::type_invariant]
954 pub closed spec fn type_inv(self) -> bool {
955 &&& self.segment.inv()
956 &&& self.segment.range.start <= self.range.start
957 &&& self.range.end == self.segment.range.end
958 &&& self.current_segment().invariants(self.tracked_owner@, *self.tracked_regions@)
959 &&& self.range.start < self.range.end ==> !self.tracked_remaining@.done
960 }
961
962 #[verus_spec(res =>
963 with
964 Tracked(regions): Tracked<&'a mut MetaRegionOwners>,
965 Tracked(owner): Tracked<&'a mut SegmentOwner<M>>,
966 requires
967 segment.invariants(owner, *regions),
968 ensures
969 res.segment_ref() == segment,
970 res.range_spec() == segment.range,
971 IteratorSpec::decrease(&res) is Some,
972 IteratorSpec::initial_value_relation(&res, &res),
973 )]
974 pub fn new(segment: &'a Segment<M>) -> Self {
975 Self {
976 segment,
977 range: segment.range.start..segment.range.end,
978 tracked_regions: Tracked(regions),
979 tracked_owner: Tracked(owner),
980 tracked_remaining: Tracked(SegmentIteratorProphecySeq::new()),
981 }
982 }
983
984 #[verus_spec(res =>
1013 with
1014 Tracked(regions_ref): Tracked<&mut &'a mut MetaRegionOwners>,
1015 Tracked(owner_ref): Tracked<&mut &'a mut SegmentOwner<M>>,
1016 Tracked(remaining): Tracked<&mut SegmentIteratorProphecySeq<SegmentIteratorItem<M>>>,
1017 requires
1018 segment.inv(),
1019 segment.range.start <= old(range).start,
1020 old(range).end == segment.range.end,
1021 (Segment {
1022 range: old(range).start..old(range).end,
1023 _marker: core::marker::PhantomData,
1024 }).invariants(*old(owner_ref), **old(regions_ref)),
1025 old(range).start < old(range).end ==> !old(remaining).done,
1026 ensures
1027 segment.inv(),
1028 segment.range.start <= final(range).start,
1029 final(range).end == segment.range.end,
1030 (Segment {
1031 range: final(range).start..final(range).end,
1032 _marker: core::marker::PhantomData,
1033 }).invariants(*final(owner_ref), **final(regions_ref)),
1034 final(range).start < final(range).end ==> !final(remaining).done,
1035 match res {
1036 None => {
1037 &&& final(range).start == old(range).start
1038 &&& final(range).end == old(range).end
1039 &&& old(remaining).seq() == Seq::<SegmentIteratorItem<M>>::empty()
1040 &&& final(remaining).seq() == Seq::<SegmentIteratorItem<M>>::empty()
1041 },
1042 Some(item) => {
1043 &&& final(range).start == old(range).start + PAGE_SIZE
1044 &&& final(range).end == old(range).end
1045 &&& item.0.paddr() == old(range).start
1046 &&& old(remaining).seq() == seq![item] + final(remaining).seq()
1047 },
1048 },
1049 no_unwind
1050 )]
1051 fn next_inner(segment: &'a Segment<M>, range: &mut Range<Paddr>) -> (res: Option<
1052 SegmentIteratorItem<M>,
1053 >) {
1054 if range.start < range.end {
1055 let ghost old_remaining = remaining.seq();
1056 let ghost old_range = range.start..range.end;
1057 let ghost old_owner = **owner_ref;
1058 let ghost old_regions = **regions_ref;
1059 let paddr = range.start;
1060
1061 proof {
1062 old_owner.relate_regions_at(old_regions, 0);
1063 assert(paddr == old_range.start);
1064 }
1065
1066 proof_decl! {
1067 let tracked from_raw_obl: DropObligation<usize>;
1068 }
1069 let frame = unsafe {
1070 #[verus_spec(with Tracked(*regions_ref) => Tracked(from_raw_obl))]
1071 Frame::<M>::from_raw(paddr)
1072 };
1073
1074 proof {
1075 let new_range = ((old_range.start + PAGE_SIZE) as usize)..old_range.end;
1076 let tracked redeem_tok = DropObligation::tracked_mint(frame.index());
1077 (*regions_ref).tracked_redeem_frame_obligation(redeem_tok);
1078 assert((**regions_ref).frame_obligations == old_regions.frame_obligations);
1079 (**owner_ref).range = new_range;
1080
1081 assert forall|i: int|
1082 #![trigger frame_to_index(((**owner_ref).range.start + i * PAGE_SIZE) as usize)]
1083 0 <= i < crate::specs::mm::frame::segment::seg_nframes(
1084 (**owner_ref).range,
1085 ) implies {
1086 let idx = frame_to_index(((**owner_ref).range.start + i * PAGE_SIZE) as usize);
1087 &&& (**regions_ref).frame_obligations.count(idx) >= 1
1088 &&& (**regions_ref).slot_owners.contains_key(idx)
1089 &&& (**regions_ref).slots.contains_key(idx)
1090 &&& (**regions_ref).slot_owners[idx].slot_vaddr == meta_addr(idx)
1091 &&& (**regions_ref).slot_owners[idx].inner_perms.ref_count.value() > 0
1092 &&& (**regions_ref).slot_owners[idx].inner_perms.ref_count.value()
1093 <= crate::mm::frame::meta::REF_COUNT_MAX
1094 &&& (**regions_ref).slot_owners[idx].paths_in_pt.is_empty()
1095 &&& (**regions_ref).slot_owners[idx].usage is Frame
1096 } by {
1097 old_owner.relate_regions_at(old_regions, i + 1);
1098 old_owner.relate_regions_distinct(old_regions, 0, i + 1);
1099 }
1100 assert forall|i: int, j: int|
1101 #![trigger frame_to_index(((**owner_ref).range.start + i * PAGE_SIZE) as usize),
1102 frame_to_index(((**owner_ref).range.start + j * PAGE_SIZE) as usize)]
1103 0 <= i < j < crate::specs::mm::frame::segment::seg_nframes(
1104 (**owner_ref).range,
1105 ) implies frame_to_index(((**owner_ref).range.start + i * PAGE_SIZE) as usize)
1106 != frame_to_index(((**owner_ref).range.start + j * PAGE_SIZE) as usize) by {
1107 old_owner.relate_regions_distinct(old_regions, i + 1, j + 1);
1108 }
1109 broadcast use group_page_meta;
1110
1111 assert((**regions_ref).slots[frame.index()].pptr() == frame.ptr);
1112 assert(frame.wf_with_region(**regions_ref));
1113 }
1114
1115 range.start = range.start + PAGE_SIZE;
1116 let item = (frame, Tracked(from_raw_obl));
1117 proof {
1118 remaining.resolve_cons(item);
1119 broadcast use vstd::seq::group_seq_axioms;
1120
1121 assert(remaining.seq() == old_remaining.drop_first());
1122 assert(item == old_remaining[0]);
1123 }
1124 Some(item)
1125 } else {
1126 let ghost old_remaining = remaining.seq();
1127 proof {
1128 remaining.resolve_nil();
1129 assert(remaining.seq() == old_remaining);
1130 }
1131 None
1132 }
1133 }
1134}
1135
1136impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> IteratorSpecImpl for SegmentIterator<
1137 '_,
1138 M,
1139> {
1140 open spec fn obeys_prophetic_iter_laws(&self) -> bool {
1141 true
1142 }
1143
1144 #[verifier::prophetic]
1145 closed spec fn remaining(&self) -> Seq<Self::Item> {
1146 self.remaining_spec()
1147 }
1148
1149 #[verifier::prophetic]
1150 closed spec fn will_return_none(&self) -> bool {
1151 true
1152 }
1153
1154 closed spec fn decrease(&self) -> Option<nat> {
1155 Some((self.range.end - self.range.start) as nat)
1156 }
1157
1158 #[verifier::prophetic]
1159 open spec fn initial_value_relation(&self, init: &Self) -> bool {
1160 &&& IteratorSpec::remaining(init) == IteratorSpec::remaining(self)
1161 &&& init.remaining_spec() == self.remaining_spec()
1162 &&& init.segment_ref() == self.segment_ref()
1163 &&& init.range_spec() == self.range_spec()
1164 }
1165
1166 open spec fn peek(&self, index: int) -> Option<Self::Item> {
1167 None
1168 }
1169}
1170
1171impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Iterator for SegmentIterator<'_, M> {
1172 type Item = SegmentIteratorItem<M>;
1173
1174 fn next(&mut self) -> Option<Self::Item> {
1176 proof {
1177 use_type_invariant(&*self);
1178 }
1179
1180 #[verus_spec(with
1181 Tracked(self.tracked_regions.borrow_mut()),
1182 Tracked(self.tracked_owner.borrow_mut()),
1183 Tracked(self.tracked_remaining.borrow_mut()),
1184 )]
1185 SegmentIterator::next_inner(self.segment, &mut self.range)
1186 }
1187}
1188
1189#[verus_verify]
1190impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> From<Frame<M>> for Segment<M> {
1191 #[verifier::external_body]
1200 fn from(frame: Frame<M>) -> Self {
1201 let pa = frame.start_paddr();
1202 let _ = core::mem::ManuallyDrop::new(frame);
1203 Self { range: pa..(pa + PAGE_SIZE), _marker: core::marker::PhantomData }
1204 }
1205}
1206
1207impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Iterator for Segment<M> {
1208 type Item = Frame<M>;
1209
1210 #[verifier::external_body]
1217 fn next(&mut self) -> Option<Self::Item> {
1218 if self.range.start < self.range.end {
1219 let frame = unsafe { Frame::<M>::from_raw(self.range.start) };
1222 self.range.start = self.range.start + PAGE_SIZE;
1223 Some(frame)
1224 } else {
1225 None
1226 }
1227 }
1228}
1229
1230impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Segment<M> {
1231 #[verus_spec(
1240 with Tracked(owner): Tracked<SegmentOwner<M>>,
1241 Tracked(regions): Tracked<&mut MetaRegionOwners>
1242 requires
1243 self.invariants(&owner, *old(regions)),
1244 forall|i: int|
1245 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1246 0 <= i < crate::specs::mm::frame::segment::seg_nframes(self.range) ==> {
1247 let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
1248 old(regions).slot_owners[idx].inner_perms.ref_count.value() == 1 ==> {
1249 &&& old(regions).slot_owners[idx].inner_perms.storage.is_init()
1250 &&& old(regions).slot_owners[idx].inner_perms.in_list.value() == 0
1251 }
1252 },
1253 ensures
1254 final(regions).inv(),
1255 )]
1256 pub fn drop(self) {
1257 let tracked owner = owner;
1258 let ghost old_owner = owner;
1259 let ghost n = crate::specs::mm::frame::segment::seg_nframes(self.range);
1260 let mut paddr = self.range.start;
1261
1262 let ghost mut k: int = 0;
1263
1264 let ghost old_owner = owner;
1265
1266 assert forall|i: int| #![trigger frame_idx_at(self.range.start, i)] 0 <= i < n implies {
1267 let idx = frame_idx_at(self.range.start, i);
1268 old(regions).slot_owners[idx].inner_perms.ref_count.value() == 1 ==> {
1269 &&& old(regions).slot_owners[idx].inner_perms.storage.is_init()
1270 &&& old(regions).slot_owners[idx].inner_perms.in_list.value() == 0
1271 }
1272 } by {};
1273
1274 proof {
1275 assert(old_owner.range == self.range);
1276 assert forall|i: int|
1277 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1278 0 <= i < n implies old(regions).frame_obligations.count(
1279 frame_to_index((self.range.start + i * PAGE_SIZE) as usize),
1280 ) >= 1 by {
1281 old_owner.relate_regions_at(*old(regions), i);
1282 };
1283 assert forall|i: int, j: int|
1284 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize),
1285 frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1286 0 <= i < j < n implies frame_to_index((self.range.start + i * PAGE_SIZE) as usize)
1287 != frame_to_index((self.range.start + j * PAGE_SIZE) as usize) by {
1288 old_owner.relate_regions_distinct(*old(regions), i, j);
1289 };
1290 crate::specs::mm::frame::segment::tracked_redeem_seg_obligations(
1291 regions,
1292 self.range.start,
1293 n,
1294 );
1295 }
1296
1297 loop
1298 invariant
1299 regions.inv(),
1300 self.inv(),
1301 self.range.start <= paddr <= self.range.end,
1302 paddr == (self.range.start + k * PAGE_SIZE) as usize,
1303 paddr % PAGE_SIZE == 0,
1304 paddr <= MAX_PADDR,
1305 0 <= k <= n,
1306 n == (self.range.end - self.range.start) / PAGE_SIZE as int,
1307 paddr < self.range.end <==> k < n,
1308 forall|j: int|
1309 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1310 k <= j < n ==> {
1311 let idx = frame_to_index((self.range.start + j * PAGE_SIZE) as usize);
1312 &&& regions.slot_owners.contains_key(idx)
1313 &&& regions.slots.contains_key(idx)
1314 &&& regions.slot_owners[idx] == old(regions).slot_owners[idx]
1315 },
1316 forall|j: int|
1317 #![trigger frame_idx_at(self.range.start, j)]
1318 k <= j < n ==> regions.slot_owners.contains_key(
1319 frame_idx_at(self.range.start, j),
1320 ) && regions.slot_owners[frame_idx_at(self.range.start, j)] == old(
1321 regions,
1322 ).slot_owners[frame_idx_at(self.range.start, j)],
1323 regions.slot_owners.dom() == old(regions).slot_owners.dom(),
1324 self.wf(&old_owner),
1325 old_owner.inv(),
1326 old(regions).inv(),
1327 old_owner.relate_regions(*old(regions)),
1328 old_owner.range == self.range,
1329 forall|i: int|
1330 #![trigger frame_to_index((self.range.start + i * PAGE_SIZE) as usize)]
1331 0 <= i < n ==> {
1332 let idx = frame_to_index((self.range.start + i * PAGE_SIZE) as usize);
1333 old(regions).slot_owners[idx].inner_perms.ref_count.value() == 1 ==> {
1334 &&& old(regions).slot_owners[idx].inner_perms.storage.is_init()
1335 &&& old(regions).slot_owners[idx].inner_perms.in_list.value() == 0
1336 }
1337 },
1338 decreases n - k,
1339 {
1340 if paddr >= self.range.end {
1341 break;
1342 }
1343 proof {
1344 old_owner.relate_regions_at(*old(regions), k);
1345 }
1346
1347 proof_decl! {
1348 let tracked from_raw_obl: vstd_extra::drop_tracking::DropObligation<usize>;
1349 }
1350
1351 let frame = unsafe {
1357 #[verus_spec(with Tracked(regions) => Tracked(from_raw_obl))]
1358 Frame::<M>::from_raw(paddr)
1359 };
1360
1361 frame.drop(Tracked(regions), Tracked(from_raw_obl));
1362
1363 proof {
1364 assert forall|j: int|
1365 #![trigger frame_to_index((self.range.start + j * PAGE_SIZE) as usize)]
1366 (k + 1) <= j < n implies {
1367 let idx = frame_to_index((self.range.start + j * PAGE_SIZE) as usize);
1368 &&& regions.slot_owners.contains_key(idx)
1369 &&& regions.slots.contains_key(idx)
1370 &&& regions.slot_owners[idx] == old(regions).slot_owners[idx]
1371 } by {
1372 old_owner.relate_regions_distinct(*old(regions), k, j);
1373 };
1374 }
1375
1376 paddr = paddr + PAGE_SIZE;
1377
1378 proof {
1379 k = k + 1;
1380 }
1381 }
1382 }
1383}
1384
1385impl<M: AnyFrameMeta + ?Sized> Inv for Segment<M> {
1492 open spec fn inv(self) -> bool {
1497 &&& self.start_paddr() % PAGE_SIZE == 0
1498 &&& self.end_paddr() % PAGE_SIZE == 0
1499 &&& self.start_paddr() <= self.end_paddr() <= MAX_PADDR
1500 }
1501}
1502
1503}